Android calls OpenCV configuration method

1. Environment

Windows10
Android studio 3.0
Android NDK: android-ndk-r16b
Opencv3.2.0

2. Preparation

Download Android studio3.0, android-ndk-r16b, download link: http://www.androiddevtools.cn/index.html

Download the opencv-3.2.0-android-sdk.zip package, and unzip the download link: https://opencv.org/releases.html

3. Start building the sample project

Create a new android project, check Include C++ support, and then all the way to next until finish.

There may be an error at the beginning, it is probably ndk not found, the solution is to add the ndk path.
Click file->project structure



After Android studio2.3, it supports the include C++ support option, which can automatically create NDK projects, saving development time.
After the project is created, you can see that the cpp folder is automatically created under src/main/, and the native-lib.cpp file is created under it:

#include <jni.h>
#include <string>

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_v_1fanlulin_testdemoforopencv_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

Inside is a sample function, using C++ to return a string "Hello from C++".
This method can be called by Android java code through Jni.

The approach in Java code is:

package com.example.v_fanlulin.testdemoforopencv;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.4000106090
    static {
        System.loadLibrary("native-lib");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Example of a call to a native method
        TextView tv = (TextView) findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
}


by

static {
    System.loadLibrary("native-lib");
}

Load the native-lib library.

by

/**
 * A native method that is implemented by the 'native-lib' native library,
 * which is packaged with this application.
 */
public native String stringFromJNI();

A native method is declared, which is implemented in native-lib.cpp.

With c++ code and java code, to implement java calling c++, c++ needs to be compiled into a dynamic library. This requires an important file CMakeLists.txt, which is used to compile c++ code into a dynamic library that can be called by java. It declares the library, path, source file and other information needed for compilation.

The complete CMakeLists.txt content is as follows:

   # For more information about using CMake with Android Studio, read the
    # documentation: https://d.android.com/studio/projects/add-native-code.html
    
    # Sets the minimum version of CMake required to build the native library.
    
    cmake_minimum_required(VERSION 3.4.1)
    
    # Creates and names a library, sets it as either STATIC
    # or SHARED, and provides the relative paths to its source code.
    # You can define multiple libraries, and CMake builds them for you.
    # Gradle automatically packages shared libraries with your APK.
    
    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 )
    
    # Searches for a specified prebuilt library and stores the path as a
    # variable. Because CMake includes system libraries in the search path by
    # default, you only need to specify the name of the public NDK library
    # you want to add. CMake verifies that the library exists before
    # completing its build.
    
    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 )
    
    # Specifies libraries CMake should link to your target library. You
    # can link multiple libraries, such as libraries you define in this
    # build script, prebuilt third-party libraries, or system libraries.
    
    target_link_libraries( # Specifies the target library.
                           native-lib
    
                           # Links the target library to the log library
                           # included in the NDK.
                           ${log-lib} )

At this point, all the components that call C++ code in Android are complete. The same is true for calling opencv code.


4. Integrate opencv library

4.1 Import opencv library

Copy the libs folder under opencv-3.2.0-android-sdk\OpenCV-android-sdk\sdk\native to the main directory of the project and rename it to jniLibs.

4.2 配置CMakeLists.txt

Set the path of opencv, configure native dependencies, import the libopencv_java3.so file, and finally link lib_opencv in target_link_libraries.
The complete CMakeLists.txt is as follows:

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

set(pathToOpenCv E:/Android/opencv-3.2.0-android-sdk/OpenCV-android-sdk)#设置OpenCv的路径变量
# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

#支持-std=gnu++11
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#配置加载native依赖
include_directories(${pathToOpenCv}/sdk/native/jni/include)

set(CURRENT_DIR ${CMAKE_SOURCE_DIR})
# 在Gradle Console输出信息
# CMAKE_SOURCE_DIR:
message("CURRENT_DIR:" ${CMAKE_SOURCE_DIR})

