【Android App】人脸识别中借助摄像头和OpenCV实时检测人脸讲解及实战(附源码和演示 超详细)
创始人
2024-03-14 18:31:29
0

需要全部代码请点赞关注收藏后评论区留言私信~~~

一、借助摄像头实时检测人脸

与Android自带的人脸检测器相比,OpenCV具备更强劲的人脸识别功能,它可以通过摄像头实时检测人脸,实时检测的预览空间是JavaCameraView 常用方法说明如下

setCvCameraViewListener:设置OpenCV的相机视图监听器。监听器需要写下列三个状态变更方法:

onCameraViewStarted:相机视图开始预览时回调。

onCameraViewStopped:相机视图停止预览时回调。

onCameraFrame:相机视图预览变更时回调。

enableView:启用OpenCV的相机视图。

 disableView:禁用OpenCV的相机视图。

接下来把JavaCameraView加入App工程,走一遍它的详细使用过程,首先修改AndroidManifest.xml补充一行相机权限配置

实时检测人脸有如下四个步骤

(1)从布局文件中获得相机视图对象后,调用它的setCvCameraViewListener方法,设置OpenCV的相机视图监听器。

(2)OpenCV初始化与资源加载完成后,调用enableView方法开启相机视图。

(3)活动类由继承AppCompatActivity改为继承CameraActivity类,并重写getCameraViewList方法,返回相机视图的单例列表。

(4)第一步重写监听器接口的onCameraFrame方法时,补充人脸识别等处理逻辑,也就是先检测人脸,再给人脸标上相框。

二、效果展示

运行测试App 会自动打开手机摄像机 然后检测摄像机内的人脸

由顶部状态栏可以看到打开了相机功能 此处用了博主小时候的照片~~~

三、代码 

部分代码如下 需要全部源码请点赞关注收藏后评论区留言~~~

package com.example.face;import android.content.Context;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.widget.TextView;import com.example.face.util.DateUtil;import org.opencv.android.CameraActivity;import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.Collections;
import java.util.List;//OpenCV的实时扫描页面必须继承CameraActivity
public class DetectRealtimeActivity extends CameraActivity implements CameraBridgeViewBase.CvCameraViewListener2 {private static final String TAG = "DetectRealtimeActivity";private static final Scalar FACE_RECT_COLOR = new Scalar(0, 255, 0, 255);private Mat mRgba, mGray; // 全彩矩阵,灰度矩阵private CascadeClassifier mJavaDetector; // OpenCV的人脸检测器private int mAbsoluteFaceSize = 0; // 绝对人脸大小// OpenCV默认横屏扫描,需要旋转90度改成竖屏预览,详细改动见CameraBridgeViewBase.java的deliverAndDrawFrame方法private CameraBridgeViewBase jcv_detect; // 声明一个OpenCV的相机视图对象@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_detect_realtime);findViewById(R.id.iv_back).setOnClickListener(v -> finish());TextView tv_title = findViewById(R.id.tv_title);tv_title.setText("实时检测人脸");jcv_detect = findViewById(R.id.jcv_detect);jcv_detect.setVisibility(CameraBridgeViewBase.VISIBLE);jcv_detect.setCvCameraViewListener(this); // 设置OpenCV的相机视图监听器}@Overridepublic void onPause() {super.onPause();if (jcv_detect != null) {jcv_detect.disableView(); // 禁用OpenCV的相机视图}}@Overridepublic 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_0_0, this, mLoaderCallback);} else {Log.d(TAG, "OpenCV library found inside package. Using it!");mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);}}@Overrideprotected List getCameraViewList() {return Collections.singletonList(jcv_detect);}@Overridepublic void onDestroy() {super.onDestroy();jcv_detect.disableView(); // 禁用OpenCV的相机视图}@Overridepublic void onCameraViewStarted(int width, int height) {mGray = new Mat();mRgba = new Mat();}@Overridepublic void onCameraViewStopped() {mGray.release();mRgba.release();}// 相机预览回调@Overridepublic Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {mRgba = inputFrame.rgba();mGray = inputFrame.gray();Core.rotate(mRgba, mRgba, Core.ROTATE_90_CLOCKWISE); // 适配竖屏,顺时针旋转90度Core.rotate(mGray, mGray, Core.ROTATE_90_CLOCKWISE); // 适配竖屏,顺时针旋转90度if (mAbsoluteFaceSize == 0) {Log.d(TAG, "width="+mGray.width()+", height="+mGray.height()+", cols="+mGray.cols()+", rows="+mGray.rows());int height = mGray.rows();if (Math.round(height * 0.2f) > 0) {mAbsoluteFaceSize = Math.round(height * 0.2f);}
//            String filePath = String.format("%s/%s.jpg",
//                    getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).toString(),
//                    DateUtil.getNowDateTime());
//            Imgcodecs.imwrite(filePath, mRgba);
//            Log.d(TAG, "filePath="+filePath);}MatOfRect faces = new MatOfRect();if (mJavaDetector != null) { // 检测器开始识别人脸mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2,new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());}Rect[] faceArray = faces.toArray();for (Rect rect : faceArray) { // 给找到的人脸标上相框Imgproc.rectangle(mRgba, rect.tl(), rect.br(), FACE_RECT_COLOR, 3);Log.d(TAG, rect.toString());}Core.rotate(mRgba, mRgba, Core.ROTATE_90_COUNTERCLOCKWISE); // 恢复原状,逆时针旋转90度return mRgba;}private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {@Overridepublic void onManagerConnected(int status) {if (status == LoaderCallbackInterface.SUCCESS) {Log.d(TAG, "OpenCV loaded successfully");// 在OpenCV初始化完成后加载so库System.loadLibrary("detection_based_tracker");File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);File cascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");// 从应用程序资源加载级联文件try (InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);FileOutputStream os = new FileOutputStream(cascadeFile)) {byte[] buffer = new byte[4096];int bytesRead;while ((bytesRead = is.read(buffer)) != -1) {os.write(buffer, 0, bytesRead);}} catch (Exception e) {e.printStackTrace();}// 根据级联文件创建OpenCV的人脸检测器mJavaDetector = new CascadeClassifier(cascadeFile.getAbsolutePath());if (mJavaDetector.empty()) {Log.d(TAG, "Failed to load cascade classifier");mJavaDetector = null;} else {Log.d(TAG, "Loaded cascade classifier from " + cascadeFile.getAbsolutePath());}cascadeDir.delete();jcv_detect.enableView(); // 启用OpenCV的相机视图} else {super.onManagerConnected(status);}}};}

创作不易  觉得有帮助请点赞关注收藏~~~

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...