0%

为Android编译OpenCV3_SDK

OpenCV 整套代码是基于 C 和 C++实现的,在 Android 上调用存在两种方式:

  • Java Native 代码实现
  • C++ NDK 代码实现

** 其中 Java Native 代码实现是直接通过 Java OpenCV API 编写算法实现部分,相对应的特点在于:**

  • 环境搭建简单:直接引入官方 OpenCV-for-Android 的对应 jar 包即可
  • 代码维护繁琐:由于OpenCV-for-AndroidJava APIC++不完全相同,任何算法的更新都需要重写 => 在存在 Windows、iOS 等多平台更新时比较麻烦
  • 运行效率低:Java 代码会在内部进行 C++翻译,运行时性能损耗较大

** 而直接采用 C++代码导入的方式的特点在于:**

  • 环境搭建复杂:往往需要现自行编译对应的库,再进行NDK、Cmakelistsbuild.gradle的配置.
  • 代码维护简单:由于直接采用 C++实现算法部分,与其他平台的兼容性极好,能与 Android 程序员分离开发 => 算法升级时替换对应的算法库文件即可.
  • 运行效率高:不存在内部执行时的代码转换问题,性能最好.
  • 总结来看,Java Native 代码实现是爽一时但是后面会不爽很久,对于有时间精力且要求较高的开发任务,强烈建议多花点时间搭建 C++ NDK 方式.

如果自己不从源码编译也可去这里下载,网上很多配置教程都是基于这里下载的 SDK 而写的.如: Android Studio 集成 OpenCV


Python 脚本编译

  • 依赖工具
    • CMake > 3.7
    • ninja-build
    • ccache
    • python

安装编译工具

1
2
3
4
5
6
7
~$ apt-get install ninja-build  ccache
~$ export ANDROID_SDK=/fullpath/Android/Sdk
~$ export ANDROID_NDK=/fullpath/Android/Sdk/android-ndk-r16b

~$ mkdir build
~$ cd build ../opencv-3.4.1/platforms/android/build_sdk.py --no_ccache --extra_module=/fullpath/opencv_contrib-3.4.1/modules --config=ndk-16.config.py build-ndk ../opencv-3.4.1

  • 使用opencv-3.4.1/platforms/android/build_sdk.py 脚本安装,可以一次编译多种平台的 SDK,相关的一些配置要参照文件ndk-16.config.py.
  • 如果没有出错误的话,build-ndk目录结构如下:
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
~$ tree build-ndk -L 1
build-ndk
├── build_service_arm64-v8a
├── build_service_armeabi
├── build_service_armeabi-v7a
├── build_service_x86
├── build_service_x86_64
├── o4a
└── OpenCV-android-sdk

7 directories, 0 files

~$ tree build-ndk/OpenCV-android-sdk/ -L 2
build-ndk/OpenCV-android-sdk/
├── apk
│   ├── OpenCV_3.4.1_Manager_3.41_arm64-v8a.apk
│   ├── OpenCV_3.4.1_Manager_3.41_armeabi.apk
│   ├── OpenCV_3.4.1_Manager_3.41_armeabi-v7a.apk
│   ├── OpenCV_3.4.1_Manager_3.41_x86_64.apk
│   ├── OpenCV_3.4.1_Manager_3.41_x86.apk
│   └── readme.txt
├── LICENSE
├── README.android
├── samples
│   ├── 15-puzzle
│   ├── camera-calibration
│   ├── color-blob-detection
│   ├── example-15-puzzle.apk
│   ├── example-camera-calibration.apk
│   ├── example-color-blob-detection.apk
│   ├── example-face-detection.apk
│   ├── example-image-manipulations.apk
│   ├── example-tutorial-1-camerapreview.apk
│   ├── example-tutorial-2-mixedprocessing.apk
│   ├── example-tutorial-3-cameracontrol.apk
│   ├── face-detection
│   ├── image-manipulations
│   ├── tutorial-1-camerapreview
│   ├── tutorial-2-mixedprocessing
│   └── tutorial-3-cameracontrol
└── sdk
├── build.gradle
├── etc
├── java
└── native

