Android Studio配置并运行OpenCV4Android的face-detection

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/wblgers1234/article/details/74852811

0. 开发环境

之前一直是用ADT bundle自带的Eclipse来做OpenCV4Android的开发,其实AS(Android Studio)经过几年的发展已经逐渐完善,对Android开发的支持也好过Eclipse,所以痛下决心,这一次就花点时间把OpenCV4Android在AS中配置好。我会尽量把配置过程写得详细点,因为自己在配置过程中也遇到了很多坑。

为什么要选择face-detection这个project呢?相信熟悉OpenCV4Android的同学都知道fd的人脸识别模块调用的是jni的库,所以正好在借这个机会把jni在Android Studio里面的配置也搞清楚。

下面是我的开发环境清单:

  • 操作系统: Win7
  • Android Studio 2.2.2
  • JDK&JRE: 1.8
  • OpenCV4Android-2.4.10
  • NDK: android-ndk-r10d

1. 导入eclipse程序

1.1 确定SdkVersion

在导入程序之前,我们需要先确定待会的OpenCv工程中的一些和SdkVersion有关的配置,最好的办法就是先用AS建一个HelloWorld,也可以顺便熟悉一下Android Studio的开发流程。在工程中打开build.gradle,可以得到我们需要的信息:

#这两个很重要
compileSdkVersion 25
buildToolsVersion "25.0.2"
#这个随意,和开发的APP的兼容性有关
minSdkVersion 21
targetSdkVersion 25

1.2 导入samples\face-detection

在Android Studio的界面上,选择File->New->Import Project:
这里写图片描述
在弹出的框里面选择OpenCV-2.4.10-android-sdk下的samples\face-detection,点击OK:
这里写图片描述

选择Next:
这里写图片描述

下一步请按下图勾选,然后点击Finish:
这里写图片描述

此时Android Studio会新打开一个窗口实例来导入工程,不出意外会出现如下错误:
这里写图片描述

此时,我们在AS左侧的Project窗口的打开如下的配置文件:
openCVSamplefacedetection->src->build.gradle
这里写图片描述

修改如下4个配置信息:

compileSdkVersion 14
buildToolsVersion "25.0.2"

minSdkVersion 8
targetSdkVersion 8

按照之前的HelloWorld工程里的配置进行修改:
这里写图片描述

在修改完成之后,需要重新进行”Gradle project sync”,点击Tools->Android->Sync Project with Gradle Files:
这里写图片描述

Oops,貌似又报错了:

Error:Failed to find target with hash string 'android-14' in: D:\develop\Android_Studio\sdk
<a href="install.android.platform">Install missing platform(s) and sync project</a>

原因在于,工程openCVSamplefacedetection依赖于库工程openCVLibrary2410,而库工程openCVLibrary2410的build.gradle配置也需要修改。这里不再赘述,找到openCVLibrary2410下的build.gradle进行修改即可。

修改完成后再次进行”Gradle project sync”,这一次”Gradle Sync”没有报错,随后AS会进行”Gradle build”,也顺利完成。

接下来我们尝试进行工程构建,点击工具栏中的“锤子”图案进行构建:
这里写图片描述

这一次出现以下错误,分析可以知道是fd工程的jni C++部分没有被正确编译。

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':openCVSamplefacedetection:compileDebugNdk'.
> Error: Your project contains C++ files but it is not using a supported native build system.

1.3 jni的配置

怎样解决上面出现的问题?
首先,我们需要先配置NDK的路径,点击File->Project Structure,在如下的界面上配置NDK的路径。
这里写图片描述

然后,在左侧的项目窗口中选中openCVSamplefacedetection,右键点击”Link C++ Project with Gradle”,在弹出的窗口中按照下图选择,点击”OK”。
这里写图片描述

接下来,在左右的项目窗口中的“External Build Files”下,选择Android.mk,修改OpenCV.mk的路径:

include ../../sdk/native/jni/OpenCV.mk

修改后的路径为,当然你需要根据自己电脑上的OpenCV4Android路径进行配置:

include D:\develop\OpenCV-2.4.10-android-sdk\sdk\native\jni\OpenCV.mk

最后一个需要修改的地方,修改对应于当前module(openCVSamplefacedetection)的build.gradle:
这里写图片描述

在第12行的ndk部分加入以下的声明:

abiFilters "armeabi-v7a"

最终得到:

ndk {
    abiFilters "armeabi-v7a"
    moduleName "detection_based_tracker"
}

至此,整个jni部分的配置就全部完成,这时再点击”构建“,可以发现已经可以生成成功。

BUILD SUCCESSFUL

2. 剔除OpenCV Manager依赖

在上一小节中,我们已经可以成功地配置fd工程,并且编译生成都成功,此时我们可以将apk部署到手机上进行运行。但是等等,你还想被OpenCV Manager所困扰吗?说实话,每次我想要找到适合自己手机的OpenCV Manager,都要上网查一大堆资料,费时又费劲。

那么接下来我就基于face-detection工程,给大家分享一个去掉OpenCV Manager依赖的方法。

找到mainActivity,在我们这里是FdActivity,如下两段代码是载入OpenCV Manager的核心代码:

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

                // Load native library after(!) OpenCV initialization
                System.loadLibrary("detection_based_tracker");

                try {
                    // load cascade file from application resources
                    InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
                    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                    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();

                    mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
                    if (mJavaDetector.empty()) {
                        Log.e(TAG, "Failed to load cascade classifier");
                        mJavaDetector = null;
                    } else
                        Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());

                    mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);

                    cascadeDir.delete();

                } catch (IOException e) {
                    e.printStackTrace();
                    Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
                }

                mOpenCvCameraView.enableView();
            } break;
            default:
            {
                super.onManagerConnected(status);
            } break;
        }
    }
};
@Override
public void onResume()
{
    super.onResume();
    OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}

在onResume method中进行OpenCVLoader的初始化,然后在回调函数onManagerConnected中,当OpenCV Manager载入成功,则进行后续的初始化。

要完全剔除OpenCV Manager的依赖,我们在编译构建apk时就选择将当前依赖的.so库进行静态链接,而不是动态地在app运行时再动态链接。

首先,将OpenCV-2.4.10-android-sdk\sdk\native下的libs文件夹拷贝至face-detection\openCVSamplefacedetection\src\main,并且重新命名为jniLibs;

然后修改代码,移除前面两段代码,在当前的activity中加入如下的静态声明:

static{ 
    System.loadLibrary("opencv_java"); 
}

将下面这段代码搬移到onCreate函数的最后部分。

// Load native library after(!) OpenCV initialization
System.loadLibrary("detection_based_tracker");

try {
    // load cascade file from application resources
    InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
    File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
    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();

    mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
    if (mJavaDetector.empty()) {
        Log.e(TAG, "Failed to load cascade classifier");
        mJavaDetector = null;
    } else
        Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());

    mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);

    cascadeDir.delete();

} catch (IOException e) {
    e.printStackTrace();
    Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
}

mOpenCvCameraView.enableView();

这时,我们可以惊喜地发现,在手机上没有安装OpenCV Manager的情况下,face-detection也可以顺利运行。

3. 运行效果

在手机上实测的人脸识别效果如下所示:
这里写图片描述

猜你喜欢

转载自blog.csdn.net/wblgers1234/article/details/74852811