https://www.jianshu.com/p/5414ba2b5508
背景
最近需要做一个人脸检测并实时预览的功能。就是边检测人脸,边在预览界面上框出来。
当然本人并不是专门做Android的,另外也觉得网上的杂乱重复信息太多了,有的、没的、摘抄的、翻腾一遍又发一遍的都称得上是信息污染了,所以开始是不想写这个的,担心功力不够,给网络信息添乱,影响大家准确搜寻正确有用的信息。
主要是在网上搜罗了好久都没个具体方案,都是对于android-Camera2Basic这个Demo翻来倒去。人脸检测也只是输出一个坐标,缺失了很多实际应用中需要的东西,所以把做的东西分享出来供大家参考。
有不对或者偏颇的地方希望各位大牛指正。
前期探索
一直倾慕于OpenCV的强大,所以最开始是想用OpenCV(用的openCVLibrary340)做人脸检测,后面发现默认预览是横屏的,网上搜了一些方案,都不是太满意:
1.修改源码:改写CameraBridgeViewBase类的deliverAndDrawFrame方法,通过旋转画布等方法,自定义最终的绘制。尽管将逻辑可以下方到子类,但始终需要对源码做一定的修改,这种侵入源码的方式太不优雅,只能作最后的手段。
2.自定义图像:在CameraBridgeViewBase.CvCameraViewListener2监听中对图像进行处理。二次处理会在一定程度上影响速度。
当然还有其它的方式,但是基本都会有各自的缺陷,而之前有用过Android的人脸检测API FaceDetector,所以就想着用Android原生的方式。
首先肯定排除调用Android的人脸检测API做了,拍照后的后期检测裁剪之类的还行。预览实时检测的话资源耗费太大速度太慢。
然后Camera已经不推荐使用了,自然就选Camera2,好吧Camera2 API个人觉得挺不友好、不好用,但是既然Google让用,那就用吧。
界面
先看看效果图
做的过程中是预览画面与未处理过角度的拍照画面对比着进行分析矫正的,所以分析逻辑的时候可以先不对拍照画面进行处理。
界面结构与代码
最开始是想直接在预览画面上加上方框,后面发现费时费力还不讨好。好吧其实用的是TextureView,后面发现预览过程中获取不到Canvas不能绘制。当然不侵入预览画面,预览画面还可以做别用,不然就只能当预览画面了。
最终是在预览的TextureView上覆盖了一个同样大小的TextureView,在上面的TextureView上进行绘制。
界面结构:
界面代码:
`<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.face.detect.demo.MainActivity">
<TextureView
android:id="@+id/cView"
android:layout_width="180dp"
android:layout_height="240dp"
android:layout_marginStart="8dp" android:layout_marginTop="8dp" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <ImageView android:id="@+id/imageView" android:layout_width="150dp" android:layout_height="200dp" android:layout_marginBottom="8dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:background="?android:attr/colorEdgeEffect" android:scaleType="centerInside" android:src="@android:color/transparent" app:layout_constraintBottom_toBottomOf="@+id/cView" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/cView" app:layout_constraintTop_toTopOf="@+id/cView" /> <Button android:id="@+id/btnFront" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="前置" app:layout_constraintEnd_toStartOf="@+id/btnBack" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/cView" /> <Button android:id="@+id/btnBack" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="后置" app:layout_constraintEnd_toStartOf="@+id/btnClose" app:layout_constraintStart_toEndOf="@+id/btnFront" app:layout_constraintTop_toBottomOf="@+id/cView" /> <Button android:id="@+id/btnClose" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginEnd="8dp" android:layout_marginSta