交叉編譯OpenCV的Android版本
OpenCV作為一個強大的圖像處理庫,在Android上也有強大的應用。
OpenCV官網提供了SDK的下載,可以直接下載使用
OpenCV官網地址:https://opencv.org/
不過有時候也會有自定義編譯的需求
下面來記錄一下最近在交叉編譯OpenCV所作的筆記
避免以后走彎路。
編譯Host系統是Ubuntu 16.04
准備工作
下載opencv:
1 git clone git@github.com:opencv/opencv.git 2 git checkout 3.4
下載opencv依賴的庫
1 git clone git@github.com:opencv/opencv_contrib.git 2 git checkout 3.4
這里我們使用的版本都是3.4。
配置環境:
1. 安裝ant
編譯Java代碼需要用到ant或者gradle
但是我還沒搞清楚怎么配置使用gradle編譯
而且我這次是在服務器上工作,沒有x11環境
沒裝Android Studio,所以,姑且使用ant編譯Java。
修改opencv/CMakeLists.txt文件
激活ant編譯
set(ANDROID_PROJECTS_SUPPORT_ANT ON)
sudo apt-get install ant
2. 安裝ndk
安裝ndk需要翻wall,請自備梯子
這里寫了一個python程序,用於枚舉NDK的版本,
然后手動輸入選擇下載對應的版本,
這里我下載的r17c版本NDK,下載完成之后配置NDK_ROOT環境變量
1 #!/usr/bin/env python 2 3 import urllib2 4 import collections 5 import json 6 import os 7 8 def init(): 9 """ 10 Return name/link dict 11 12 @return: name-to-link dict 13 """ 14 with open('table.json') as data_file: 15 url_table = json.load(data_file) 16 17 if url_table is None or len(url_table) <= 0: 18 print('\033[91m' + ' There is no item in table.json ' + '\033[0m') 19 os.sys.exit(0) 20 21 # Sort alphabetically 22 url_table = collections.OrderedDict(sorted(url_table.items())) 23 index = 0 24 for key in url_table: 25 index = index + 1 26 print str(index) + '] ' + key 27 28 return url_table 29 30 def getTargetLink(desired_index, url_table): 31 """ 32 Return download link 33 34 @type desired_index: number 35 @param desired_index: Desired index 36 @type url_table: dict 37 @param url_table: name-to-link 38 39 @return: Download link 40 """ 41 index = 0 42 for key in url_table: 43 index = index + 1 44 if desired_index == index: 45 return url_table[key] 46 return None 47 48 def download(url): 49 if url == None: 50 return 51 52 file_name = url.split('/')[-1] 53 u = urllib2.urlopen(url) 54 f = open(file_name, 'wb') 55 meta = u.info() 56 file_size = int(meta.getheaders("Content-Length")[0]) 57 print "Downloading: %s Bytes: %s" % (file_name, file_size) 58 59 file_size_dl = 0 60 block_sz = 8192 61 while True: 62 buffer = u.read(block_sz) 63 if not buffer: 64 break 65 66 file_size_dl += len(buffer) 67 f.write(buffer) 68 status = r"%10d [%3.2f%%]" % (file_size_dl, file_size_dl * 100. / file_size) 69 status = status + chr(8)*(len(status)+1) 70 print status, 71 72 f.close() 73 74 if __name__ == '__main__': 75 url_table = init() 76 var = raw_input("Please enter the numer you want to download: ") 77 link = getTargetLink(int(var), url_table) 78 download(link)
3. 安裝SDK
由於我們需要編譯的android版本,需要用到SDK的build tools和sdk的platform版本庫
這里使用SDK的build tools版本是24.0.3
往上的版本,Google去掉了aidl,會導致沒法編譯Java端的代碼,也無法生成libopencv_java3.so
所以在下載的SDK版本中,build tools只能保留不高於24.0.3的版本
platform版本庫使用android-21
下載SDK的方法:
找一台裝有Android Studio的電腦,使用SDK Manager下載對應的版本即可
然后將SDK拷貝至交叉編譯的電腦上,配置SDK環境變量
export NDK_ROOT=/path/to/android-ndk-r17c
export ANDROID_HOME=path/to/sdk
4. 配置SDK tools版本
在我們的SDK中,有個tools目錄
具體的版本,是Android Studio在SDK Manager中配置的
但是OpenCV只能支持到tools_r25.2.5-linux.zip
所以需要手動下載tools_r25.2.5-linux.zip,解壓替換SDK目錄的tools
下載地址:https://dl.google.com/android/repository/tools_r25.2.5-linux.zip
5. 安裝CMake和其它編譯環境
sudo apt-get install cmake sudo apt-get install build-essential make
開始交叉編譯
由於OpenCV需要使用cmake編譯
需要配置很多參數,所以使用bash腳本是最方便的方式
編譯腳本放在opencv和opencv_contrib的同級目錄
#!/bin/bash NDK_ROOT="${1:-${NDK_ROOT}}" ### ABIs setup #declare -a ANDROID_ABI_LIST=("armeabi-v7a with NEON") declare -a ANDROID_ABI_LIST=("armeabi-v7a") ### path setup SCRIPT=$(readlink -f $0) WD=`dirname $SCRIPT` OPENCV_ROOT="${WD}/opencv" N_JOBS=${N_JOBS:-4} INSTALL_DIR="${WD}/opencv-build" rm -rf "${INSTALL_DIR}/opencv" ### Make each ABI target iteratly and sequentially for i in "${ANDROID_ABI_LIST[@]}" do ANDROID_ABI="${i}" echo "Start building ${ANDROID_ABI} version" if [ "${ANDROID_ABI}" = "armeabi" ]; then API_LEVEL=19 else API_LEVEL=21 fi temp_build_dir="${OPENCV_ROOT}/platforms/build_android_${ANDROID_ABI}" ### Remove the build folder first, and create it #-DANDROID_TOOLCHAIN_NAME=clang #-DANDROID_TOOLCHAIN_NAME="arm-linux-androideabi-5" \ #-DANDROID_STL=gnustl_static \ rm -rf "${temp_build_dir}" mkdir -p "${temp_build_dir}" cd "${temp_build_dir}" cmake -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \ -DCMAKE_TOOLCHAIN_FILE="${OPENCV_ROOT}/platforms/android/android.toolchain.cmake" \ -DANDROID_NDK="${NDK_ROOT}" \ -DANDROID_NATIVE_API_LEVEL=${API_LEVEL} \ -DANDROID_ABI="${ANDROID_ABI}" \ -DANDROID_CPP_FEATURES="rtti exceptions" \ -DANDROID_ARM_NEON=TRUE \ -DANDROID_STL=gnustl_static \ -DCMAKE_BUILD_TYPE=Release \ -D BUILD_opencv_java=ON \ -D BUILD_ANDROID_PROJECTS=ON \ -D WITH_CUDA=OFF \ -D WITH_MATLAB=OFF \ -D BUILD_ANDROID_EXAMPLES=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_TESTS=OFF \ -DOPENCV_EXTRA_MODULES_PATH="${WD}/opencv_contrib/modules/" \ -DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}/opencv" \ ../.. # Build it make -j${N_JOBS} # Install it make install/strip ### Remove temp build folder cd "${WD}" rm -rf "${temp_build_dir}" echo "${temp_build_dir}" echo "end building ${ANDROID_ABI} version" done
這里只啟用了armeabi-v7a編譯目標
其它平台可根據需求添加
目前無法使用ANDROID_TOOLCHAIN_NAME來指定clang編譯器
因為OpenCV的makefile在解析clang交叉編譯工具鏈使用的代碼沒做匹配
而我也暫時沒精力自己修改做匹配
有興趣的同學,可以修改
${OPENCV_ROOT}/platforms/android/android.toolchain.cmake
來匹配clang編譯器
STL鏈接使用的是gnu版本的
因為OpenCV用到了C++11
如果使用c++_static版本,因為Google沒做后續支持維護
gcc在這個工具鏈上不支持很多C++和C++11特性
會導致編譯失敗,我嘗試過使用CrystaX NDK
但是在configure階段就失敗了
只能無疾而終
其它編譯選項顧名思義,不做過多解析。
備注:
如果需要使用C++14特性編譯
需要修改opencv/CMakeList.txt文件
手動添加,pathch如下所示
--- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -156,7 +156,11 @@ endif() OCV_OPTION(ENABLE_CXX11 "Enable C++11 compilation mode" "${OPENCV_CXX11}") include(cmake/OpenCVDetectCXXCompiler.cmake) ocv_cmake_hook(POST_DETECT_COMPILER) - +set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_VERBOSE_MAKEFILE ON) +set(ANDROID_PROJECTS_SUPPORT_ANT ON) # Add these standard paths to the search paths for FIND_LIBRARY # to find libraries from these locations first if(UNIX AND NOT ANDROID)