Android Studio 2.2 uses CAMKE for OpenCV NDK development

I mentioned in how to import OpenCV in Java layer in Android Studio ( Including the opencv_contrib part), but this is just the import of the Java layer. With the deepening of learning, we can gradually discover that the OpenCV library does not support Java very much. For example, when I use the SIFT algorithm, the feature points that are generally extracted have one. More than 10,000, which contains a large number of invalid feature points, if I want to specify the number of feature points, say 500 (tested, Java uses OpenCV to extract feature points default to 500), but there is no OpenCV Java library Provide such a method (or I did not find it, if there is a big god know, I also hope to inform). However, in C++, it is possible to specify feature points for SIFT. There is a need to call C++ in Java. In Java, we know that JNI or JNA can be used. In Androd, we can use NDK to do it. Java calls to C++.

Before Android Studio 2.2, we usually set up local development through and files; but in Android Studio 2.2 and later, we added the method of compiling NDK project with CMAKE configuration, which is undoubtedly It's a good news, we can finally abandon the cumbersome method before, this article just talk about the use of CMAKE in Android Studio for OpenCV NDK development.


First, we need to configure CMAKE, NDK tools in Android Studio, open Android Studio 2.2, click 按钮打开SDK Manager,在SDK Platforms中选择你所需要的Android版本,这里我使用的是Android 7.0。


in the SDK Tools to select the red box marked part (recommended SDK here) The NDK provided in the Manager, the path of the NDK is installed is <Android SDK Path>\ndk-bundle):


officially started:

Create a new project. In the process of creating, we need to check the Include C++ Support, the following steps can be ok by default, and can be compared with, the writing is not very good, everyone forgive me.

After the project is successfully created, a folder named cpp will be created under app\src\main, which contains a native-lib.cpp file. At the same time, there will be a CMakeLists.txt file in the app directory. Android Studio calls CMAKE to use this file to coordinate the compilation of C++ code (by default, Clang is compiled), and the generated .so file is provided to the packaging process of the apk file.

Then you need to import OpenCV in the Java layer. OpenCV 3.2 Android SDK can be used to compile the library. Download address:; in Android Studio, click File -> New ... -> Import Module, then select <OpenCV 3.2 Android SDK>\sdk\java directory in the Source Directory, then the Module Name will automatically become "openCVLibrary320", and the subsequent steps will be the default settings.

Just after importing the OpenCV package, Android Studio will try to compile automatically. Since its default build.gradle file setting is not suitable for the latest version, it will report an error. Modifying openCVLibrary320\build.gradle to correct these errors (the red box marked part needs to be consistent with app\build.gradle).


Click File -> Project Structure, click on "app" in the Modules on the left, then click on the plus sign on the right, then select Module Dependency, then select: openCVLibrary320 in the pop-up box. In this way, we added OpenCV support to the Java layer for our project app (where library is another library I use, don't bother).


The next step is to configure the OpenCV application using CMAKE:

First, you need to copy all the header files and library files needed to apply OpenCV C++ to the project, <OpenCV 3.2 Android SDK>\sdk\native Copy the \jni\include folder to app\src\main\cpp, copy the <OpenCV 3.2 Android SDK>\sdk\native\libs folder to app\src\main and rename the folder to jniLibs.


Then change app\build.gradle to (you can compare and modify it):


apply plugin: ''

android {
    compileSdkVersion 25
    buildToolsVersion "27.0.1"
    defaultConfig {
        applicationId "com.example.demo02"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner ""
        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'), ''
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"

dependencies {
    compile ''
    compile fileTree(include: ['*.jar'], dir: 'libs')
    androidTestCompile('', {
        exclude group: '', module: 'support-annotations'
    compile ''
    testCompile 'junit:junit:4.12'
    compile project(':openCVLibrary320')


app\CMakeLists.txt is modified to:


cmake_minimum_required(VERSION 3.4.1)

set(ocvlibs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")

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

add_library( # Sets the name of the library.

             # Sets the library as a shared library.

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

find_library( # Sets the name of the path variable.

              # 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} )


Configuration section is completed, paste the key part of the code NDK help class OpenCVNDKHelper:


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


C++ file 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>
 7 using namespace std;
 8 using namespace cv;
 9 using namespace xfeatures2d;
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 }


The main function of this code is to extract the Sift feature (I will not introduce the process of generating the .h file here, as long as it is mastered. The method of function naming in the cpp file, this process can be omitted).

Add a little: This code actually explains how to pass Mat to C++ in Java. The call in java is as follows (src and srcMat are Mat objects):

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

PS: used in the article The jniLibs is copied directly to the directory. The storage space of this project is relatively large, about 1G. Every new project needs to be re-copied. You can also use soft links or absolute paths instead. I won't introduce it here. . But the resulting APK file size is similar.



In the process of writing a blog, Dad suddenly looked for me to video chat. We talked a lot, mainly reminding me to find a girlfriend. Is it necessary to be called by parents after 95? Is it a girlfriend? It feels that since I graduated in June (maybe earlier), this topic has not stopped, and the brain has been able to go home for the New Year. . .

真高贵 is not better than others, but better than the past!