14 directories, 17 files

~$ tree build-ndk/OpenCV-android-sdk/sdk/native -L 2
build-ndk/OpenCV-android-sdk/sdk/native
├── 3rdparty
│   └── libs
├── jni
│   ├── abi-arm64-v8a
│   ├── abi-armeabi
│   ├── abi-armeabi-v7a
│   ├── abi-x86
│   ├── abi-x86_64
│   ├── android.toolchain.cmake
│   ├── include
│   ├── OpenCV-arm64-v8a.mk
│   ├── OpenCV-armeabi.mk
│   ├── OpenCV-armeabi-v7a.mk
│   ├── OpenCVConfig.cmake
│   ├── OpenCVConfig-version.cmake
│   ├── OpenCV.mk
│   ├── OpenCV-x86_64.mk
│   └── OpenCV-x86.mk
├── libs
│   ├── arm64-v8a
│   ├── armeabi
│   ├── armeabi-v7a
│   ├── x86
│   └── x86_64
└── staticlibs
├── arm64-v8a
├── armeabi
├── armeabi-v7a
├── x86
└── x86_64

21 directories, 9 files

CMake 编译方式

编译环境

  • android-ndk-r14b

  • tools_r25.2.5

  • 这里可能要注意, 本次编译测试必須使用**[tools_r25.2.5]**

  • 建议使用**[tools_r25.2.5]**测试编译,不然有可能会出现如下错误

1
2
3
4
5
6
7
8
9
10
--     SDK target:  android_sdk_target-NOTFOUND

[...]
The "android" command is deprecated.
For manual SDK, AVD, and project management, please use Android Studio.
For command-line tools, use tools/bin/sdkmanager and tools/bin/avdmanager
*************************************************************************
Invalid or unsupported command "--silent create lib-project --path /fullpath/opencv-3.4.1/build-android/android_sdk --target android_sdk_target-NOTFOUND --name OpenCV --package org.opencv"
[...]

CMake 单独编译参数

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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
~$ cd /fullpath/Android/Sdk
~$ ln -svf tools_r25.2.5 tools
~$ ln -svf android-ndk-r14b ndk-bundle
~$ export ANDROID_NDK=/fullpath/Android/Sdk/ndk-bundle
~$ cmake
-D ANDDROID_ABI=armeabi-v7a
-D ANDROID_FUNCTION_LEVEL_LINKING=ON
-D ANDROID_NATIVE_API_LEVEL=19
-D ANDROID_NDK_HOST_X64=ON
-D ANDROID_NDK_NOEXECSTACK=ON
-D ANDROID_STL=gnustl_static
-D BUILD_JPEG=ON
-D BUILD_PNG=ON
-D BUILD_PACKAGE=ON
-D CMAKE_TOOLCHAIN_FILE=/fullpath/opencv-3.4.1/platforms/android/android.toolchain.cmake
-D ANDROID_SDK=/fullpath/Android/Sdk
-D ANDROID_FORCE_ARM_BUILD=OFF
-D ANDROID_NO_UNDEFINED=ON
-D BUILD_ANDROID=ON
-D BUILD_ANDROID_EXAMPLES=ON
-D OPENCV_EXTRA_MODULES_PATH=/fullpath/opencv_contrib-3.4.1/modules
-D BUILD_PYTHON_SUPPORT=ON
-D BUILD_opencv_python3=ON
-D PYTHON_DEFAULT_EXECUTABLE=$HOME/.pyenv/versions/3.6.5/bin/python3.6m
-D PYTHON_INCLUDE_DIRS=$HOME/.pyenv/versions/3.6.5/include/python3.6m
-D PYTHON_EXECUTABLE=$HOME/.pyenv/versions/3.6.5/bin/python3.6
-D PYTHON_LIBRARY=$HOME/.pyenv/versions/3.6.5/lib/libpython3.6m.so.1.0
-D BUILD_JDK=ON
-D BUILD_opencv_java=ON
-D CMAKE_INSTALL_PREFIX=/fullpath/opencv3-android-ndk ../

