AndroidStudio,opncv,ndk,jni,人脸识别示例程序

毕设要做人脸识别。在网上查了资料,决定使用AS+NDK+JNI+OpenCV完成。于是就在坑摸爬滚打了几天。今天总算把OpenCV里的人脸识别示例程序运行起来了。

现在的情况是:熟悉android,c/c++以前学过基础,没有在项目中使用过,opencv没有碰过。

几个概念

  • NDK提供编译打包等工具,是一个工具的集合。提供一定的API。
  • Jni 需要明确的是:这是java的东西,不是android的东西。作用是提供api与其他语言通信。使java与本地已编译好的代码交互。
  • .so 与Android手机cpu架构有关的动态链接库。说到底就是一个库文件。其实本来是linux下的。比如某些地图api的集成需要导入.so库,多个文件对应着不同的cpu架构。
  • 静态链接库所有的依赖文件都编译进去。
  • 动态链接库编译的时候不把依赖编译进去,运行时动态查找。
  • 交叉编译在一个平台生成另一个平台的可执行的代码。
  • mk文件指定需要编译的文件,还有一些库的引入。在ndk-build的时候会用到。

参考的文章

  • Android Studio ndk-Jni开发详解这篇文章主要介绍了如何实现HelloWorld。把具体的操作流程说了一遍。我按这个做的时候遇到了一个问题,找不到头文件具体的实现:c/c++文件。发现原来不能完全copy,c文件里的方法名要和生成头文件相同。另外这篇文章里的代码贴的代码有一些小问题,不过都比较容易解决。在实现过后感觉懵懵懂懂,知道了怎么做,却不知道为什么这么做。对照下面这个图会帮助理解。

  • Android Studio 使用jni编译opencv完整实例这篇文章介绍了他如何运行opencv和遇到的坑。我就是因为这个坑找到这篇文章的。就是那个找不到头文件的问题。根据文章里的方法确实解决了,然后又遇到了另一个问题。运行后找不到对应的c方法。后来发现是因为没有生成对应我的手机的cpu架构的so文件。

具体实现流程

1.当然是创建project啦,这里需要注意的是包名。原因的话后面就知道了。其他的和平时创建没有什么不同。

2.下载opencv for android OpenCV官网

3.安装,设置NDK,在Project Structure中设置NDK,如果没有的话直接可以点击下载。

4.导入OpenCV-android-sdk\samples\face-detection。在AS中,file->new->import module,直接下一步下一步,finish。

5.Message会提示

在gradle.properties中添加android.useDeprecatedNdk=true即可。

6.看这个目录


jni文件夹里这几个东西是是干嘛的?先不管,运行了再说。然后出现了这个。

7.编译so文件

找不到这个文件。其实,java代码里调用的是so库,而不是直接调用c文件。所以我们要先生成so库。
先到jni目录 cd 你的目录,然后调用 ndk-build命令(注意ndk要配置环境变量)。然后又出现了一个问题,如下图。


在Android.mk里出的问题,找不到OpenCV.mk。去opencv的sdk里找找,发现其实是有opencv.mk的,那应该是路径问题了。把图里的位置改成自己sdk里opencv.mk的位置.

8.运行
改好后再次ndk-build。应该可以成功运行了,然后在main文件夹下生成了obj和libs文件夹。这时候运行一下。那个找不到头文件的问题依然在。我按照上面参考文章说的,其实在生成so文件后那个文件就已经没有用了。把它删了就好。
再次运行,运行成功,在安装opencv manager后,又报错了!

找不到方法的实现。这里是因为没有调用so文件。
在build.gradle中的android下添加代码

android {
    compileSdkVersion 14
    buildToolsVersion "19.1.0"

    defaultConfig {
        applicationId "org.opencv.samples.facedetect"
        minSdkVersion 8
        targetSdkVersion 8

        ndk {
            moduleName "detection_based_tracker"
        }
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
-----------------------------------------------
    sourceSets {

        main() {

            jniLibs.srcDirs = ['src/main/libs']

        }

    }
-----------------------------------------------
}

再次点运行。可以运行了!心理瞬间有底了。如果还有找不到方法实现的问题,可能是因为不支持你的机器的cpu架构。在application.mk中可以修改。

现在思考的问题是,怎么调试程序。想想都烦的很,得找找有什么好的解决方案。