坑
在android studio中使用时,会出现如下错误
undefined reference to `cv::imwrite(cv::String const&, cv::_InputArray const&, std::__ndk1::vector<int, std::__ndk1::allocator > const&)’
clang++: error: linker command failed with exit code 1 (use -v to see invocation)
ninja: build stopped: subcommand failed.
这个错误不是编译的错误,因为通过查看动态库的符号表,imwrite是有定义的,更奇怪的是imread的使用是正常的,这就完全不符合makefile的编译逻辑了。我把imwrite函数重写去vector参数的传入,再编译使用,imwrite正常写了,但是这样能解决这个问题,但其他函数还有同样问题,总不能opencv带vector的接口全部改一遍。
所以,我断定不是编译问题,更不是代码问题,只能是编译方法的问题(STL)。注意到,我的android studio中jni用的-DANDROID_STL=c++_shared,而在编译opencv时,使用gnustl_static.
下面尝试改用c++_shared来编译(经过多次编译实验成功了)
首先,在网上查相关资料:
- opencv3及以下的版本仅仅支持gnustl_shared编译
- NDK16之后就不支持gnustl_shared的编译了,使用libc++作为默认的STL
基于以上两点,我选择opencv3.4.1和NDK r.18b。
imwrite用gnustl_static编出动态库的符号
_ZN2cv7imwriteERKNS_6StringERKNS_11_InputArrayERKSt6vectorIiSaIiEE
imwrite用c++_shared编出动态库的符号
_ZN2cv7imwriteERKNS_6StringERKNS_11_InputArrayERKNSt6__ndk16vectorIiNS6_9allocatorIiEEEE
二者的符号不同。
准备
下载android-sdk
android-sdk
解压
tools 执行 ./android update sdk
选择一个build-tools安装
android-ndk
https://developer.android.google.cn/ndk/downloads
下载android-ndk-r18b-linux-x86_64.zip
生成独立的工具链
./build/tools/make-standalone-toolchain.sh --install-dir=../android-toolchain-r18b/ --toolchain=arm-linux-androideabi
下载opencv源码
git clone bashhttps://github.com/opencv/opencv.git
git show 3.4.1 # commit-id
git reset --hard commit-id
git checkout -b 3.4.1
编译
在opencv根目录创建build.sh文件
#!/bin/bash
NDK_ROOT="/home/q/project/opencv_compile/opt/android-ndk-r18b"
### ABIs setup
ANDROID_ABI_LIST=("arm64-v8a" "armeabi-v7a")
### path setup
SCRIPT=$(readlink -f $0)
WD=`dirname $SCRIPT`
OPENCV_ROOT="${WD}"
N_JOBS=${N_JOBS:-4}
INSTALL_DIR="${WD}/build"
rm -rf "${INSTALL_DIR}"
### 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=24
fi
temp_build_dir="${OPENCV_ROOT}/platforms/build_android_${ANDROID_ABI}"
### Remove the build folder first, and create it
rm -rf "${temp_build_dir}"
mkdir -p "${temp_build_dir}"
cd "${temp_build_dir}"
echo ${INSTALL_DIR}
cmake \
-DCMAKE_MAKE_PROGRAM=/usr/bin/make \
-DCMAKE_BUILD_WITH_INSTALL_RPATH=ON \
-DCMAKE_TOOLCHAIN_FILE=${NDK_ROOT}/build/cmake/android.toolchain.cmake \
-DANDROID_ABI=${ANDROID_ABI} \
-DANDROID_STL=c++_shared \
-DCMAKE_BUILD_TYPE=Release \
-DANDROID_NATIVE_API_LEVEL=${API_LEVEL} \
-DCMAKE_BUILD_TYPE=Release \
-DWITH_FFMPEG=ON \
-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 \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DANDROID_SDK="/home/q/project/3rd-source/android_sdk" \
../..
# Build it
make -j${N_JOBS}
# Install it
make install/strip
### Remove temp build folder
cd "${WD}"
rm -rf "${temp_build_dir}"
echo "end building ${ANDROID_ABI} version"
done
运行
cd opencv
chmod u+x build.sh
./build.sh