[...]
-- Linker flags (Release): -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-allow-shlib-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
-- Linker flags (Debug): -Wl,--fix-cortex-a8 -Wl,--no-undefined -Wl,-allow-shlib-undefined -Wl,--gc-sections -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now
-- ccache: NO
-- Precompiled headers: NO
-- Extra dependencies: z dl m log
-- 3rdparty dependencies: libcpufeatures libprotobuf libjpeg libwebp libpng libtiff libjasper IlmImf tegra_hal
--
-- OpenCV modules:
-- To be built: aruco bgsegm bioinspired calib3d ccalib core datasets dnn dnn_objdetect dpm face features2d flann fuzzy hfs highgui img_hash imgcodecs imgproc java_bindings_generator line_descriptor ml objdetect optflow phase_unwrapping photo plot python_bindings_generator reg rgbd saliency shape stereo stitching structured_light superres surface_matching text tracking ts video videoio videostab xfeatures2d ximgproc xobjdetect xphoto
-- Disabled: js world
-- Disabled by dependency: -
-- Unavailable: cnn_3dobj cudaarithm cudabgsegm cudacodec cudafeatures2d cudafilters cudaimgproc cudalegacy cudaobjdetect cudaoptflow cudastereo cudawarping cudev cvv dnn_modern freetype hdf java matlab ovis python2 python3 sfm viz
-- Applications: tests perf_tests
-- Documentation: NO
-- Non-free algorithms: NO
--
-- Android:
-- Android ABI: armeabi-v7a
-- STL type: gnustl_static
-- Native API level: android-19
-- SDK target: android-19
-- Android NDK: /fullpath/Android/Sdk/ndk-bundle-r14b (toolchain: arm-linux-androideabi-4.9)
-- android tool: /fullpath/3TB-DISK/Android/Sdk/tools/android (Android SDK Tools, revision 25.2.5.)

--
-- GUI:
--
-- Media I/O:
-- ZLib: z (ver 1.2.3)
-- JPEG: build (ver 90)
-- WEBP: build (ver encoder: 0x020e)
-- PNG: build (ver 1.6.34)
-- TIFF: build (ver 42 - 4.0.9)
-- JPEG 2000: build (ver 1.900.1)
-- OpenEXR: build (ver 1.7.1)
[...]
-- Java: export all functions
-- ant: /fullpath/ant/current/bin/ant (ver 1.10.1)
-- Java wrappers: YES
-- Java tests: YES
[...]
-- Install to: /fullpath/opencv3-android-ndk

~$ make -j4
[...]

# 编译成功的标志
BUILD SUCCESSFUL
Total time: 6 seconds
[100%] Built target example-color-blob-detection
[100%] Copy project sources: example-tutorial-1-camerapreview
COPYFILES: ... 1 entries (SRC_COPY)
COPYFILES: ... directory '.../android/tutorial-1-camerapreview' with 5 files
COPYFILES: All files are up-to-date.
[100%] Built target example-tutorial-1-camerapreview_copy_src
Scanning dependencies of target example-tutorial-1-camerapreview
[100%] Updating Android project at /fullpath/opencv-3.4.1/samples/android/tutorial-1-camerapreview. SDK target: android-19
[100%] Generating example-tutorial-1-camerapreview-debug.apk

BUILD SUCCESSFUL
Total time: 6 seconds
[100%] Built target example-tutorial-1-camerapreview
[100%] Copy project sources: example-tutorial-2-mixedprocessing
COPYFILES: ... 1 entries (SRC_COPY)
COPYFILES: ... directory '.../android/tutorial-2-mixedprocessing' with 5 files
COPYFILES: All files are up-to-date.
[100%] Built target example-tutorial-2-mixedprocessing_copy_src
[100%] Built target mixed_sample
Scanning dependencies of target example-tutorial-2-mixedprocessing
[100%] Updating Android project at /fullpath/opencv-3.4.1/samples/android/tutorial-2-mixedprocessing. SDK target: android-19
[100%] Generating example-tutorial-2-mixedprocessing-debug.apk

