Android+openCV 动态人脸检测

动态人脸检测前提是需要打开摄像头。

网上看了很多教程,我知道的有两种方式打开摄像头:

JavaCameraView mCameraView = new JavaCameraView(this, -1);
setContentView(mCameraView);
mCameraView.setCvCameraViewListener(this);

mCameraView.enableView();

第2种:在布局文件中添加 CameraBridgeViewBase

mCameraView = (CameraBridgeViewBase) findViewById(R.id.java_surface_view);
mCameraView.setCvCameraViewListener(this);
mCameraView.enableView();

以上两种获取摄像头实时视频流方式需要 implements  CameraBridgeViewBase.CvCameraViewListener

public class FaceTrackingActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener {
  @Overrid
  protected void onCreate(Bundle savedInstanceState) { ... } @Override public void onCameraViewStarted(int width, int height) { } @Override public void onCameraViewStopped() { } @Override public Mat onCameraFrame(Mat inputFrame) { return null; } }
onCameraFrame 函数中将捕获视频每一帧。
这样我在预览视频的时候,发现很难控制大小,以及摄像头的方向。
后来我直接采用以往的camera类去操作视频流。
以上参考:http://blog.csdn.net/tobacco5648/article/details/51615632

实时处理摄像头预览帧视频参考:http://blog.csdn.net/yanzi1225627/article/details/8605061

定义 SurfaceView

    <SurfaceView
        android:id="@+id/java_surface_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
        mSurfaceView = (SurfaceView) findViewById(R.id.java_surface_view);
        mSurfaceHolder = mSurfaceView.getHolder();

        // mSurfaceView 不需要自己的缓冲区
        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
        // mSurfaceView添加回调
        mSurfaceHolder.addCallback(new SurfaceHolder.Callback() {
            @Override
            public void surfaceCreated(SurfaceHolder holder) { //SurfaceView创建
                try {
                    cameraManager = new CameraManager(FaceTrackingActivity.this, mObjectDetects, cimbt, mSurfaceHolder);
                    cameraManager.openDriver();
                    cameraManager.startPreview();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

            }

            @Override
            public void surfaceDestroyed(SurfaceHolder holder) { //SurfaceView销毁
                holder.removeCallback(this); // Camera is being used after Camera.release() was called
                cameraManager.stopPreview();
                cameraManager.closeDriver();

            }
        });

我这里独立出来了一个 CameraManager 类,本来我想把检测的代码写在 CameraManager 类之外,然而并没有实现:

 CameraManager 类中  implements Camera.PreviewCallback 可以实现 onPreviewFrame 对实时数据处理:

    @Override
    public void onPreviewFrame(byte[] bytes, Camera camera) {
        Camera.Size previewSize = camera.getParameters().getPreviewSize();

        Bitmap bitmap = ByteToBitmap(bytes, previewSize);
        //Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);//将data byte型数组转换成bitmap文件

        final Matrix matrix = new Matrix();//转换成矩阵旋转90度
        if (cameraPosition == 1) {
            matrix.setRotate(90);
        } else {
            matrix.setRotate(-90);
        }
        bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);//旋转图片


        Mat grayscaleImage = new Mat(previewSize.height, previewSize.width, CvType.CV_8UC4);
        int absoluteFaceSize = (int) (previewSize.height * 0.2);

        if (bitmap != null) {
            Mat inputFrame = new Mat();
            Utils.bitmapToMat(bitmap, inputFrame);

            if (!bitmap.isRecycled()) {
                bitmap.recycle();
            }

            // Create a grayscale image
            Imgproc.cvtColor(inputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);

            MatOfRect mRect = new MatOfRect();


            int maxRectArea = 0 * 0;
            Rect maxRect = null;

            int facenum = 0;

            for (ObjectDetector detector : mObjectDetects) {
                // 检测目标
                Rect[] object = detector.detectObjectImage(inputFrame, mRect);
                Log.e(TAG, object.length + "");

                for (Rect rect : object) {
                    ++facenum;
                    // 找出最大的面积
                    int tmp = rect.width * rect.height;
                    if (tmp >= maxRectArea) {
                        maxRectArea = tmp;
                        maxRect = rect;
                    }
                }
            }

            Bitmap rectBitmap = null;
            if (facenum != 0) {
                // 剪切最大的头像
                //Log.e("剪切的长宽", String.format("高:%s,宽:%s", maxRect.width, maxRect.height));
                Rect rect = new Rect(maxRect.x, maxRect.y, maxRect.width, maxRect.height);
                Mat rectMat = new Mat(inputFrame, rect);  // 从原始图像拿
                rectBitmap = Bitmap.createBitmap(rectMat.cols(), rectMat.rows(), Bitmap.Config.ARGB_8888);
                Utils.matToBitmap(rectMat, rectBitmap);

                Bitmap resizeBmp = cimbt.resizeBitmap(rectBitmap, cimbt.getWidth(), cimbt.getHeight());
                cimbt.setBitmap(resizeBmp);
            } else {
                cimbt.clearnImage();
                cimbt.setText("没有检测到人脸");
            }
        }

    }

补充:在初始化相机时激活onPreviewFrame

camera.setPreviewCallback(this);
//camera.setOneShotPreviewCallback(this); // 激活 onPreviewFrame 执行一次

整个人脸静态动态检测源代码: https://github.com/haoxr/faceDetection

动态检测截图:

Android+openCV 动态人脸检测