#动态方式加载
add_library(lib_opencv STATIC IMPORTED ) #表示创建一个导入库,静态方式
#引入libopencv_java3.so文件
set_target_properties(lib_opencv
                       PROPERTIES
                       IMPORTED_LOCATION ${CURRENT_DIR}/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so
                       )

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.

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 )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

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 )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

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

4.3 Code declaration and implementation

Declare the native method you want to call in MainActivity. For example, you want to call an image blur method:

public native int[] imgBlur();

After the declaration, it needs to be implemented in cpp. It is very convenient to use the code prompt alt+enter to directly generate the jni declaration and function body of the function in native-lib.cpp.

Just write the corresponding opencv code in the function to do image processing.

After writing, the complete native-lib.cpp file is as follows:

#include <jni.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

extern "C"
JNIEXPORT jstring

JNICALL
Java_com_example_v_1fanlulin_testdemoforopencv_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

extern "C"
JNIEXPORT jintArray JNICALL
Java_com_example_v_1fanlulin_testdemoforopencv_MainActivity_imgBlur(JNIEnv *env, jobject instance,
                                                                    jintArray buf, jint w,
                                                                    jint h) {
    jint *cbuf = env->GetIntArrayElements(buf, JNI_FALSE );
    if (cbuf == NULL) {
        return 0;
    }

    Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf);
    /*图像处理开始*/
    cvtColor(imgData,imgData,CV_BGRA2BGR);
    blur(imgData,imgData,Size(20,20));
    cvtColor(imgData,imgData,CV_BGR2BGRA);
    /*图像处理结束*/
    uchar *ptr = imgData.data;
    int size = w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, (const jint *)ptr);
    env->ReleaseIntArrayElements(buf, cbuf, 0);
    return result;
}

Call the native method in MainActivity, the complete code is as follows:

package com.example.v_fanlulin.testdemoforopencv;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.4000106090
    static {
        System.loadLibrary("native-lib");
    }

    private ImageView mImageView;
    private Bitmap bitmapBack;//用于备份的bitmap

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mImageView =  (ImageView) findViewById(R.id.iv);
    }

    /**
     * 恢复为原图
     * @param view
     */
    public void converToOrig(View view) {
        //直接从备份的bitmapBack拿图片
        if(bitmapBack==null){
            bitmapBack = BitmapFactory.decodeResource(getResources(), R.mipmap.genie);

        }
        mImageView.setImageBitmap(bitmapBack);

    }

    /**
     * 模糊图像
     * @param view
     */
    public void converToBlur(View view) {
        //从imageview上获取bitmap图片
        mImageView.setDrawingCacheEnabled(true);
        Bitmap bitmap = mImageView.getDrawingCache();

        int w=bitmap.getWidth(),h=bitmap.getHeight();
        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);
        //调用native函数,模糊图像
        int[] resultInt=imgBlur(pix, w, h);
        Bitmap resultImg=Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
        resultImg.setPixels(resultInt, 0, w, 0, 0,w, h);
        mImageView.setDrawingCacheEnabled(false);
        mImageView.setImageBitmap(resultImg);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();

    public native int[] imgBlur(int[] buf,int w,int h);
}

4.3 Operation effect

Original image:
Original image

After blurring:

After blur

5. Other errors and solutions that may be encountered

5.1 Package conflict

Error:Execution failed for task ':app:preDebugAndroidTestBuild'.
>Conflict with dependency 'com.android.support:support-annotations' in project ':app'. Resolved versions for app (26.1.0) and test app (27.1.1) differ. See https://d.android.com/r/tools/test-apk-dependency-conflicts.html for details.

Solution:
Add to the dependencies in the build.gradle of the app:

  androidTestCompile('com.android.support:support-annotations:26.1.0'){
        force = true
 }

Reference article: https://www.jianshu.com/p/9f5758c36b34

Guess you like

Origin blog.csdn.net/fxjzzyo/article/details/86650133