Wons' Blog

个人博客

后端程序猿 - Python / C++ / Java


回首向来萧瑟处,也无风雨也无晴

使用OpenCV Android SDK从摄像头帧实时检测人脸

在配置好 OpenCV Android SDK 之后(具体见前一篇文章Android Studio中使用OpenCV Android SDK),可以使用 OpenCV 封装的接口很方便地进行各种图像处理操作。

这里简单介绍如何直接使用 OpenCV 训练的人脸模型直接从摄像头帧检测人脸。

1. 新建Android Project

这里可以直接使用默认的 Android Studio 项目模板, Activity 选择 Empty Activity

2. 配置OpenCV Android SDK

参考前一篇文章: Android Studio中使用OpenCV Android SDK

3. 向 AndroidManifest.xml 中添加 Camera 相关的 Permission

AndroidManifest.xml 文件 <application> 节点前添加如下代码:

<uses-permission android:name="android.permission.CAMERA"/>

<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>

4. 添加OpenCV训练的人脸模型

OpenCV Android SDKsdk/etc 目录下的 lbpcascade_frontalface.xml 文件复制到项目 app/src/main/res/raw 目录下。

5. 修改 MainActivity.java 的代码

修改 MainActivity.java 的代码为:

public class MainActivity extends AppCompatActivity
        implements CameraBridgeViewBase.CvCameraViewListener {


    private CameraBridgeViewBase openCvCameraView;
    private CascadeClassifier cascadeClassifier;
    private Mat grayscaleImage;
    private int absoluteFaceSize;


    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                    initializeOpenCVDependencies();
                    break;
                default:
                    super.onManagerConnected(status);
                    break;
            }
        }
    };


    private void initializeOpenCVDependencies() {


        try {
            // Copy the resource into a temp file so OpenCV can load it
            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();


            // Load the cascade classifier
            cascadeClassifier = new CascadeClassifier(mCascadeFile.getAbsolutePath());
        } catch (Exception e) {
            Log.e("OpenCVActivity", "Error loading cascade", e);
        }


        // And we are ready to go
        openCvCameraView.enableView();
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);


        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);


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


    @Override
    public void onCameraViewStarted(int width, int height) {
        grayscaleImage = new Mat(height, width, CvType.CV_8UC4);


        // The faces will be a 20% of the height of the screen
        absoluteFaceSize = (int) (height * 0.2);
    }


    @Override
    public void onCameraViewStopped() {
    }


    @Override
    public Mat onCameraFrame(Mat aInputFrame) {
        // Create a grayscale image
        Imgproc.cvtColor(aInputFrame, grayscaleImage, Imgproc.COLOR_RGBA2RGB);


        MatOfRect faces = new MatOfRect();


        // Use the classifier to detect faces
        if (cascadeClassifier != null) {
            cascadeClassifier.detectMultiScale(grayscaleImage, faces, 1.1, 2, 2,
                    new Size(absoluteFaceSize, absoluteFaceSize), new Size());
        }


        // If there are any faces found, draw a rectangle around it
        Rect[] facesArray = faces.toArray();
        for (int i = 0; i <facesArray.length; i++)
            Core.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()) {
            Log.e("log_wons", "OpenCV init error");
            // Handle initialization error
        }
        initializeOpenCVDependencies();
        //OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_6, this, mLoaderCallback);
    }
}

6. 编译程序,运行

编译之后运行程序,程序会获取手机上的默认相机(一般为后置摄像头)并进行人脸检测。

效果:

人脸检测效果

参考资料

知乎日报: Android相机开发那些坑

Android Developers: Camera

OpenCV Documentation: OpenCV4Android SDK

最近的文章

在Android Studio中进行NDK开发的一般流程

1 在类中声明native方法2 在 app/src/main 下创建 jni 目录3 在 app/src/main/java 下运行命令 javah -jni -d ../jni com.path2class.ClassName4 在 app/src/main/jni 下生成了对应的头文件,创建cpp源文件,利用此头文件实现对应的native方法5 在 app 下的 build.gradle 文件中,android->defaultConfig下添加代码:ndk { m...…

Android继续阅读
更早的文章

Android Studio中使用OpenCV Android SDK

OpenCV是著名的跨平台计算机视觉开源库,广泛应用于计算机视觉相关领域。OpenCV 已经发布 Android 平台下的 SDK,可以直接导入 Android Studio。OpenCV Android SDK 下载地址: Download OpenCV Android SDK 。Android Studio项目中配置使用OpenCV Android SDK1 在项目根目录下创建 libraries 目录。2 复制 Android SDK 中目录 sdk 下的 java 文件夹到刚刚创建...…

Android继续阅读