BUILD SUCCESSFUL
Total time: 6 seconds
[100%] Built target example-tutorial-2-mixedprocessing
[100%] Copy project sources: example-tutorial-3-cameracontrol
COPYFILES: ... 1 entries (SRC_COPY)
COPYFILES: ... directory '.../android/tutorial-3-cameracontrol' with 6 files
COPYFILES: All files are up-to-date.
[100%] Built target example-tutorial-3-cameracontrol_copy_src
Scanning dependencies of target example-tutorial-3-cameracontrol
[100%] Updating Android project at /fullpath/opencv-3.4.1/samples/android/tutorial-3-cameracontrol. SDK target: android-19
[100%] Generating example-tutorial-3-cameracontrol-debug.apk

BUILD SUCCESSFUL
Total time: 6 seconds
[100%] Built target example-tutorial-3-cameracontrol


~$ make install
  • 运行完成make install后,所有相关的库文件都会安装到**/fullpath/opencv3-android-ndk**,目录如下:
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
opencv3-android-ndk$ tree -L 3
.
├── apk
│   └── readme.txt
├── LICENSE
├── README.android
└── sdk
├── build.gradle
├── etc
│   ├── haarcascades
│   ├── lbpcascades
│   ├── valgrind_3rdparty.supp
│   └── valgrind.supp
├── java
│   ├── AndroidManifest.xml
│   ├── gen
│   ├── lint.xml
│   ├── project.properties
│   ├── res
│   └── src
└── native
├── 3rdparty
├── jni
├── libs
└── staticlibs

14 directories, 9 files

Android Studio 集成 OpenCV 测试

  • 这里可以直接导入一个 OpenCV Samples 工程做测试,我编译安装完上述 SDK 后,使用了samples/tutorial-1-camerapreview这个工程做测试,正常情况下,app 会通过 opencv 打开摄像头.

原有工程,添加 OpenCV 支持

  • 创建一个支持 C++的 Android 工程
  • 导入模块, File->New->Import Module ,选择**/fullpath/opencv3-android-ndk** ,这里我把它命名为**:opencv_sdk**, Finish.
  • 如果 IDE 没有报错,
  • 进入 File>Project Structure. 选择app ,点击Dependencides,点击+->3 Module dependency->模块名,
  • 等几分钟,IDE 就会处理完导入库的操作.
  • 如果在File>Project Structure没有看到一个新的模块名opencv_sdk,但是它的目录已经复制到工程目录的根目录下了,就在settings.gradle里的include后面加上如: include ‘:app’,’opencv_sdk’
  • 因为我本次使用的是Android-Studio 3.1的版本,要把build.gradle里的修改成 26以上,不然会出错:
1
2
3
4
5
6
7
8
9
10
11
12
android {
compileSdkVersion 27
//buildToolsVersion "27.0.3" // not needed since com.android.tools.build:gradle:3.0.0

defaultConfig {
minSdkVersion 14
targetSdkVersion 26
}

[...]
}

  • 导入模块后,IDE 会把 opencv 相关复制工程根目录下,目录名为opencv_sdk.导入后 Android 工程目录如下:
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
~$ tree -L 1
.
├── app
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── local.properties
├── opencv3_android.iml
├── opencv_sdk
└── settings.gradle

~$ tree app -L 4
app
├── app.iml
├── build.gradle
├── CMakeLists.txt
├── libs
├── proguard-rules.pro
└── src
├── androidTest
│   └── java
│   └── com
├── main
│   ├── AndroidManifest.xml
│   ├── cpp
│   │   └── native-lib.cpp
│   ├── java
│   │   └── com
│   └── res
│   ├── drawable
│   ├── drawable-v24
│   ├── layout
│   ├── menu
│   ├── mipmap-anydpi-v26
│   ├── mipmap-hdpi
│   ├── mipmap-mdpi
│   ├── mipmap-xhdpi
│   ├── mipmap-xxhdpi
│   ├── mipmap-xxxhdpi
│   ├── raw
│   └── values
└── test
└── java
└── com

25 directories, 6 files

