“编译库就像烹饪美食一样。有时候我们只想要一个简略的番茄酱,而不是五花八门的酱料。” —— 某位聪明的程序员

在这篇博客中,我们将一起评论怎样为您的Android项目编译OpenCV 4.1.0版别。究竟,谁不喜爱一碗美味的意大利面(代码)配上简略的番茄酱(库)呢?

在开始之前,我们需求确保现已安装了以下东西和库:

  1. Android NDK(我们将运用20.0.5594570版别)
  2. OpenCV 4.1.0源代码
  3. CMake(我们将运用3.26.3版别)
  4. Ninja构建系统
  5. 硬件环境Macbook Pro m1 Pro

准备好了吗?那么让我们开始吧!

第一步:下载OpenCV 4.1.0源代码

获取源代码: 从OpenCV的GitHub库房克隆4.1.0版别的代码:

git clone https://github.com/opencv/opencv.git
cd opencv
git checkout 4.1.0

第二步:创建构建目录

为了坚持源代码目录的整洁,我们将在opencv-4.1.0目录周围创建一个名为build_android的构建目录。这个目录将存放我们编译生成的文件。

第三步:编译OpenCV库

现在,我们需求编译OpenCV库。首先,我们将为armeabi-v7aarm64-v8aABI创建独自的构建目录。为了使这个进程更简略,我们将运用以下指令:

mkdir build_android_armv7
mkdir build_android_arm64

接下来,我们将运用CMake和Ninja东西为不同的ABI构建OpenCV库。让我们首先为armeabi-v7a构建库:

# 切换到创建的armeabi-v7a构建目录
cd build_android_armv7
# 运转CMake指令以生成构建文件,指定以下选项:
# -DCMAKE_TOOLCHAIN_FILE: 指定Android NDK的toolchain文件途径
# -DANDROID_ABI: 设置政策Android ABI(本例中为armeabi-v7a)
# -DANDROID_PLATFORM: 设置政策Android平台版别(本例中为android-21)
# -DANDROID_STL: 设置C++规范库类型(本例中为c++_static)
# -DANDROID_NATIVE_API_LEVEL: 设置Android Native API等级(本例中为21)
# -DBUILD_SHARED_LIBS: 是否构建共享库(本例中为ON)
# -DBUILD_EXAMPLES: 是否构建示例(本例中为OFF)
# -DBUILD_DOCS: 是否构建文档(本例中为OFF)
# -DBUILD_PERF_TESTS: 是否构建功用检验(本例中为OFF)
# -DBUILD_TESTS: 是否构建检验(本例中为OFF)
# -DBUILD_ANDROID_EXAMPLES: 是否构建Android示例(本例中为OFF)
# -DBUILD_LIST: 设置要构建的模块列表
# -GNinja: 运用Ninja作为构建系统
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=armeabi-v7a \
      -DANDROID_PLATFORM=android-21 \
      -DANDROID_STL=c++_static \
      -DANDROID_NATIVE_API_LEVEL=21 \
      -DBUILD_SHARED_LIBS=ON \
      -DBUILD_EXAMPLES=OFF \
      -DBUILD_DOCS=OFF \
      -DBUILD_PERF_TESTS=OFF \
      -DBUILD_TESTS=OFF \
      -DBUILD_ANDROID_EXAMPLES=OFF \
      -DBUILD_LIST=core,imgproc,imgcodecs,videoio,highgui,objdetect \
      -GNinja \
      ../

假设需求构建一切模块,删掉-DBUILD_LIST这一行即可

现在我们现已生成了构建文件,接下来我们将运用Ninja来实践构建库:

# 运用Ninja进行构建
ninja

在构建完成后,我们会得到针对armeabi-v7a ABI的OpenCV库。同样的进程也可以使用于arm64-v8a ABI,只需将-DANDROID_ABI选项更改为arm64-v8a并进入build_android_arm64目录即可:

# 切换到创建的arm64-v8a构建目录
cd ../build_android_arm64
# 运转CMake指令以生成构建文件,指定以下选项(与前面的指令类似,但将ANDROID_ABI更改为arm64-v8a)
cmake -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \
      -DANDROID_ABI=arm64-v8a \
      -DANDROID_PLATFORM=android-21 \
      -DANDROID_STL=c++_static \
      -DANDROID_NATIVE_API_LEVEL=21 \
      -DBUILD_SHARED_LIBS=ON \
      -DBUILD_EXAMPLES=OFF \
      -DBUILD_DOCS=OFF \
      -DBUILD_PERF_TESTS=OFF \
      -DBUILD_TESTS=OFF \
      -DBUILD_ANDROID_EXAMPLES=OFF \
      -DBUILD_LIST=core,imgproc,imgcodecs,videoio,highgui,objdetect \
      -GNinja \
      ../
