使用Android NDK進行C++原生代碼開發時,如何配置項目來使用OpenCV靜態庫且支持NEON指令集+OMP多线程+OpenCL并行?
1.準備工具
- Android Studio(可選)
- Cmake編譯配置工具(使用Android Studio時,由於採用Gradle,因此必須使用AS內置cmake)
- NDK(Native C++ Development Kit),必須和Cmake版本匹配
- Android SDK,版本必須和NDK對應
- OpenCV Android SDK(版本必須與NDKSDK兼容,可從GitHub上下載Release的Android編譯版本)
【題外:版本選擇依據爲——OpenCV最新版本->兼容的NDK/SDK版本->支持的Cmake版本->最新的Android Studio版本】
2.創建項目
前述:本示例項目採用omp(openmp及open multi-threads parallel多線程並行編譯支持,opencv內部已包含,但項目中編譯時還需手動添加到CmakeList.txt中)
1.創建新項目,如圖





2.打開C++源碼編輯自己的程序,如圖

3.點擊三角按鈕將同時進行編譯和運行,編譯完成的程序會自動安裝在USB鏈接的Android手機上(確保手機調試開關打開,新手機的打開方式是連續點擊系統設置中的Android版本號直至成功消息出現,小米手機還需要特別開啓通過USB安裝APP權限開關)

4.由於下載的OpenCV一般是Release版本,且APP開發完成後發布應用也需要採用Release方式編譯,因此,請設置編譯選項如圖

5.編譯信息全部在下方BUILD選項卡中顯示,如圖

6.在選擇Release方式變異後,雖然能成功編譯,但運行時會報錯,原因是未配置Release的发布签名(签名的作用是保护初始开发者的代码不受他人更改盗用),如图

7.点击Fix按钮配置签名,如图,由于还未创建过签名,因此需要先创建一个,如图,在build->generate signed apk->key store->create new中创建

8.其余信息按实填写即可,如图

9.创建完成,选择记住密码,以后不必填写密码,如图

10.下一步非常重要!如图设置

11.完成后,再点击RUN按钮解决签名配置问题,也即应用该签名进行应用部署,如图

12.在Flavor(默认配置)中选择刚才创建的签名配置config,如图

13.在Build Types中选择刚才创建的签名配置config,如图

14.最终点击OK,返回运行界面,再点击RUN发现可以直接运行了,选择调试机器为USB连接的真机即可(没有真机可选用虚拟机),如图

15.安装过程中被告知无法正常安装,因为存在应用替换的情形,如图,选择OK即可

16.在RUN选项卡中查看运行调试信息,如图

17.至此,Release版本的NDK项目创建完成,但尚未添加opencv支持,请配置Gradle,如图,图中选中区域为新增配置代码
其中Gradle代码如下
arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_ARM_NEON=TRUE"
abiFilters 'arm64-v8a'
Gradle是基于Groovy的脚本语言,用于配置编译、发布应用,其中签名创建其实也可以在本文件中进行(是第二个build.gradle文件!)
其中arguments用于添加c++代码编译选项,比如希望支持ARM的NEON扩展并行处理指令集,可以添加上述代码;
其中abiFilters用于指示编译目标平台,截至2020年1月14日,大部分Android新机都采用的是ARM64-v8a架构支持64位指令集,兼容32位指令集,因此选择arm64-v8a即可。
另外,为了支持opencv-4.1.1,sdk版本不能低于28,Gradle中Sdk配置部分修改如下

18.点击Sync Now,完成配置同步,也可在右侧配置区选择手动同步,如图

19.修改默认的NDK配置,例如,在本项目中使用了最新稳定版本的opencv 4.1.1,而该版本不支持NDK-16.1,所以替换为更高版本的NDK-19.2,如图

20.接下来,要配置cmakelists.txt,是最为关键的一步,添加opencv支持就是在这里完成的,如图,添加框中的代码,用于告知cmake编译器opencv的具体地址,以及对应的头文件、静态库位置、版本信息、需要加载的模块名称等,cmake会找到opencv目录下对应版本的opencvConfig.cmake来获取所需的编译信息。
cmake新增的脚本代码如下
# opencv configuration
set( OpenCV_ANDROID_SDK E:/opencv-4.1.1-android-sdk-omp )
set( OpenCV_DIR ${OpenCV_ANDROID_SDK}/sdk/native/jni )
find_package(OpenCV REQUIRED core highgui calib3d imgproc imgcodecs features2d ximgproc photo)
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)
21.接下来解决编译之后的链接(Linker)问题,如图,修改cmakelists.txt如下
本段代码如下
target_link_libraries( # Specifies the target library.
native-lib
${OpenCV_LIBRARIES}
# Links the target library to the log library
# included in the NDK.
${log-lib} )
# add open mp for opencv
SET( CMAKE_CXX_FLAGS "-fopenmp ${CMAKE_CXX_FLAGS}" )
22.如果项目中还是用了OpenCL做GPU加速,还需要添加以下代码支持, 如图。(由于OpenCL库是由厂商(vendor)自行提供,因此存在缺失的可能,opencl库并非android系统的预装库,因此找不到也是可能的,或者也可能没有访问该库的权限,这些都会导致OPENCL代码无法执行,为此,需要添加fallback机制,当不支持OPENCL时,自动回退到CPU版本代码继续执行。)
cmake脚本如下
include_directories(src/main/cpp/)
add_library(OpenCL STATIC src/main/cpp/libopencl.cpp)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR
CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR
CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
target_compile_options(OpenCL PRIVATE -O2 -fPIC -Wall)
endif()
23.需要注意的是,使用OPENCL时,需要添加相应的opencl头文件和动态库加载模块(编译为静态库,这一步在步骤22中已完成),所以需要添加相应的头文件到代码所在目录,并且添加opencl加载模块的cpp文件到应用代码中,如图

24.其中CLBackend是自定义的opencl代码,其余均为用于加载opencl库的代码,由于依赖于自己写的加载opencl的模块,且该模块被编译成了一个静态库,所以需要添加该库名至target_link_lib中,如图

25.再次编译,显示编译成功,如图。

26.点击运行,查看效果,成功运行,如图
结束语:至此,本demo项目就已经完成了NDK+OPENCV+NEON+OMP+OPENCL所有支持。项目的全部代码和文件在本人的gitee或github上可查看。地址为
Gitee: Android NDK Demo with support of OpenCV & NEON & OMP & OPENCL.
Github: Android NDK Demo