美文网首页
安卓OpenCV开发(二)人脸检测

安卓OpenCV开发(二)人脸检测

作者: motosheep | 来源:发表于2021-06-13 10:29 被阅读0次

    重点是人脸检测,检测,检测。

    就是把人脸检测出来,不是识别,不是识别,不是识别。识别的意思,就是检测到人脸,并且通过数据比对,算法分析后得出人脸相识度的过程。而检测,仅仅是检测出来。

    针对全网关于安卓OpenCV识别XXX之类的标题,而实际只做了检测的相关文章,在此表示呵呵

    回到正题

    如何预览视频并进行人脸检测?

    (一)预览视频

    可直接使用OpenCV库中的JavaCameraView控件,进行视频的预览。

    1、布局中声明该对象:

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <org.opencv.android.JavaCameraView
            android:id="@+id/activity_main_camera_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
    </RelativeLayout>
    

    2、在布局中,直接调用该对象的enableView()方法,即可预览。

    备注:权限申请之类的老生常谈,这里不再啰嗦。

    (二)构建检测分类器

    OpenCV中,CascadeClassifier是用于分类器进行数据处理的。首先,构建一个分类器,需要数据源,而人脸检测的分类器数据源,OpenCV官方已经有一个可以直接用了,这里可以直接拿过来用。而文件的路径,就在下载的资源文件中的OpenCV-android-sdk\sdk\etc\lbpcascades目录下,关于构建项目的流程,不懂可看我上一篇文章
    OpenCV导入

    把分类器数据复制到主项目的res-raw目录下,没有该目录就新建,复制后如下图:


    raw文件目录

    然后,在应用检测前,进行分类器数据复制到本地,并初始化分类器,代码如下:

    try {
                InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
                File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                File 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();
                cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
            } catch (Exception e) {
                Log.e("OpenCVActivity", "Error loading cascade", e);
            }
    

    这样就完成了分类器的构建了。

    (三)监听视频数据

    对JavaCameraView设置CameraBridgeViewBase.CvCameraViewListener即可对视频数据进行监听

    (四)人脸检测,基于第三部,在监听回调方法onCameraFragment()中,对回调的视频数据进行监听,实现代码如下:

       @Override
        public Mat onCameraFrame(Mat aInputFrame) {
            Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
            MatOfRect faces = new MatOfRect();
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
                        new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }
            Rect[] facesArray = faces.toArray();
            for (int i = 0; i <facesArray.length; i++){
                Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
            }
            return aInputFrame;
        }
    

    首先,这里对传入的图片帧,进行了一个色值转换的才做,然后再通过分类器的detectMultiScale方法,进行人脸检测,最后通过Imgproc.rectangle()方法,进行绘制人脸。

    对于detectMultiScale方法的传入参数,析意如下:

    1.image表示的是要检测的输入图像
    2.objects表示检测到的人脸目标序列
    3.scaleFactor表示每次图像尺寸减小的比例
    4.minNeighbors表示每一个目标至少要被检测到3次才算是真的目标(因为周围的像素和不同的窗口大小都可以检测到人脸)
    5.minSize为目标的最小尺寸
    6.minSize为目标的最大尺寸

    最后附上完整代码:

    package com.north.light.libopencv;
    
    import android.Manifest;
    import android.content.Context;
    import android.os.Build;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.WindowManager;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    
    import org.opencv.android.CameraBridgeViewBase;
    import org.opencv.android.JavaCameraView;
    import org.opencv.android.OpenCVLoader;
    import org.opencv.core.Core;
    import org.opencv.core.CvType;
    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 MainActivity extends AppCompatActivity implements CameraBridgeViewBase.CvCameraViewListener{
    
        private CameraBridgeViewBase openCvCameraView;
        private CascadeClassifier cascadeClassifier;
        private Mat grayscaleImage;
        private int absoluteFaceSize;
        private void initializeOpenCVDependencies() {
            try {
                InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
                File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                File 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();
                cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
            } catch (Exception e) {
                Log.e("OpenCVActivity", "Error loading cascade", e);
            }
            openCvCameraView.enableView();
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
    
            setContentView(R.layout.activity_main);   // 为该活动设置布局
            openCvCameraView = findViewById(R.id.activity_main_camera_view);
            openCvCameraView.setCvCameraViewListener(this);
    
        }
        @Override
        public void onCameraViewStarted(int width, int height) {
            grayscaleImage = new Mat(height, width, CvType.CV_8UC4);
            absoluteFaceSize = (int) (height * 0.2);
        }
    
        @Override
        public void onCameraViewStopped() {
        }
    
        @Override
        public Mat onCameraFrame(Mat aInputFrame) {
            Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);
            MatOfRect faces = new MatOfRect();
            if (cascadeClassifier != null) {
                cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 3, 2,
                        new Size(absoluteFaceSize, absoluteFaceSize), new Size());
            }
            Rect[] facesArray = faces.toArray();
            for (int i = 0; i <facesArray.length; i++){
                Imgproc.rectangle(aInputFrame, facesArray[i].tl(), facesArray[i].br(), new Scalar(0, 255, 0, 255), 3);
            }
            return aInputFrame;
        }
        @Override
        public void onResume() {
            super.onResume();
    
            if (!OpenCVLoader.initDebug()) {
            }
            initializeOpenCVDependencies();
            final String[] permissions = {
                    Manifest.permission.CAMERA
            };
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                requestPermissions(permissions,0);
            }
        }
    
        @Override
        public void onBackPressed() {
            super.onBackPressed();
            Log.d("返回键","back back back");
        }
    }
    

    至此,人脸检测已经完成,不过目前检测人脸的预览显示,还是横屏了,官方的demo也是横屏显示的,而对于竖屏显示,请看我下一篇文章。
    that's all---------------------------------------------------------------------------------

    相关文章

      网友评论

          本文标题:安卓OpenCV开发(二)人脸检测

          本文链接:https://www.haomeiwen.com/subject/hwfweltx.html