基于opencv实现人脸检测

opencv简述

opencv是一个开源的计算机视觉库,它有着C++,Python,Java等接口,支持Windows,Linux,Mac OS,IOS 和 Android平台.Opencv 是使用C/C++所写的,可以利用多核处理.通过OpenCL启用,它可以利用底层异构计算平台的硬件加速。关于Opencv的详细介绍可以去其官网查看.Opencv 官网

注意

1.如果对opencv还没有接触过的,可以先参考参考这篇文章,了解如何在Android项目接入opencv.android 接入opencv的3种方式 .建议结合Opencv 的Tutorials看,效果更加.
2.这边接入使用的opencv library是利用github上面opencv和opencv-contrib库里的源码来编译的适用于Android平台的库.这个库的地址在opencv+opencv-contrib-lib4Android 编的这个库是3.4.2版本,Android的各个平台都有.还是很全的.
如果想自己编译的话,可以参考我之前的文章编译opencv+opencv-contrib 遇到的坑 .
当然你也可以直接从opencv的官网下载人家已经编译好的库.但是从其官网下载的库内容不全,比如Tracker这一块的内容,就没有.(PS:后面会更一篇利用OpenCV实现物体追踪功能的文章。就是需要tracker)这是在opencv-contrib库里的.
那什么是opencv-contrib库?opencv-contrib库是一个额外库,里面包含的是一些较新,高级些的功能模块.

目标

利用Opencv的分类器CascadeClassifier,对从Camera读取的yuv数据进行实时检测,并且把结果显示在屏幕上.

CascadeClassifier介绍

CascadeClassifier不仅仅可以检测人脸,也可以检测眼睛,身体,嘴巴等.通过加载一个想要检测的.xml的分类器文件就可以.

开撸

要实现在相机预览画面的实时人脸检测,那么关于Android Camera的部分肯定要先弄起来.这边为了方便演示,简单封装了一个CameraModule库.来实现相机预览,Camera 数据回调.

         CameraApi.getInstance().setCameraId(CameraApi.CAMERA_INDEX_BACK);CameraApi.getInstance().initCamera(this, this);CameraApi.getInstance().setPreviewSize(new Size(previewWidth, previewHeight));CameraApi.getInstance().setFps(30).configCamera();CameraApi.getInstance().startPreview(holder);

在成功获取Camera 的preview数据之后,我们开始处理opencv部分的逻辑.
1.首先我们需要创建CascadeClassifier.
在Activity的onResume回调中,先加载Opencv的library.

@Overrideprotected void onResume() {super.onResume();if (!OpenCVLoader.initDebug()) {Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_4_0, this, mLoaderCallback);} else {Log.d(TAG, "OpenCV library found inside package. Using it!");mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);}}

在加载成功的回调中,创建需要的属于opencv的对象.代码如下:

private LoaderCallbackInterface mLoaderCallback = new LoaderCallbackInterface() {@Overridepublic void onManagerConnected(int status) {if (status == LoaderCallbackInterface.SUCCESS) {init();isLoadSuccess = true;try {// load cascade file from application resourcesInputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");FileOutputStream os = new FileOutputStream(mCascadeFile);byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {os.write(buffer, 0, bytesRead);}is.close();os.close();mFaceCascade = new CascadeClassifier(mCascadeFile.getAbsolutePath());if (mFaceCascade.empty()) {Log.e(TAG, "Failed to load cascade classifier");mFaceCascade = null;} else {Log.e(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());}cascadeDir.delete();} catch (IOException e) {e.printStackTrace();Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);}}}@Overridepublic void onPackageInstall(int operation, InstallCallbackInterface callback) {}};
private void init() {mSrcMat = new Mat(previewHeight, previewWidth, CvType.CV_8UC1);mDesMat = new Mat(previewHeight, previewWidth, CvType.CV_8UC1);matOfRect = new MatOfRect();initQueue();}

我们分析一下上面的代码,首先我们创建了一些必须的对象,比如Mat对象.
Mat - The Basic Image Container 在opencv里,对图像的处理,大都是先把图像数据转化成Mat对象,Mat对象就像是一个容器,对图像的处理就是对Mat的处理.
然后,我们从raw文件夹里读取了opencv训练好的,用于检测人脸的分类器文件lbpcascade_frontalface.xml.xml分类器文件,可以从opencv下载的包里面找到.你会发现,里面有两种类型的分类器文件,一种是haar的,一种是lbp的.关于这两种的不同.可以参考haar-vs-lbp .
这里我们选择的是lbp的.分类器文件获取到后,我们通过分类器文件,创建了我们想要的CascadeClassifier.

2.对相机预览数据的处理
这边设置的预览的FPS是30,因为人脸检测是耗时操作,为了不影响预览的画面流畅度.这边采用了,子线程+队列的处理方式.通过创建两个队列,来保证对相机数据的管理.

@Overridepublic void onPreviewFrameCallback(byte[] data, Camera camera) {mCamera.addCallbackBuffer(data);if (isStart) {CameraRawData rawData = mFreeQueue.poll();if (rawData != null) {rawData.setRawData(data);rawData.setTimestamp(System.currentTimeMillis());mFrameQueue.offer(rawData);}}}

3.从队列获取数据,进行检测

/*** face detect thread*/private class DetectThread extends Thread {DetectThread(String name) {super(name);}@Overridepublic void run() {super.run();while (isStart && isLoadSuccess) {synchronized (mLock) {try {mCameraRawData = mFrameQueue.poll(20, TimeUnit.MILLISECONDS);} catch (InterruptedException e) {e.printStackTrace();}if (mCameraRawData == null) {continue;}frameDatas = mCameraRawData.getRawData();mSrcMat.put(0, 0, frameDatas);Imgproc.cvtColor(mSrcMat, mDesMat, Imgproc.COLOR_YUV2GRAY_420);mFaceCascade.detectMultiScale(mDesMat, matOfRect, 1.1, 5, 2, mMinSize, mMaxSize);if (matOfRect.toArray().length != 0) {Rect rect = getBiggestFace(matOfRect.toArray());mResultView.showFace(rect);} else {mResultView.clear();}mFreeQueue.offer(mCameraRawData);mCamera.addCallbackBuffer(frameDatas);}}}}

如上面的代码所示,我们通过创建子线程,在里面进行face detect处理.
首先我们从队列中获取Camera data.接着为mSrcMat对象赋值.接着利用Opencv 的convert方法,对源数据进行灰度化处理.

 Imgproc.cvtColor(mSrcMat, mDesMat, Imgproc.COLOR_YUV2GRAY_420);

这里主要看下第三个参数.因为我这边设置的image format 是NV21 ,所用了这个YUV420 to Gray的flag.我们进去可以看到:

我们发现,只要是YUV420的无论是P还是SP都是用的同一个Flag.还挺省事,省的格式转化了O(∩_∩)O.

我们接着看这行代码:

mFaceCascade.detectMultiScale(mDesMat, matOfRect, 1.1, 5, 2, mMinSize, mMaxSize);

这就是检测的核心代码,这里说一下各个参数所代表的含义.
Parameters
image Matrix of the type CV_8U containing an image where objects are detected.
objects Vector of rectangles where each rectangle contains the detected object, the rectangles may be partially outside the original image.
scaleFactor Parameter specifying how much the image size is reduced at each image scale.
minNeighbors Parameter specifying how many neighbors each candidate rectangle should have to retain it.
flags Parameter with the same meaning for an old cascade as in the function cvHaarDetectObjects. It is not used for a new cascade.
minSize Minimum possible object size. Objects smaller than that are ignored.
maxSize Maximum possible object size. Objects larger than that are ignored. If maxSize == minSize model is evaluated on single scale.

参数的含义,来自官网,懒得翻译。

这里主要说下minNeighbors,minSize,maxSize.这三个参数.
通过这三个参数可以控制检测的精确度.
minNeighbors 值越大,检测的准确度越高,不过耗时也越久.酌情调整.
minSize 可以根据Screen 尺寸的一定比例来设置,别设置太小,不然会有一些错误干扰结果.
maxSize 最大可检测尺寸,酌情调整.

接着往下看,检测结果出来后,是一个rect集合,检测到的每一张脸是一个矩形…O__O "…
这边做的处理选择了一张脸最大的来显示.

现在我们把代码跑起来,看一下效果:

通过效果gif演示,我们可以很明显的看到,成功的检测到了人脸。这里要说个缺点,就是使用OpenCV的CascadeClassifier进行人脸检测,检测的结果是返回一个MatOfRect对象,可理解为rectangle集合,意思是只记录着检测到脸的位置。并没有其他的信息了,并不能记住识别人脸。注意***人脸识别***和***人脸检测***的区别。关于OpenCV的人脸识别(FaceRecognizer)需要对目标先进行数据训练,训练好才能对目标成功识别。关于OpenCV人脸识别的内容,这边先不说了,之后的文章再讨论。

结语

关于使用OpenCV来进行人脸检测,就说到这,后期想到什么要补充的会再补充。人脸检测的实现,也写了一篇利用Firebase Vision ML Kit库来实现的文章,建议大家去看看,做做对比,根据需要选择合适的技术手段来实现。利用Google vision来实现人脸检测
演示demo地址如下。
OpencvFaceDetect


加入我的个人技术公众号,一起学习Android知识!


扫码体验小程序:微捷径

基于opencv实现人脸检测相关推荐

  1. 【零基础跑项目】20代码教你基于opencv的人脸检测

    20代码教你基于opencv的人脸检测

  2. 基于opencv的人脸检测与识别(python)(1)

    基于opencv的人脸检测与识别(python语言)(1) 人脸检测和识别技术就目前而言,已经相对成熟,各类算法层出不穷,这都归功于各位奋斗在一线的大佬的努力(站在巨人的肩膀上的感觉就是爽).本文是参 ...

  3. 基于opencv的人脸检测(图片、视频、摄像头)

    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 目录 前言 一.检测图片中的人脸 二.检测视频与摄像头中的人脸 总结 前言 人脸检测识别一直是个热门的研究问题,同时也是opencv中 ...

  4. 【机器学习】最容易实现的基于OpenCV的人脸检测代码、检测器及检测效果

    基于opencv自带的人脸检测模型,实现简单的人脸检测功能,可作为机器学习初学者练手使用.简单易学,具体的方法及代码如下. 1.运行结果 输入原图 输出结果 2.工程需要加载的opencv库如下: 3 ...

  5. 基于opencv的人脸检测

    这里写目录标题 一.基本信息 1.导言 2.应用 3.环境搭建 二.逻辑以及关键代码 1.逻辑分析 关键代码 三.结果分析 四.总结 一.基本信息 1.导言 输入:图片,视频,可以使用本地,网络,监控 ...

  6. python基于opencv的人脸检测(有最详细的注释)摄像头实时检测人脸

    主要实现功能: 通过opencv的模块的内置的方法打开电脑摄像头,读取每一帧数据进行分析.通过界面的方式在界面里实时更新摄像头视频并且标记出人脸. 效果图: 代码: 这部分代码可以用来检测opencv ...

  7. Python基于OpenCV的人脸检测

    检测代码 import cv2 import sysimagePath = "timg.jpg" #包含人脸的图像文件 cascPath = "haarcascade_f ...

  8. opencv实现人脸检测、性别和年龄预测

    opencv实现人脸检测.性别和年龄预测 文章目录: 一.下载预训练的模型 1.下载模型 2.模型说明 二.实现步骤 1.加载模型 2.人脸检测 3.性别与年龄预测 4.完整代码 主要是通过openc ...

  9. 基于 OpenCV 的人脸识别

    一点背景知识 OpenCV 是一个开源的计算机视觉和机器学习库.它包含成千上万优化过的算法,为各种计算机视觉应用提供了一个通用工具包.根据这个项目的关于页面,OpenCV 已被广泛运用在各种项目上,从 ...

最新文章

  1. 验证视图MAC失败 Validation of ViewState MAC Failed
  2. 微信公众号签名错误 invalid signature
  3. 身体器官工作表一览,别熬夜
  4. 系统设计:负载均衡(负载均衡算法、转发实现、session)
  5. 90TB显存!英伟达发布新一代SuperPod超算,AI算力新巅峰!
  6. 毕啸南专栏 | 对话智联招聘CEO郭盛:未来的社会是透明的
  7. Android studio 怎么使用已经下载好的Android SDK ?
  8. 13. PHP 数组
  9. 数据结构 树的遍历(递归遍历练习)
  10. ZooKeeper 安装与部署
  11. 语音排队叫号系统源码
  12. python人脸识别代码实现
  13. 酷炫的可视化数据地图都是咋做的?10分钟学会
  14. 【清橙A1339】JZPLCM(顾昱洲) (树状数组)
  15. 截止失真放大电路_BJT的失真
  16. android抽屉式listview,Android实现列表抽屉展示效果
  17. b-spline学习-系数计算及程序实践
  18. 路由器自动重启指令_如何按计划自动重启路由器,简便方法
  19. Hadoop 推测执行
  20. 程序员与颈椎病(一) 我得了什么病

热门文章

  1. jbpm3\jbpm4_在jBPM中支持高级用户交互模式
  2. c++ value categories
  3. HTML常用标签、文本格式化标签:加粗、倾斜、删除线、下划线等
  4. Openstack 虚拟机云盘扩容
  5. 更换APP启动图标和名称
  6. Docker-入门基础知识(1)
  7. ARM Linux异常处理之data abort(一)
  8. java xmpp协议_GitHub - zhengzhi530/xmpp: 基于Xmpp协议的即时通讯社交软件(客户端+服务端)...
  9. 使用pycharm配置出现Conda executable path is empty问题
  10. 服务器发布Java jar包