使用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(版本必須與NDK\SDK兼容,可從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