opencv交叉编译android库

本文详细记录了解决在Android Studio中使用OpenCV遇到的编译问题,特别是关于imwrite函数链接错误的解决方案。问题根源在于STL库的选择,通过调整编译配置,从gnustl_static改为c++_shared,最终成功编译。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在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来编译(经过多次编译实验成功了)
首先,在网上查相关资料:

  1. opencv3及以下的版本仅仅支持gnustl_shared编译
  2. 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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值