本文的合集已经编著成书,高级Android开发强化实战,欢迎各位读友的建议和指导。在京东即可购买:https://item.jd.com/12385680.html

检测人脸, 在应用中有很多用处, 可以提供更好的交互, 和一些有针对性的意见. 检测脸部关键信息, 也可以更加方便的处理一些微表情的内容.

Google推出了官方的人脸检测功能, 很不幸依赖Google Service, 需要版本8.1以上. 国内手机基本不会默认配置. 下载地址, 此版本适配手机系统4.4+.

官方API

我讲解一下用法, 写了一个简单的显示控件, 注释详细.

关注:
(1) 如何提取人脸(Face)位置.
(2) 如何提取脸部关键点(Landmark)位置.
(3) 如何在画布(Canvas)居中绘制图片.

1. 配置项目

新建HelloWorld项目, 配置build.gradle.

    compile 'com.google.android.gms:play-services-vision:8.1.0' // 包含人脸识别类compile 'com.jakewharton:butterknife:7.0.1'

一般都会从最基础的HelloWorld开始, 方便学习和理解. ButterKnife必用.

2. 检测人脸控件

控件居中显示一张图片, 在图片上, 绘制人脸位置和关键点(Landmarks).
关键点包括: 眼睛, 鼻子, 嘴等属性. 存在遮挡, 根据不同人脸提取量不同.
通过FaceDetector检测Bitmap, 获取图片的所有脸部(face)信息.
根据位置(Position)画出脸的形状, 根据关键点(Landmarks)画出脸部特征.
同时可以获取各种特征的概率(Probability), 和脸部偏移.

/*** 检测人脸的控件* <p/>* Created by wangchenlong on 15/12/15.*/
public class FacesDisplayView extends View {private static final String TAG = "DEBUG-WCL: " + FacesDisplayView.class.getSimpleName();private Bitmap mBitmap; // 图片private SparseArray<Face> mFaces; // 人脸数组// 确保图片居中private int mHorizonOffset; // 水平偏移private int mVerticalOffset; // 竖直偏移public FacesDisplayView(Context context) {this(context, null);}public FacesDisplayView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FacesDisplayView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);}// 设置显示图片@SuppressWarnings("unused")public void setBitmap(Bitmap bitmap) {mBitmap = bitmap;FaceDetector detector = new FaceDetector.Builder(getContext()).setTrackingEnabled(true).setLandmarkType(FaceDetector.ALL_LANDMARKS).setMode(FaceDetector.ACCURATE_MODE).build();if (!detector.isOperational()) {Log.e(TAG, "加载失败");return;} else {Frame frame = new Frame.Builder().setBitmap(bitmap).build();mFaces = detector.detect(frame);detector.release();}logFaceData(); // 打印人脸数据invalidate();  // 填充}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if ((mBitmap != null) && (mFaces != null)) {double scale = drawBitmap(canvas);drawFaceBox(canvas, scale);drawFaceLandmarks(canvas, scale);}}// 绘制图片, 返回缩放概率private double drawBitmap(Canvas canvas) {double viewWidth = canvas.getWidth(); // 显示宽度double viewHeight = canvas.getHeight(); // 显示高度double imageWidth = mBitmap.getWidth(); // 图片宽度double imageHeight = mBitmap.getHeight(); // 图片高度double wScale = viewWidth / imageWidth;double hScale = viewHeight / imageHeight;double scale;Rect destBounds;// 水平竖直缩放if (wScale > hScale) {mHorizonOffset = (int) ((viewWidth - imageWidth * hScale) / 2.0f);destBounds = new Rect(mHorizonOffset, 0,(int) (imageWidth * hScale) + mHorizonOffset, (int) (imageHeight * hScale));scale = hScale;} else {mVerticalOffset = (int) ((viewHeight - imageHeight * wScale) / 2.0f);destBounds = new Rect(0, mVerticalOffset,(int) (imageWidth * wScale), (int) (imageHeight * wScale) + mVerticalOffset);scale = wScale;}canvas.drawBitmap(mBitmap, null, destBounds, null); // 添加图片return scale;}// 绘制脸部方形private void drawFaceBox(Canvas canvas, double scale) {// 画笔Paint paint = new Paint();paint.setColor(Color.GREEN);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);float left;float top;float right;float bottom;// 绘制每张脸for (int i = 0; i < mFaces.size(); i++) {Face face = mFaces.valueAt(i);left = (float) (face.getPosition().x * scale);top = (float) (face.getPosition().y * scale);right = (float) scale * (face.getPosition().x + face.getWidth());bottom = (float) scale * (face.getPosition().y + face.getHeight());canvas.drawRect(left + mHorizonOffset, top + mVerticalOffset,right + mHorizonOffset, bottom + mVerticalOffset, paint);}}// 绘制脸部关键部位private void drawFaceLandmarks(Canvas canvas, double scale) {Paint paint = new Paint();paint.setColor(Color.YELLOW);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(5);for (int i = 0; i < mFaces.size(); i++) {Face face = mFaces.valueAt(i);for (Landmark landmark : face.getLandmarks()) {int cx = (int) (landmark.getPosition().x * scale);int cy = (int) (landmark.getPosition().y * scale);canvas.drawCircle(cx + mHorizonOffset, cy + mVerticalOffset, 10, paint);}}}// 输出脸部数据private void logFaceData() {float smilingProbability;float leftEyeOpenProbability;float rightEyeOpenProbability;float eulerY;float eulerZ;for (int i = 0; i < mFaces.size(); i++) {Face face = mFaces.valueAt(i);// 可能性smilingProbability = face.getIsSmilingProbability();leftEyeOpenProbability = face.getIsLeftEyeOpenProbability();rightEyeOpenProbability = face.getIsRightEyeOpenProbability();eulerY = face.getEulerY(); // 竖直轴偏移eulerZ = face.getEulerZ(); // 前后偏移Log.e(TAG, "脸数: " + i);Log.e(TAG, "微笑概率: " + smilingProbability);Log.e(TAG, "左眼睁开概率: " + leftEyeOpenProbability);Log.e(TAG, "右眼睁开概率: " + rightEyeOpenProbability);Log.e(TAG, "竖直轴偏移: " + eulerY);Log.e(TAG, "前后偏移: " + eulerZ);Log.e(TAG, "--------------------");}}
}

