功能解释:1.人脸检测:摄像头下有人检测出来即可。
功能解释:2.人脸识别:得识别出当前的人是否和人脸库里面的人一致。
我这里实现的是第一个功能。
默认你的工程已接入了OpenCv所需要的相关库,如果没接入的话可以看我写的一篇:Android OpenCv导入工程
第一步:添加相机权限: 如果手机是6.0以上的要动态申请权限,否则不能正常使用相机功能。6.0以上动态权限申请
第二步:创建布局文件,使用opencv提供的 JavaCameraView
第三步:activity 添加属性: android:screenOrientation="landscape"使activity强制横屏显示。添加这个可以解决相机图像显示旋转问题。
第四步直接上代码:
package demo.android.caifengopencv;
import android.content.Context;
import android.hardware.Camera;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.OpenCVLoader;
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.imgproc.Imgproc;
import org.opencv.objdetect.CascadeClassifier;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
public class FaceDetectionActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener2 {
private static final String TAG = “caifeng”;
private CameraBridgeViewBase mOpenCvCameraView;
// -1/0:后置双摄 1:前置
private static final int FRONT = 1;//前置摄像头
private static final int POSTPOSITION = 0;//后置摄像头
//当前显示的摄像头是前置还是后置
private int mCurrentCameraDirection = POSTPOSITION;
private CascadeClassifier mFrontalFaceClassifier = null; //正脸 级联分类器
private CascadeClassifier mProfileFaceClassifier = null; //侧脸 级联分类器
private Rect[] mFrontalFacesArray;
private Rect[] mProfileFacesArray;
private int mFronFacesSize;//正脸总数
private int mProFacesSize; //侧脸总数
private Mat mRgba;
private Mat mGray;
//设置检测区域
private Size m55Size = new Size(55, 55);
private Size m65Size = new Size(65, 65);
private Size mDefault = new Size();
private long mOldTime;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detection);
initOpenCvCameraView();
}
/**
* 初始化相机
*/
private void initOpenCvCameraView() {
mOpenCvCameraView = findViewById(R.id.java_cameraView);
int numCameras = Camera.getNumberOfCameras();
//如果有两个摄像头。这里使用前置摄像头
if (numCameras > 1) {
mCurrentCameraDirection = POSTPOSITION;
mOpenCvCameraView.setCameraIndex(mCurrentCameraDirection); //摄像头索引 -1/0:后置双摄 1:前置
}
mOpenCvCameraView.enableFpsMeter(); //显示FPS
mOpenCvCameraView.setCvCameraViewListener(this);//监听
mOpenCvCameraView.setMaxFrameSize(640, 480);//设置帧大小
}
/**
* @Description 初始化正脸分类器
*/
private void initFrontalFace() {
try {
//这个模型是我觉得来说相对不错的
InputStream is = getResources().openRawResource(R.raw.haarcascade_frontalface_alt); //OpenCV的人脸模型文件: lbpcascade_frontalface_improved
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File mCascadeFile = new File(cascadeDir, "haarcascade_frontalface_alt.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();
// 加载 正脸分类器
mFrontalFaceClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
/**
* @Description 初始化侧脸分类器
*/
private void initProfileFace() {
try {
//这个模型是我觉得来说相对不错的
InputStream is = getResources().openRawResource(R.raw.haarcascade_profileface); //OpenCV的人脸模型文件: lbpcascade_frontalface_improved
File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
File mCascadeFile = new File(cascadeDir, "haarcascade_profileface.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();
// 加载 侧脸分类器
mProfileFaceClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
} catch (Exception e) {
Log.e(TAG, e.toString());
}
}
/**
* 相机启动
*
* @param width - the width of the frames that will be delivered
* @param height - the height of the frames that will be delivered
*/
@Override
public void onCameraViewStarted(int width, int height) {
mGray = new Mat();
mRgba = new Mat();
}
/**
* 相机停止
*/
@Override
public void onCameraViewStopped() {
mGray.release();
mRgba.release();
}
/**
* 相机捕抓的帧在这里处理
*
* @param inputFrame
* @return
*/
@Override
public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
mRgba = inputFrame.rgba(); //RGBA
mGray = inputFrame.gray(); //单通道灰度图
//检测并显示
MatOfRect frontalFaces = new MatOfRect();
MatOfRect profileFaces = new MatOfRect();
if (mFrontalFaceClassifier != null) {//这里2个 Size 是用于检测人脸的,越小,检测距离越远,1.1, 5, 2, m65Size, mDefault着四个参数可以提高检测的准确率,5表示确认五次,具体百度 detectMultiScale 这个方法
mFrontalFaceClassifier.detectMultiScale(mGray, frontalFaces, 1.1, 5, 2, m65Size, mDefault);
mFrontalFacesArray = frontalFaces.toArray();
mFronFacesSize = mFrontalFacesArray.length;
//如果正脸数大于0就绘制框框
if (mFronFacesSize > 0) {
Log.i(TAG, "正脸人数为 : " + mFrontalFacesArray.length);
for (int i = 0; i < mFrontalFacesArray.length; i++) { //用框标记
Imgproc.rectangle(mRgba, mFrontalFacesArray[i].tl(), mFrontalFacesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
Log.d("caifeng", "绘制正脸框框");
}
}
}
if (mProfileFaceClassifier != null) {//这里2个 Size 是用于检测人脸的,越小,检测距离越远
mProfileFaceClassifier.detectMultiScale(mGray, profileFaces, 1.1, 6, 0, m55Size, mDefault);
mProfileFacesArray = profileFaces.toArray();
mProFacesSize = mProfileFacesArray.length;
//如果侧脸数大于0就绘制框框
if (mProFacesSize > 0) {
Log.i(TAG, "侧脸人数为 : " + mProfileFacesArray.length);
for (int i = 0; i < mProfileFacesArray.length; i++) { //用框标记
Imgproc.rectangle(mRgba, mProfileFacesArray[i].tl(), mProfileFacesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
}
}
}
return mRgba;
}
@Override
protected void onResume() {
super.onResume();
//初始化opencv
if (!OpenCVLoader.initDebug()) {
Log.e(TAG, "OpenCV init error");
} else {
Log.e(TAG, "OpenCV init success");
if (mFrontalFaceClassifier == null || mProfileFaceClassifier == null) {
initFrontalFace();
initProfileFace();
}
mOpenCvCameraView.enableView();
}
}
@Override
public void onPause() {
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
@Override
protected void onDestroy() {
super.onDestroy();
mOpenCvCameraView.disableView();
}
}
下载地址:Demo下载地址