“编译库就像烹饪美食一样。有时候我们只想要一个简单的番茄酱,而不是五花八门的酱料。” —— 某位聪明的程序员
在这篇博客中,我们将一起探讨如何为您的Android项目编译OpenCV 4.1.0版本。毕竟,谁不喜欢一碗美味的意大利面(代码)配上简单的番茄酱(库)呢?
在开始之前,我们需要确保已经安装了以下工具和库:
- Android NDK(我们将使用20.0.5594570版本)
- OpenCV 4.1.0源代码
- CMake(我们将使用3.26.3版本)
- Ninja构建系统
- 硬件环境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-v7a和arm64-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-v7a和arm64-v8a ABI的OpenCV库。接下来,我们将继续将这些库整合到您的Android项目中。
下图为我编译好的so文件。
看到这里可能有人要问,我制定了六个模块,为什么生成了九个so文件?
对于OpenCV,某些模块会依赖于其他模块。因此,在构建特定模块时,其依赖项也会被构建。在指定的六个模块中,有些模块依赖于其他模块,这就是为什么看到了多于六个的.so文件的原因。
生成的.so文件列表及其可能的依赖关系:
libopencv_core.so(核心模块,几乎所有其他模块都依赖于此模块)libopencv_objdetect.so(依赖于core、imgproc、calib3d、features2d、highgui、imgcodecs、flann等)libopencv_calib3d.so(依赖于core、imgproc、features2d等)libopencv_features2d.so(依赖于core、imgproc、flann等)libopencv_highgui.so(依赖于core、imgcodecs、videoio等)libopencv_videoio.so(依赖于core、imgcodecs等)libopencv_imgcodecs.so(依赖于core、imgproc等)libopencv_imgproc.so(依赖于core)libopencv_flann.so(依赖于core)
即使你仅指定了六个模块,但由于它们的依赖关系,还是生成了其他模块的.so文件。在实际应用中,这些依赖关系可能是必要的。
第五步:将编译好的库整合到Android项目中
现在我们已经为两种不同的ABI编译了OpenCV库,接下来我们需要将这些库整合到您的Android项目中。为了简化这个过程,请遵循以下步骤:
- 将
build_android_armv7和build_android_arm64目录中的lib文件夹复制到您的Android项目的jniLibs目录中。如果jniLibs目录尚不存在,请创建它。您的项目结构应该如下所示:
your-android-project
│
└───app
└───src
└───main
└───jniLibs
├───armeabi-v7a
│ └───libopencv_*.so
└───arm64-v8a
└───libopencv_*.so
- 将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
- 在您的项目中使用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项目中。
希望这篇文章能对您有所帮助。现在,您可以好好享受那碗美味的意大利面(代码)和番茄酱(库)了!如果您在编译过程中遇到任何问题,请在评论区留言,我们将尽力提供帮助。祝您编程愉快