~$ tree opencv_sdk -L 3
opencv_sdk
├── build.gradle
├── etc
│   ├── haarcascades
│   │   ├── haarcascade_eye_tree_eyeglasses.xml
│   │   ├── haarcascade_eye.xml
│   │   ├── haarcascade_frontalcatface_extended.xml
│   │   ├── haarcascade_frontalcatface.xml
│   │   ├── haarcascade_frontalface_alt2.xml
│   │   ├── haarcascade_frontalface_alt_tree.xml
│   │   ├── haarcascade_frontalface_alt.xml
│   │   ├── haarcascade_frontalface_default.xml
│   │   ├── haarcascade_fullbody.xml
│   │   ├── haarcascade_lefteye_2splits.xml
│   │   ├── haarcascade_licence_plate_rus_16stages.xml
│   │   ├── haarcascade_lowerbody.xml
│   │   ├── haarcascade_profileface.xml
│   │   ├── haarcascade_righteye_2splits.xml
│   │   ├── haarcascade_russian_plate_number.xml
│   │   ├── haarcascade_smile.xml
│   │   └── haarcascade_upperbody.xml
│   ├── lbpcascades
│   │   ├── lbpcascade_frontalcatface.xml
│   │   ├── lbpcascade_frontalface_improved.xml
│   │   ├── lbpcascade_frontalface.xml
│   │   ├── lbpcascade_profileface.xml
│   │   └── lbpcascade_silverware.xml
│   ├── valgrind_3rdparty.supp
│   └── valgrind.supp
├── java
│   ├── AndroidManifest.xml
│   ├── gen
│   ├── lint.xml
│   ├── project.properties
│   ├── res
│   │   └── values
│   └── src
│   └── org
├── native
│   ├── 3rdparty
│   │   └── libs
│   ├── jni
│   │   ├── abi-armeabi-v7a
│   │   ├── android.toolchain.cmake
│   │   ├── include
│   │   ├── OpenCV-armeabi-v7a.mk
│   │   ├── OpenCVConfig.cmake
│   │   ├── OpenCVConfig-version.cmake
│   │   └── OpenCV.mk
│   ├── libs
│   │   └── armeabi-v7a
│   └── staticlibs
│   └── armeabi-v7a
└── opencv_sdk.iml

19 directories, 34 files

JNI C++开发,调用 OPENCV

  • 如果我们要在 Android 工程里的使用 JNI 直接调用 opencv 的 API 函数,如上面工程 src/main/cpp/native-lib.cpp.
    需要在app/build.gradleandroid结点里添加相关路径:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

android {

[...]
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}

sourceSets {
main {
jni.srcDirs = [jni.srcDirs,'../opencv_sdk/native/jni/include']
jniLibs.srcDirs = [jniLibs.srcDirs,'../opencv_sdk/native/3rdparty/libs','../opencv_sdk/native/libs']
}
}
}
  • app/CMakeLists.txt里要包含如下信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18

    set(pathToOpenCV ${CMAKE_CURRENT_SOURCE_DIR}/../open_sdk )
    include_directories(${pathToOpenCV}/native/jni/include) # Not needed for CMake >= 2.8.11

    set(CMAKE_VERBOSE_MAKEFILE on)
    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
    add_library( lib_opencv STATIC IMPORTED )
    set_target_properties(lib_opencv PROPERTIES IMPORTED_LOCATION
    ${pathToOpenCV}/native/libs/${ANDROID_ABI}/libopencv_java3.so)
    target_link_libraries( # Specifies the target library.
    native-lib

    # Links the target library to the log library
    # included in the NDK.
    ${log-lib}
    lib_opencv # 要加上这lib_opencv 才能链接到opencv的库.
    )

  • 添加上述路径之后,就可以在src/main/cpp/native-lib.cpp 里添加#include <opencv2/opencv.hpp>.

  • 上述 JNI 方式开发就是写原生的 C++代码调用 API,编译成功后会生成.so的文件,通过 JNI 方式加载这个库文件,或者升级更新这个库文件,不需要修改 Android 的文件.但是不能像 PC 下那样使用,如:imshow(),namedWindow(),createTrackBar(),waitKey(),这些函数是不能用.


谢谢支持