图像和特征是显示在画布上, 根据画布大小, 等比例缩放, 并居中显示.

3. 主页面

主界面通过一个简单的ViewPager连续显示图片.

    @Bind(R.id.main_vp_container) ViewPager mVpContainer; // 连续@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);ButterKnife.bind(this);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);mVpContainer.setAdapter(new FacesViewPagerAdapter(getSupportFragmentManager()));}

适配传递参数, 根据参数, 返回不同的图片页面.

/*** 脸部适配器* <p/>* Created by wangchenlong on 15/12/15.*/
public class FacesViewPagerAdapter extends FragmentPagerAdapter {private static final int NUM = 9;public FacesViewPagerAdapter(FragmentManager fm) {super(fm);}@Override public Fragment getItem(int position) {return ShowFaceFragment.newInstance(position);}@Override public int getCount() {return NUM;}
}

每页是个Fragment, 根据参数, 使用不同资源.

/*** 显示人脸的界面* <p/>* Created by wangchenlong on 15/12/15.*/
public class ShowFaceFragment extends Fragment {private static final String ARG_SELECTION_NUM = "arg_selection_num";@Bind(R.id.main_fdv_face_detector) FacesDisplayView mFdvFaceDetector;@RawRes ArrayList<Integer> mPhotos; // 图片集合public ShowFaceFragment() {mPhotos = new ArrayList<>();mPhotos.add(R.raw.total_large_poster);mPhotos.add(R.raw.jessicajung_large_poster);mPhotos.add(R.raw.seohyun_large_poster);mPhotos.add(R.raw.sooyoung_large_poster);mPhotos.add(R.raw.sunny_large_poster);mPhotos.add(R.raw.taeyeon_large_poster);mPhotos.add(R.raw.tiffany_large_poster);mPhotos.add(R.raw.yoona_large_poster);mPhotos.add(R.raw.yuri_large_poster);}public static ShowFaceFragment newInstance(int selectionNum) {ShowFaceFragment simpleFragment = new ShowFaceFragment();Bundle args = new Bundle();args.putInt(ARG_SELECTION_NUM, selectionNum);simpleFragment.setArguments(args);return simpleFragment;}@Nullable @Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_show_face, container, false);ButterKnife.bind(this, view);return view;}@Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);@RawRes int image = mPhotos.get(getArguments().getInt(ARG_SELECTION_NUM));InputStream stream = getResources().openRawResource(image);Bitmap bitmap = BitmapFactory.decodeStream(stream);mFdvFaceDetector.setBitmap(bitmap);}@Override public void onDestroyView() {super.onDestroyView();ButterKnife.unbind(this);}
}

注意使用注释(Annotation), 判断资源类型, 如@RawRes.

Github下载地址

有时间再完善一下这个小控件吧.

OK, Enjoy It.

