Android OpenCv实现人脸检测

功能解释: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下载地址

你可能感兴趣的:(笔记,学习日志)