# 运用Ninja进行构建
ninja

经过这些进程,您现已成功编译了针对armeabi-v7aarm64-v8a ABI的OpenCV库。接下来,我们将持续将这些库整合到您的Android项目中。

下图为我编译好的so文件。

好戏演出:为Android项目编译OpenCV 4.1.0,可按需编译模块,大大削减空间。

看到这儿或许有人要问,我制定了六个模块,为什么生成了九个so文件? 关于OpenCV,某些模块会依托于其他模块。因而,在构建特定模块时,其依托项也会被构建。在指定的六个模块中,有些模块依托于其他模块,这就是为什么看到了多于六个的.so文件的原因。

生成的.so文件列表及其或许的依托联系:

  • libopencv_core.so(中心模块,简直一切其他模块都依托于此模块)
  • libopencv_objdetect.so(依托于coreimgproccalib3dfeatures2dhighguiimgcodecsflann等)
  • libopencv_calib3d.so(依托于coreimgprocfeatures2d等)
  • libopencv_features2d.so(依托于coreimgprocflann等)
  • libopencv_highgui.so(依托于coreimgcodecsvideoio等)
  • libopencv_videoio.so(依托于coreimgcodecs等)
  • libopencv_imgcodecs.so(依托于coreimgproc等)
  • libopencv_imgproc.so(依托于core
  • libopencv_flann.so(依托于core

即便你仅指定了六个模块,但由于它们的依托联系,仍是生成了其他模块的.so文件。在实践使用中,这些依托联系或许是必要的。

第五步:将编译好的库整合到Android项目中

现在我们现已为两种不同的ABI编译了OpenCV库,接下来我们需求将这些库整合到您的Android项目中。为了简化这个进程,请遵从以下进程:

  1. build_android_armv7build_android_arm64目录中的lib文件夹复制到您的Android项目的jniLibs目录中。假设jniLibs目录尚不存在,请创建它。您的项目结构应该如下所示:
your-android-project
│
└───app
    └───src
        └───main
            └───jniLibs
                ├───armeabi-v7a
                │   └───libopencv_*.so
                └───arm64-v8a
                    └───libopencv_*.so
  1. 将OpenCV库的头文件也复制到项目中。您可以将opencv-4.1.0/include目录复制到项目的cpp目录下(假设尚不存在,请创建它)。您的项目结构应该如下所示:
your-android-project
│
└───app
    └───src
        └───main
            ├───cpp
            │   └───include
            │       └───opencv2
            └───jniLibs
                ├───armeabi-v7a
                │   └───libopencv_*.so
                └───arm64-v8a
                    └───libopencv_*.so
  1. 在您的项目中运用OpenCV库。首先,在您的项目的CMakeLists.txt文件中,添加以下内容:
# 添加OpenCV头文件途径
include_directories(${CMAKE_SOURCE_DIR}/cpp/include)
# 链接OpenCV库
function(add_opencv_lib LIB_NAME)
    add_library(${LIB_NAME} SHARED IMPORTED)
    set_target_properties(${LIB_NAME} PROPERTIES
                          IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/jniLibs/${ANDROID_ABI}/${LIB_NAME}.so)
    target_link_libraries(your_target_name ${LIB_NAME})
endfunction()
add_opencv_lib(libopencv_core)
add_opencv_lib(libopencv_imgproc)
add_opencv_lib(libopencv_imgcodecs)
add_opencv_lib(libopencv_videoio)
add_opencv_lib(libopencv_highgui)
add_opencv_lib(libopencv_objdetect)

记住将your_target_name替换为您项目中CMakeLists.txt中的政策名称。

现在,您已成功将编译好的OpenCV库整合到了您的Android项目中。您可以在项目中运用OpenCV供应的各种功用了。

结束语

在这篇博客文章中,我们具体介绍了怎样为Android项目编译OpenCV 4.1.0库的整个进程。我们了解了怎样运用CMake和Ninja构建东西为不同的ABI生成库文件,以及怎样将这些库整合到您的Android项目中。

希望这篇文章能对您有所帮忙。现在,您可以好好享受那碗美味的意大利面(代码)和番茄酱(库)了!假设您在编译进程中遇到任何问题,请在谈论区留言,我们将尽力供应帮忙。祝您编程愉快