Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)

      近日突然对Android上的人脸检测感兴趣,就小试了一下。中间也遇到了一些坑。下面是完整的过程。

1)      首先,关于Android OpenCV的SDK的下载,这里就不赘述了。下面使用的是Android Studio 4.1.1,下载的OpenCV SDK版本是4.5.1.。SDK解压到文件夹里面。

2)将OpenCV的SDK导入到工程      

Android Studio 创建空白工程,然后,通过菜单里面的Import Module,加载SDK

选择刚才OpenCV解压路径下的SDK

点击确定后,会在Android Studio的项目目录中出现sdk,表明导入成功

然后,需要修改导入sdk的build.gradle中的配置,要与app的build.gradle的版本号一致

主要是compileSdkVersion,sdk和app的build.gradle版本一致。

接下来,要在app中引用sdk。通过项目右键菜单,打开Open Module Setting

通过下面操作顺序,引入对sdk的依赖

操作成功后,可以在app的build.gradle中看到对sdk引用的说明

此次,初步编译一次项目,运行。这里是不会出现异常。空白工程能在手机上正常运行。

3)添加代码,实现手机摄像头的实时采集显示

  界面代码

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <org.opencv.android.JavaCameraView
        android:id="@+id/cjv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00090808" />

</androidx.constraintlayout.widget.ConstraintLayout>

、MainActity代码

public class MainActivity extends CameraActivity implements CameraBridgeViewBase.CvCameraViewListener2 {

    private static final String    TAG                 = "OCVSample::Activity";

    private CameraBridgeViewBase mOpenCvCameraView;

    private Mat                  mIntermediateMat;




    private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                {
                    Log.i(TAG, "OpenCV loaded successfully");

                    mOpenCvCameraView.enableView();

                } break;
                default:
                {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
        setContentView(R.layout.activity_main);

        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.cjv);

        mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);

        //这里的cjv也是我的项目中JavaCameraView的id,自己改一下
        mOpenCvCameraView.setCvCameraViewListener(this);

    }

    @Override
    public void onCameraViewStarted(int width, int height) {

    }

    @Override
    public void onCameraViewStopped() {
        if (mIntermediateMat != null)
            mIntermediateMat.release();


        mIntermediateMat = null;

    }

    @Override
    protected List<? extends CameraBridgeViewBase> getCameraViewList() {
        return Collections.singletonList(mOpenCvCameraView);
    }


    @Override
    public Mat onCameraFrame(CameraBridgeViewBase.CvCameraViewFrame inputFrame) {
        Mat rgba = inputFrame.rgba();
        Size sizeRgba = rgba.size();
        Mat temp = new Mat();
        Mat dst = new Mat();
        Imgproc.cvtColor(rgba, temp , Imgproc.COLOR_RGBA2BGR);
        Imgproc.cvtColor(temp, dst, Imgproc.COLOR_BGR2GRAY);
        return dst;


    }

   

    @Override
    protected void onResume() {
        super.onResume();

        if (!OpenCVLoader.initDebug()) {
            Log.d(TAG, "Internal OpenCV library not found. Using OpenCV Manager for initialization");
            OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_0_0, this, mLoaderCallback);
        } else {
            Log.d(TAG, "OpenCV library found inside package. Using it!");
            mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
        }

    }


    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();

    }

   
}

Manifest 的设置权限,主要是对摄像头添加权限

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.haardemo">

    <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"/>

    <supports-screens android:resizeable="true"
        android:smallScreens="true"
        android:normalScreens="true"
        android:largeScreens="true"
        android:anyDensity="true" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.HaarDemo">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

运行程序,可以在手机中看到灰度化的影像。

3)添加层叠分类器和JNI的引用

首先,将层叠分类器(xml文件)复制到工程res下面的raw中来

其次,在工程目录中添加JNI(这里,我将OpenCV SDK提供的Sample中的人脸检测代码中的jni目录整个复制到工程目录中)

然后,打开app的build.gradle添加对ndk的编译选项

还有一个编译设置

此时,编译工程,会在工程目录中成功看到so文件编译出来了,程序不会报任何异常,能运行。我们距离成功不远了。

感兴趣的各位可以用winrar解压生成的apk文件,你会发现so文件已经被打包到apk里面的lib里面了。

 

接下来,我们需要在代码中引用so文件里面提供的jni方法。可以将sdk中sample里面的DetectionBasedTracker类的代码引入到当前工程。

但是,这个代码中下面对JNI代码的外部引用会报红色错误。

private static native long nativeCreateObject(String cascadeName, int minFaceSize);
private static native void nativeDestroyObject(long thiz);
private static native void nativeStart(long thiz);
private static native void nativeStop(long thiz);
private static native void nativeSetFaceSize(long thiz, int size);
private static native void nativeDetect(long thiz, long inputImage, long faces);

这里这个坑,主要时因为我们cpp代码里面,开放出来的接口的命名空间与当前工程的不一致,需要修改。可以打开cpp文件和h文件。

下面划红线的地方要和我们当前工程的包名一致。这一点很重要,很重要,很重要。

4)MainActity添加完整的人脸检测代码,这里,注意对着Sample复制过来就好,这里笔者没有任何代码创新。本文的目的在于讲述整个操作过程,所以,最终代码与Sample一致。

5)编译,运行。效果如下图。学艺未精,只认出了一张人脸。更多的参数,还需要进一步学习。这次现分享到这里。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值