OpenCV - Android Studio 2.2 中利用CAMKE进行OpenCV的NDK开发

  我在http://www.cnblogs.com/fx-blog/p/8206737.html一文中提到了如何在Android Studio中Java层导入OpenCV(包含opencv_contrib部分),可是这仅仅是Java层的导入,随着学习的深刻,咱们能够渐渐的发现OpenCV库对Java的支持不是很给力,好比我使用SIFT算法时,通常提取出来的特征点有一万多个,这其中包含了大量的无效特征点,若是我想指定特征点的数目,好比说500个(通过测试,Java中利用OpenCV提取特征点默认为500),可是OpenCV Java库中并无提供这样的方法(或者是我没有发现,若是有大神知晓,还望告知)。可是在C++中,是能够给SIFT指定特征点的,这里面就须要有一个在Java中调用C++的功能,Java中咱们知道能够利用JNI或者JNA解决,那么在Androd中咱们即可以利用NDK作到Java对C++的调用。html

  在Android Studio 2.2以前,咱们一般是经过Android.mk和Application.mk两个文件设置本地开发;可是在Android Studio 2.2以后的版本,加入了利用CMAKE配置编译NDK项目的方法,这无疑是一个很好的消息,咱们终于能够抛弃以前那种繁琐的方法啦,本篇文章只要讲的就是在Android Studio中利用CMAKE进行OpenCV的NDK开发。java

准备工做:

  首先,咱们须要在Android Studio中配置CMAKE、NDK工具,打开Android Studio 2.2,点击按钮打开SDK Manager,在SDK Platforms中选择你所须要的Android版本,这里我使用的是Android 7.0。android

    

   在SDK Tools中选择红框标出的部分(这里推荐SDK Manager当中提供的NDK,NDK安装好后路径为<Android SDK Path>\ndk-bundle):c++

    

正式开始:

  建立一个新项目,在建立的过程当中,咱们须要勾选Include C++ Support,以后的步骤默认便可,能够与http://www.cnblogs.com/fx-blog/p/8206737.html相应正,写的不是很好,你们见谅。算法

  项目建立成功以后,会自动在app\src\main下创建一个名为cpp的文件夹,其中包含一个native-lib.cpp文件。同时,在app目录下会多出一个CMakeLists.txt文件,Android Studio调用CMAKE利用该文件来协调C++代码的编译(默认使用Clang编译),并将产生的.so文件提供给apk文件的打包过程。app

  而后须要在Java层导入OpenCV,OpenCV 3.2 Android SDK能够选用以前编译好的库,下载地址:https://pan.baidu.com/s/1kVOejLt;在Android Studio中点击File -> New… -> Import Module,而后在Source Directory中选取<OpenCV 3.2 Android SDK>\sdk\java目录,这时Module Name就会自动变成“openCVLibrary320”,以后的步骤采用默认设置便可。ide

  刚刚导入OpenCV包以后,Android Studio会尝试自动编译,因为其默认的build.gradle文件设置并不适合最新版本,因此会报错。修改openCVLibrary320\build.gradle为以下内容就会纠正这些错误(红框标出的部分须要与app\build.gradle一致)。函数

    

   点击File -> Project Structure,在左边的Modules中点击“app”,而后点击右边的加号,再选择Module Dependency,而后在弹出框中选择:openCVLibrary320。这样,就为咱们的项目app在Java层上添加了OpenCV支持(其中library是我使用的另一个库,不用理会)。工具

    

接下来就是配置利用CMAKE配置OpenCV应用了:

  首先,须要将应用OpenCV C++所须要头文件和库文件所有复制到项目中,将<OpenCV 3.2 Android SDK>\sdk\native\jni\include文件夹复制到app\src\main\cpp当中,把<OpenCV 3.2 Android SDK>\sdk\native\libs文件夹复制到app\src\main当中,并将文件夹重命名为jniLibs。学习

    

  而后将 app\build.gradle修改成(各位看官能够对比修改):

apply plugin: 'com.android.application'

android {
    compileSdkVersion 25
    buildToolsVersion "27.0.1"
    defaultConfig {
        applicationId "com.example.demo02"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11", "-frtti", "-fexceptions"
                abiFilters 'x86', 'x86_64', 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'mips', 'mips64'
            }
        }
    }
    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/jniLibs']
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
}

dependencies {
    compile 'com.android.support:design:25.3.1'
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    compile project(':openCVLibrary320')
}

  app\CMakeLists.txt修改成:

cmake_minimum_required(VERSION 3.4.1)

set(CMAKE_VERBOSE_MAKEFILE on)
set(ocvlibs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)

add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES
                      IMPORTED_LOCATION "${ocvlibs}/${ANDROID_ABI}/libopencv_java3.so")

add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

target_link_libraries( # Specifies the target library.
                       native-lib android log libopencv_java3

                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

  配置部分就此完成了,贴一下关键部分的代码吧,NDK帮助类OpenCVNDKHelper:

1 package com.example.ndk;
2 
3 public class OpenCVNDKHelper {
4     static {
5         System.loadLibrary("native-lib");
6     }
7     public native static void detectFeatures(long srcMatAddr, long dstMatAddr);
8 }

  C++文件native-lib.cpp:

 1 #include <jni.h>
 2 #include <string>
 3 #include <opencv2/core/core.hpp>
 4 #include <opencv2/features2d/features2d.hpp>
 5 #include <opencv2/xfeatures2d/nonfree.hpp>
 6 
 7 using namespace std;
 8 using namespace cv;
 9 using namespace xfeatures2d;
10 
11 extern "C"
12 {
13     JNIEXPORT void JNICALL Java_com_example_ndk_OpenCVNDKHelper_detectFeatures
14         (JNIEnv *, jclass, jlong srcMatAddr, jlong dstMatAddr) {
15         Mat* srcMat = (Mat*)srcMatAddr;
16         Mat* descriptors = (Mat*)dstMatAddr;
17         vector<KeyPoint> Keypoints;
18         Ptr<SIFT> detector = SIFT::create(1000);
19         detector->detect(*srcMat, Keypoints);
20         detector->compute(*srcMat, Keypoints, *descriptors);
21     }
22 }

  这段代码主要的做用就是提取Sift特征(这里我就不介绍生成.h文件的过程了,只要掌握.cpp文件中的函数命名的方法,这个过程是能够省略的啦)。

  补充一点:这个代码其实也解释了如何在Java中将Mat传递到C++中的方法,在java中的调用以下(src和srcMat为Mat对象):

OpenCVNDKHelper.detectFeatures(src.getNativeObjAddr(), srcMat.getNativeObjAddr());

 

  PS:文章中使用的jniLibs是直接拷贝到目录中的,这个项目的存储空间就比较大了,大约1G左右,每次新建项目都须要从新拷贝,你们也能够用软连接或者绝对路径代替,这里就很少介绍啦。可是最终生成的APK文件大小是差很少的。

  over~~~

 

跑下题:

  写博客的过程当中,老爸突然找我视频聊天,咱们聊了蛮多,主要就是催我找个女友,难道95后也要被家长催找女友了吗,感受从我6月份毕业以来(可能更早),这个话题就没有停过啊,脑补过年回家的场面。。。

相关文章
相关标签/搜索