OpenCV在Android Studio中有3中方式调用:

  1. Java API

  2. JNI + .so

  3. JNI + Cmake + 源码编译

准备环境

Win10

Android Studio 3.6

OpenCV Android SDK 3.4

NDK 16

注意不同的版本之间的对应关系:

OpenCV NDK minSdkVersion
3.4 16 19
4.2 21 21
4.3 21 21
1 创建c++项目

2 NDK变量设置

演示教程

修改文件

activity_main.xml

TextView标签替换成ImageView标签,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent" />

</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity.java

修改函数public class MainActivity extends AppCompatActivity,修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class MainActivity extends AppCompatActivity {

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

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

// img process
ImageView imageView = findViewById(R.id.imageView);
//lenna是要处理的文件名,忽略后缀
final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.lenna);
//final Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(R.drawable.lenna)).getBitmap();
//imageView.setImageBitmap(bitmap);
getEdge(bitmap);
imageView.setImageBitmap(bitmap);
}

/**
* A native method that is implemented by the 'native-lib' native library,
* which is packaged with this application.
*/
public native String stringFromJNI();
//获得Canny边缘
public native void getEdge(Object bitmap);
}

完整MainActivity.java代码如下:

native-lib.cpp

在函数Java_com_demo_opecvjni3_MainActivity_getEdge(JNIEnv *env, jobject thiz, jobject bitmap)中添加如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
AndroidBitmapInfo info;
void *pixels;
CV_Assert(AndroidBitmap_getInfo(env, bitmap, &info) >= 0);
CV_Assert(info.format == ANDROID_BITMAP_FORMAT_RGBA_8888 ||
info.format == ANDROID_BITMAP_FORMAT_RGB_565);
CV_Assert(AndroidBitmap_lockPixels(env, bitmap, &pixels) >= 0);
CV_Assert(pixels);
if (info.format == ANDROID_BITMAP_FORMAT_RGBA_8888) {
Mat temp(info.height, info.width, CV_8UC4, pixels);
Mat gray;
cvtColor(temp, gray, COLOR_RGBA2GRAY);
Canny(gray, gray, 45, 75);
cvtColor(gray, temp, COLOR_GRAY2RGBA);
} else {
Mat temp(info.height, info.width, CV_8UC2, pixels);
Mat gray;
cvtColor(temp, gray, COLOR_RGB2GRAY);
Canny(gray, gray, 45, 75);
cvtColor(gray, temp, COLOR_GRAY2RGB);
}
AndroidBitmap_unlockPixels(env, bitmap);

发现全是红色,因为我们还没有添加一些必要的头文件和依赖,稍后会生成。

CmakeLists.txt

注意两个地方:

  1. 将opencv native jni 的路径修改成自己的

  2. 末尾 target_link_libraries含有${OpenCV_LIBS}jnigraphics的字段。

修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 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)

# OpenCV_DIR 需要自己定义
set( OpenCV_DIR E:\\WorkStation\\Opencv_Tutorials\\source\\opencv-3.4.10-android-sdk\\OpenCV-android-sdk\\sdk\\native\\jni )

find_package(OpenCV REQUIRED )
if(OpenCV_FOUND)
include_directories(${OpenCV_INCLUDE_DIRS})
message(STATUS "OpenCV library status:")
message(STATUS " version: ${OpenCV_VERSION}")
message(STATUS " libraries: ${OpenCV_LIBS}")
message(STATUS " include path: ${OpenCV_INCLUDE_DIRS}")
else(OpenCV_FOUND)
message(FATAL_ERROR "OpenCV library not found")
endif(OpenCV_FOUND)


# 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).
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.
${OpenCV_LIBS}
jnigraphics
${log-lib} )
生成.h文件

确保 javah添加到系统环境变量,可以调用执行。我的javah.exeD:\Android Studio\jre\bin目录下,可供参考。

在Android Studio 中打开终端,执行:

1
2
3
4
# 进入 app/src/main/java 目录
cd app/src/main/java
# 执行语句,注意opencvjni3是我的包名
javah com.demo.opencvjni3.MainActivity

无报错的话,会生成.h文件

生成的.h文件我们移动到cpp的目录下:

结构如图:

添加图片文件

原图lenna.png:

将图片文件,添加至app > cpp > res > drawable目录下,文件结构如图:

修改native-lib.cpp

添加头文件,注意.h文件的名称:

1
2
3
4
5
#include <android/bitmap.h>
#include <opencv2/opencv.hpp>
#include "com_demo_opencvjni3_MainActivity.h"

using namespace cv;

完整的native-lib代码如下:

运行

效果如图

Q&A


Q:

A:

CmakeList.txt 出现错误,尝试查看OpenCV_DIR路径,以及这段代码:

1
2
3
4
5
6
7
8
target_link_libraries( # Specifies the target library.
native-lib

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

Q:

A:

NDK与OpenCV版本不符


Q:

libnative-lib.so', missing and no known rule to make it

A:

CmakeList.txt 中路径有问题

Android NDK CMake初体验 - Channing的博客 | Channing Blog


Q:

A:

minSdkVersion设置错误:

打开 bulid.gradle (:app) > android > defaultConfig > minSdkVersion 设置为21

这一步需要注意两个地方

1、包名,请尽量与我保持一致,否则新手容易出错。
2、最小SDK:OpenCV 4.2.0要求最小SDK必须大于21。

下一步直接Finish,项目创建成功!

参考资料

# 基于Android studio3.6的JNI教程之opencv实例详解

Junyss的个人空间 - 哔哩哔哩 ( ゜- ゜)つロ 乾杯~ Bilibili

OpenCV On Android最佳环境配置指南(Android Studio篇) - 简书