Android人脸识别app——基于Face++,MVP+Retofit+RxJava+Dagger高度解耦
热文导读| 点击标题阅读
金九银十跳槽季如何进阶找到合适满意的工作?
给你惊喜!来看看国内大公司官网隐藏的彩蛋
那些一毕业就选择华为的人,后来都怎么样了
作者:reggie1996 (文末附github地址)
地址:https://www.jianshu.com/p/920b9c525d2f
前言
最近公司项目比较空,花了点时间写了个人脸识别的app,可以查看你的性别、年龄、颜值、情绪等信息,利用的是 Face++ 的人脸识别API。本项目采用了 MVP 的架构,使用了 Retrofit、RxJava、Dagger、EventBus 等框架进行开发和解耦,利用 MaterialDesign 进行UI上的布局设计。
主要的功能就是拍照,然后将照片传至 Face++ 服务器,进行人脸识别,获取返回的信息,对信息进行处理。将人脸在照片上标出,并将信息展示出来。
话不多说,先来看一下 app 的效果(吴彦祖还是帅啊,哈哈)。
面部识别主界面 面部识别详情界面 多人脸识别
项目我已经放在 github 上,clone 下来即可编译运行。github 地址: reggie1996 - FaceDetect 。下面文章主要介绍的是本项目的开发过程和碰到的坑。
过程
项目的整个流程很简单无非就是三步,拍照片,传照片获取数据,然后对数据进行处理展示。
拍照获取照片
拍照需要获取系统权限,我封装了一个方法,来判断App是否有拍照相关的权限,如果没有就去动态请求权限,并返回 false,如果有就返回 true。
public static boolean checkAndRequestPermission(Context context, int requestCode) { if (context.checkSelfPermission( Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED || context.checkSelfPermission(Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ((Activity) context).requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.CAMERA}, requestCode); return false; }else { return true; } }
获取到拍照权限后就可以拍照了,但是拍照得到的照片我们需要通过 FileProvider 获取。FileProvider 相关的内容就不作介绍了,Android 7.0 之后都得用这个。
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.chaochaowu.facedetect.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
拍照之后从文件中读取照片,我们可以得到一个 BitMap 对象。这里就有一个很大的坑,如果手机是三星的话,照片从文件里读出来,最后得到的照片会被旋转 90°!!!,这个贼坑啊,调了我好久,以为是自己手机的故障,后来网上查了一下,也请教了一下前辈,原来三星的手机都有这个问题,所以说我们要对文件中取出来的照片进行一下处理。
/** * 读取图片的旋转的角度 * * @param path 图片绝对路径 * @return 图片的旋转角度 */ public static int getBitmapDegree(String path) { int degree = 0; try { // 从指定路径下读取图片,并获取其EXIF信息 ExifInterface exifInterface = new ExifInterface(path); // 获取图片的旋转信息 int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL); switch (orientation) { case ExifInterface.ORIENTATION_ROTATE_90: degree = 90; break; case ExifInterface.ORIENTATION_ROTATE_180: degree = 180; break; case ExifInterface.ORIENTATION_ROTATE_270: degree = 270; break; default: degree = 0; break; } } catch (IOException e) { e.printStackTrace(); } return degree; }
/** * 将图片按照某个角度进行旋转 * * @param bm 需要旋转的图片 * @param degree 旋转角度 * @return 旋转后的图片 */ public static Bitmap rotateBitmapByDegree(Bitmap bm, int degree) { Bitmap returnBm = null;
// 根据旋转角度,生成旋转矩阵 Matrix matrix = new Matrix(); matrix.postRotate(degree); try { // 将原始图片按照旋转矩阵进行旋转,并得到新的图片 returnBm = Bitmap.createBitmap(bm, 0, 0, bm.getWidth(), bm.getHeight(), matrix, true); } catch (OutOfMemoryError | Exception e) { e.printStackTrace(); } if (returnBm == null) { returnBm = bm; } if (bm != returnBm) { bm.recycle(); } return returnBm; }
封装了两个方法,依次调用可以解决三星手机照片的问题。两个方法主要的工作就是,得到取出来的照片被旋转的角度,然后再将角度旋转回去,就可以得到原来的照片。因为并不是所有的手机在获取照片时,照片都会被旋转,所以得先判断一下照片有没有被旋转,再决定是否需要将它旋转调整。
行,这样最后就获得到了正确的 BitMap 照片,可以进行下一步了。
传照片获取数据
传照片获取数据,主要是运用了 Retrofit 和 RxJava 的封装。请求的参数可以参考 Face++ 的官方文档。
/** * retrofit 面部识别请求的网络服务 * @author chaochaowu */public interface FaceppService {
/** * @param apikey * @param apiSecret * @param imageBase64 * @param returnLandmark * @param returnAttributes * @return */ @POST("facepp/v3/detect") @FormUrlEncoded Observable<FaceppBean> getFaceInfo(@Field("api_key") String apikey, @Field("api_secret") String apiSecret, @Field("image_base64") String imageBase64, @Field("return_landmark") int returnLandmark, @Field("return_attributes") String returnAttributes);
}
照片需要进行 base64 转码后上传至服务器,封装了一个照片base64转码方法。
public static String base64(Bitmap bitmap){ ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos); byte[] bytes = baos.toByteArray(); return Base64.encodeToString(bytes, Base64.DEFAULT); }
处理完成之后就可以进行网络请求获取数据。
@Override public void getDetectResultFromServer(final Bitmap photo) { String s = Utils.base64(photo); faceppService.getFaceInfo(BuildConfig.API_KEY, BuildConfig.API_SECRET, s, 1, "gender,age,smiling,emotion,beauty") .subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<FaceppBean>() { @Override public void onSubscribe(Disposable d) { mView.showProgress(); }
@Override public void onNext(FaceppBean faceppBean) { handleDetectResult(photo,faceppBean); }
@Override public void onError(Throwable e) { mView.hideProgress(); }
@Override public void onComplete() { mView.hideProgress(); } }); }
Face++ 服务器会对我们上传的照片进行处理,分析照片中的人脸信息,并以 json 形式返回,返回的数据将被放入我们定义的bean类中。
/** * 面部识别结果的bean * @author chaochaowu */public class FaceppBean { /** * image_id : Dd2xUw9S/7yjr0oDHHSL/Q== * request_id : 1470472868,dacf2ff1-ea45-4842-9c07-6e8418cea78b * time_used : 752 * faces : [{"landmark":{"mouth_upper_lip_left_contour2":{"y":185,"x":146},"contour_chin":{"y":231,"x":137},"right_eye_pupil":{"y":146,"x":205},"mouth_upper_lip_bottom":{"y":195,"x":159}},"attributes":{"gender":{"value":"Female"},"age":{"value":21},"glass":{"value":"None"},"headpose":{"yaw_angle":-26.625063,"pitch_angle":12.921974,"roll_angle":22.814377},"smile":{"threshold":30.1,"value":2.566890001296997}},"face_rectangle":{"width":140,"top":89,"left":104,"height":141},"face_token":"ed319e807e039ae669a4d1af0922a0c8"}] */
private String image_id; private String request_id; private int time_used; private List<FacesBean> faces; ...显示部分内容
bean 类中有人脸识别得到的 性别、年龄、颜值、情绪等信息,还有每张人脸在照片中的坐标位置。接下来的工作就是对这些数据进行处理。
获取信息后的数据处理
数据的处理主要就两件事,一个是将数据以文字的形式展现,这个很简单,就不介绍了,还有一个就是将人脸在照片中标示出来,这个需要对 BitMap 进行处理,利用数据中人脸在照片中的坐标位置,我们用方框将人脸标识出来。
private Bitmap markFacesInThePhoto(Bitmap bitmap, List<FaceppBean.FacesBean> faces) { Bitmap tempBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true); Canvas canvas = new Canvas(tempBitmap); Paint paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.STROKE); paint.setStrokeWidth(10);
for (FaceppBean.FacesBean face : faces) { FaceppBean.FacesBean.FaceRectangleBean faceRectangle = face.getFace_rectangle(); int top = faceRectangle.getTop(); int left = faceRectangle.getLeft(); int height = faceRectangle.getHeight(); int width = faceRectangle.getWidth(); canvas.drawRect(left, top, left + width, top + height, paint); } return tempBitmap; }
封装了一个方法,运用 Canvas 在照片上进行绘制,因为照片中的人脸可能不止一个,所以用for循环遍历。获取人脸在照片中的坐标,利用人脸左上角的坐标以及人脸的宽高,在照片中绘制一个方框将人脸标出。
剩余信息我这边采用 RecyclerView 来展示。左右滑动可以查看每张人脸的信息。RecyclerView 的 item 上展示的是简要信息,可以点击 item 进入详情页面查看面部识别的详细信息。RecyclerView 以及详情界面的实现就不作介绍了,很基本的操作。我这边也就只使用了 SharedElement 让界面切换看起来舒服一点。具体的实现可以看 github 上的代码。
其他就没什么操作了,还可以看一下我的项目架构。由于用了各种框架进行解耦,所以代码文件数量变多了,但是单个文件中的代码会变少一点,清晰易读一点,这也是解耦的目的,也方便之后的维护。
具体实现的细节可以看 github 上面的代码~
最后
写完这个APP后,我一直在思考一个问题,APP给吴彦祖的颜值打分80多,那100分的颜值会是怎样?
感兴趣的朋友可以把代码下载下来玩一下,测一下自己或者是朋友的颜值,嘿嘿。
github地址: https://github.com/reggie1996/FaceDetect
想进阿里吗快加入我们的知识星球吧,如下?
如有收获,欢迎「分享 」
「点赞」「评论 」
妈妈常教导我,让我养成良好习惯。这样长大才能成为一个有用的人。良好的习惯是尊敬师长这样长大才能成为一个有用的人。良好的习惯是尊敬师长,爱护同学,对人有礼貌;是不粗心,做事情不拖拉;还是爱护公物,不浪费粮食。为什么呢?因为拥有良好习惯,做一个品德高尚的人,懂得尊重别人,才会得到别人的尊重。我要努力地做到这些。我有一些坏习惯,有时候学习很粗心,把一些会做的题做错。在生活上,也很粗心,有一次早上起床居然穿反了衣服。我吃饭很慢,有的时候还剩饭。我还起床磨蹭,本来应该迅速地穿好衣服,但是,我总是磨磨蹭蹭地,速度很慢。“我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!” 在上幼儿园以前,我什么也不会干,就连穿衣服也是妈妈给我穿好,就要上幼儿园了,这样可不行,妈妈锻炼我要学会自己穿衣服。 有一天,妈妈把衣服摆在我面前,开始让我自己穿。一开始。我又哭又叫就是不穿,还把衣服扔的满地都是,然后坐在地上开始大哭,等了好长时间,妈妈还是不理我,我只好自己乖乖的把衣服穿好, 一出了房间门,妈妈就笑了起来,再看看我的衣服,毛衣和裤子都穿反了,我赶紧回房间又重新穿了一遍,这次穿好了,拿起外套,可是外套的扣子又扣不上了,扣子可调皮了,好像故意和我作对,我把扣子往扣眼——人类邪恶的根源;爱情——幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话:幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话幸福和光明的源泉。我一直在这些思想的舞台上徘徊。突然我发现两个身影从我面前经过,坐在不远的草地上。这是一对从农田那边走过来的青年男女。农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话“亲爱的!擦干你的眼泪,至高无上的爱情已经打开了我们的眼界,使我们成了它的崇拜者。是它,
妈妈常教导我,让我养成良好习惯。这样长大才能成为一个有用的人。良好的习惯是尊敬师长这样长大才能成为一个有用的人。良好的习惯是尊敬师长,爱护同学,对人有礼貌;是不粗心,做事情不拖拉;还是爱护公物,不浪费粮食。为什么呢?因为拥有良好习惯,做一个品德高尚的人,懂得尊重别人,才会得到别人的尊重。我要努力地做到这些。我有一些坏习惯,有时候学习很粗心,把一些会做的题做错。在生活上,也很粗心,有一次早上起床居然穿反了衣服。我吃饭很慢,有的时候还剩饭。我还起床磨蹭,本来应该迅速地穿好衣服,但是,我总是磨磨蹭蹭地,速度很慢。“我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!我打算在这学期里,改掉这些坏习惯。早上起来,迅速地穿好衣服,不拖拉。学习不粗心,仔细完成每一道题。吃饭的时候,要很快的把饭吃完,不剩饭。我要从一点一滴做起,逐渐养成良好习惯。我相信自己一定能成为一名品学兼优的好学生!” 在上幼儿园以前,我什么也不会干,就连穿衣服也是妈妈给我穿好,就要上幼儿园了,这样可不行,妈妈锻炼我要学会自己穿衣服。 有一天,妈妈把衣服摆在我面前,开始让我自己穿。一开始。我又哭又叫就是不穿,还把衣服扔的满地都是,然后坐在地上开始大哭,等了好长时间,妈妈还是不理我,我只好自己乖乖的把衣服穿好, 一出了房间门,妈妈就笑了起来,再看看我的衣服,毛衣和裤子都穿反了,我赶紧回房间又重新穿了一遍,这次穿好了,拿起外套,可是外套的扣子又扣不上了,扣子可调皮了,好像故意和我作对,我把扣子往扣眼——人类邪恶的根源;爱情- 。幸福和光明的源泉我一直在这些思想的舞台上徘徊突然我发现两个身影从我面前经过,坐在不远的草地上这是一对从农田那边走过来的青年男女农田那边有农民的茅舍。在一阵令人伤心的沉默之后,随着一声长叹,我听见从一个肺痨病人的嘴里说出了这样的话: “ 亲爱的!擦干你的眼泪,至高无上的爱情已经打开了我们的眼界,使我们成了它的崇拜者。是它,
如你有好的文章想大家状语从句:欢迎分享投稿,直接向我投递文章链接即可
最后,国庆福利来了,我们的知识星球已达到1000人了,之前说过到达1000人时将大大幅涨价到169元,为了反馈大家对我们的关注和厚爱,特此维持现价99元最后一天,今天后(今晚00:00)后将涨到169元,欢迎大家加入我们的知识星球,更多星球信息参见:
如何进阶成为Java的Android版和架构师?
金九银十跳槽季如何进阶找到合适满意的工作?
说两件事
微信扫描或者点击上方二维码领取的Android \ Python的\ AI \的Java等高级进阶资源
更多学习资料点击下面的“阅读原文 ”获取
Android人脸识别app——基于Face++,MVP+Retofit+RxJava+Dagger高度解耦相关推荐
- android app trifit_Android人脸识别app——基于Face++,MVP+Retofit+RxJava+Dagger高度解耦
前言 最近公司项目比较空,花了点时间写了个人脸识别的app,可以查看你的性别.年龄.颜值.情绪等信息,利用的是 Face++ 的人脸识别API.本项目采用了 MVP 的架构,使用了 Retrofit. ...
- Android人脸识别App(带web上传注册信息)
2019独角兽企业重金招聘Python工程师标准>>> 人脸识别+本机Web后端 人脸sdk采用虹软sdk,本机web采用AndServer:上传姓名+人脸图片即可实现注册源码地址: ...
- 基于android系统的人脸检测系统设计 论文,基于Android人脸识别系统设计与实现.doc...
基于Android人脸识别系统设计与实现 基于Android人脸识别系统设计与实现 摘要:人脸识别是公共安全领域的研究重点.随着移动互联网的快速发展,移动式终端人脸识别应用日益广泛.探讨人脸识别在An ...
- 神目 Android 人脸识别SDK编译说明
1.介绍 该文章介绍了神目 AI开放平台Android SDK 基于Android Studio的编译方法 2.Android SDK下载 登录神目AI开放平台下载Android人脸识别SDK打包文件 ...
- Android 人脸识别
Android人脸识别技术,可以参考下面的网站. http://www.faceplusplus.com.cn/ 本项目使用的就是该网站的api. 项目具体使用的技术代码 /*** 用来压缩图片的方法 ...
- Python人脸识别教程 - 基于Python的开源人脸识别库:离线识别率高达99.38%
Python人脸识别教程 - 基于Python的开源人脸识别库:离线识别率高达99.38% 仅用 Python 和命令行就可以实现人脸识别的库开源了.该库使用 dlib 顶尖的深度学习人脸识别技术构建 ...
- 【人脸识别】基于dlib库实现人脸特征值提取
一.Dlib库介绍与安装 1. Dlib库简介 Dlib库是一个机器学习的开源库,包含了机器学习的很多算法,使用起来很方便,直接包含头文件即可,并且不依赖于其他库(自带图像编解码库源码).Dlib可以 ...
- android人脸识别门禁,安卓人脸识别门禁终端DM-A1
1.产品介绍: 安卓(Android)人脸识别门禁终端DM-A1是定位为一款功能丰富,扩展性强,稳定性高,简单维护的人脸识别一体机.它集深数科技人脸比对算法及人脸识别活体检测算法,实现5000人脸库下 ...
- 人脸识别App面临的安全风险
中国信通院:2020年人脸识别技术在App应用中的隐私安全研究报告 节选 人脸识别App面临的安全风险 人脸识别技术应用在提升身份认证便捷度和效率的同时,也给个人隐私和数据保护带来了巨大的挑战.通过评 ...
最新文章
- 深度学习核心技术精讲100篇(三十八)-滴滴司机调度系统实践
- visual studio 2019 (vs) 显示右侧缩略图
- Ubuntu12.04 LTS 忘记登录密码的解决方法
- java各层级限流对比,面试官说:来谈谈限流-从概念到实现,一问你就懵逼了?...
- 服务器低功耗cpu性能,节能省电家庭共享 7款低功耗处理器推荐
- python爬虫视频课程推荐_Python 爬虫实战案例(推荐小白研究)
- 【转】千万级并发实现的秘密:内核不是解决方案,而是问题所在!
- 关于html5中a链接的download属性
- Latex:利用BibTeX批量导入参考文献
- java将汉字字符串转换为拼音(包含多音字)
- Unity插件——Odin 学习笔记(一)
- 分享39个大数据可视化工具(数据分析必备)
- 计算机专业职称入深户,深圳市人才引进入深户新政策
- MySQL查询不同年份母亲节_日期习俗大不同 走近七个国家的母亲节
- 第六十一期:中国农民花3000块,发明史上最牛输入法!曾火遍中国20年
- 获取url地址栏后面的参数
- java 串口 中文乱码_Java 实现 POS 打印机无驱串口打印(解决中文乱码)
- 5G NR OFDM链路层仿真及Matlab代码实现(1):LDPC信道编译码之5G Tollbox中相关函数使用介绍
- javascript网页自动填表_javascript 自动填写表单
- C/C++实例goto语句实现“关机代码”
热门文章
- 华为mate40pro和华为mate40pro+的区别
- 翼支付门户架构之redis之RDB和AOF
- 关于KNIME HUB
- Java平台UC浏览器6.7发布啦
- iOS 视频播放 - AVPlayer
- 解决python编码格式错误问题
- python 好玩的小乌龟
- java 缩放图片 锯齿_Java Image Filters 图像缩放质量差的问题解决
- 树莓派交叉编译opencv3.4.1/pycharm安装opencv/实现人脸识别Demo记录
- python元组有啥用_python元组是什么?python元组的用法介绍