人脸及脸部关键点检测控件相关推荐

  1. CVPR 2017:Interspeices Knowledge Transfer for Facial KeyPoint Detection(跨物种脸部关键点检测知识迁移)

    CVPR 2017: Interspeices Knowledge Transfer for Facial KeyPoint Detection(跨物种脸部关键点检测知识迁移) 一.介绍 本文主要涉及 ...

  2. 人脸定点:关键点检测方法汇总

    相关博客:  http://blog.csdn.net/yang_xian521/article/details/7468571  http://blog.sina.com.cn/s/blog_6d8 ...

  3. Demo : 人脸5个关键点检测

    Demo : 人脸5个关键点检测 资料 代码:gitee 数据集:百度云盘 密码:jc6w 算法构建 人脸关键点检测,需要使用回归算法,因此一开始的想法就是前面使用多层卷积,适当添加残差网络作为基础模 ...

  4. HyperLandmark-开源人脸106点关键点检测SDK,北京智云视图科技

    原 HyperLandmark-开源人脸106点关键点检测SDK 2018年07月19日 15:25:44 lsy17096535 阅读数:3260 </div><div class ...

  5. dilb人脸识别+68关键点检测

    **简单的人脸识别 记个笔记 ** # 导入库 import cv2.cv2 as cv2 import numpy as np import dlib import matplotlib.pyplo ...

  6. 人脸对齐及关键点检测

    严格定义上的人脸识别分为四个步骤: ①人脸检测:从图片中准确定位到人脸 ②人脸对齐: 自动定位出面部关键特征点, ③进行特征提取 ④对两张人脸图像的特征向量进行对比,计算相似度. 当今的人脸识别系统如 ...

  7. 设置断点检测控件何时创建和析构

    Created by Jerry Wang, last modified on Aug 20, 2015 mElements deregister Element 切换到debug mode, 从如下 ...

  8. python+OpenCv+dlib实现人脸68个关键点检测

    pip install dlib==19.7.0 下载地址: http://dlib.net/files/ dlib中为我们提供了关于人脸检测标注训练好的文件可在http://dlib.net/fil ...

  9. 人脸数据库大全(包括人脸识别、关键点检测、表情识别,人脸姿态等等)

    搞计算机视觉的人,对人脸技术并不陌生.在做实验的时候需要各种数据集进行训练,却往往苦于找不到合适的数据集,这篇文章将给大家带来一点福音. 目前为止最全的是人脸数据库总结: The Color FERE ...

  10. 机器视觉 脸部关键点检测(脸部识别)安卓应用App(Face Mesh)基于mediapipe。

    目录 前言 一.下载APP! 二.安装后使用结果: 三.总结 前言 安卓系统手机实现对手部关键点的识别. 一.下载APP! csdn下载:Face Mesh 百度网盘下载:链接:https://pan ...

最新文章

  1. 为什么重新new两个线程线程号相同_C++ 20中的新线程(jthread)功能
  2. 通配符(WildCard)的使用
  3. 开发最前沿:项目案例实战之桥模式
  4. H3C 交换机S6520X软件版本升级
  5. Android混淆详解
  6. boost::gil::detail::convolve_2d用法的测试程序
  7. [react] react中除了在构造函数中绑定this,还有别的方式吗?
  8. 万用表怎么测电池内阻_数字万用表和指针万用表,两者怎么选?
  9. [转]C#网络编程(同步传输字符串) - Part.2
  10. C语言 int** 二重指针的理解
  11. windows下socket编程GetLastError()函数返回结果与对照表-转
  12. 利用PDF.JS插件解决了本地pdf文件在线浏览问题(根据需要隐藏下载功能,只保留打印功能)
  13. foreign key 和on delete/update cascade用法
  14. Linux驱动——编译驱动的两种形式(内核目录外、内核目录中)
  15. Oracle 日志解析ogg,对一段OracleGoldenGate(OGG)传输进程日志(.rpt文件)的解
  16. TM4C129建立FREERTOS工程
  17. 某连锁酒店集团实行积分奖励计划,会员每次入住集团旗下酒店均可以获得一定积分,积分由欢迎积分加消费积分构成。其中欢迎积分跟酒店等级有关,具体标准如表2-1所示;消费积分跟每次入住消费金额有关,具体标准为
  18. FPGA课设实验二:计数器设计与仿真
  19. itextpdf对PDF文件进行签名
  20. 最大信息熵增益_信息熵(Entropy)、信息增益(Information Gain)

热门文章

  1. Iconfont-阿里巴巴矢量图标库
  2. Android实现文字和图片混排(文字环绕图片)效果
  3. 基于java五子棋游戏设计与实现
  4. 多功能jQuery日期控件基于jeDate
  5. Adober Pro DC 破
  6. android xml 注释快捷键,xml注释(xml注释掉一段代码)
  7. 安卓网页离线保存_Android webView 缓存 Cache + HTML5离线功能 解决
  8. cramer定理_克莱姆(cramer)法则及定理简介.ppt
  9. Python爬虫实例1
  10. Android长图文截图的实现(支持截取微博,知乎,头条等第三方app)