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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第1张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第2张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第3张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第4张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第5张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第6张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第7张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第8张图片

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

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

  界面代码




    

、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 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 的设置权限,主要是对摄像头添加权限




    

    
    
    
    

    

    
        
            
                

                
            
        
    

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

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

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第9张图片

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第10张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第11张图片

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第12张图片

还有一个编译设置

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第13张图片

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

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第14张图片

 

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第15张图片

但是,这个代码中下面对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文件。

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第16张图片

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

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

Android基于OpenCV的人脸检测(OpenCV SDK 4.5.1)_第17张图片

 

你可能感兴趣的:(opencv,android,jni)