树莓派编译构建 OpenCV C++ 项目

OpenCV 是流行的计算机视觉库。 最近因项目需要,要在树莓派上编译构建 OpenCV C++ 项目。踩了不少坑,分享出来。

编译 OpenCV 源码

OpenCV 目前的最新版本是 4.5.1,但项目使用版本 3.4.12。

在树莓派 Home 目录下,新建 opencv-project 文件夹

cd ~
mkdir opencv-project

下载 3.4.12 版本 opencv 源码,然后解压到当前目录

cd opencv-project
wget https://github.com/opencv/opencv/archive/3.4.12.tar.gz
tar xvzf 3.4.12.tar.gz

注:OpenCV 的所有版本可以从 Releases · opencv/opencv 找到

进入解压后的 opencv 源码目录,新建 _build、_output 两个目录(_build 用于暂存编译中间产物,_output 用于存放编译结果)

cd opencv-3.4.12
mkdir \_build \_output

进入 _build 目录,执行 cmake 以生成 makefile 文件

cmake -DCMAKE_BUILD_TYPE=RELEASE -DCMAKE_INSTALL_PREFIX=/home/pi/opencv-project/opencv-3.4.12/\_output  ..

-D 是 cmake 的构建参数。CMAKE_BUILD_TYPE=RELEASE 表示构建成正式版(还有一个取值是 DEBUG,表示构建成调试版,产物里会添加调试代码);CMAKE_INSTALL_PREFIX 是构建产物安装目录,这里指定到上一步的 _output 目录,方便获取所有构建产物。最后的 .. 指向 OpenCV 源码路径,也就是 _build 目录的上一层。

cmake 执行完后,会在 _build 目录下生成一系列的缓存文件和 Makefile 文件。

还在 _build 目录下,执行 make -j4,开始编译 OpenCV 源码。-j4 表示并发执行 4 个编译任务,一般有几个 CPU 核心就指定几个并发任务。

等到进度走到 100% 的时候,就表示编译结束。

继续执行 make install。执行完成后,构建产物即输出到 _output 目录。

bin 目录里是一些 OpenCV 自带的可执行程序,一般用不到。include 目录里是 C++ 头文件。lib 目录里是编译出来的 OpenCV 动态链接库。share 目录里是一些文档和模型文件。

编译 OpenCV 应用程序示例

上一步,我们已经得到了 OpenCV 最重要的头文件和动态链接库。这里用一个简单的“打开图片”的示例来说明如何基于这些头文件的库,编译一个 OpenCV 应用程序。

新建 display-a-pic 目录,然后在这个文件夹下新建 main.cpp 文件

#include <opencv2/opencv.hpp>

int main(int argc, char \*\*argv)
{
  cv::Mat img = cv::imread(argv[1], -1);

if (img.empty()) return -1;

cv::namedWindow("Example1", cv::WINDOW_AUTOSIZE);
  cv::imshow("Example1", img);
  cv::waitKey(0);
  cv::destroyWindow("Example1");

return 0;
}

注:cv:: 是 OpenCV 的命名空间

cv::imread 从指定路径读取图片,并赋值给 cv::Mat imgcv::namedWindow 打开一个视窗,cv::imshow 在视窗中显示图片。cv::waitKey 等待按键事件,0 表示任意按键都会退出等待。cv::destroyWindow 销毁视窗。

接着在当前目录下新建 CMake 配置文件 CMakeLists.txt:

# CMake 最低版本号要求
cmake_minimum_required(VERSION 3.10.2)

project(demo)

set(OpenCV_DIR "/home/concefly/Project/opencv-exp/opencv-3.4.12/\_output/share/OpenCV")

find_package( OpenCV REQUIRED )

message("WARNING" "OpenCV_INCLUDE_DIRS:" ${OpenCV_INCLUDE_DIRS})
message("WARNING" "OpenCV_LIBS:" ${OpenCV_LIBS})

include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(demo main.cpp)
target_link_libraries(demo ${OpenCV_LIBS})

由于上一节将 OpenCV 编译生成至了 _output 目录,所以必须要在编译 main.cpp 的时候指定 OpenCV 库路径,也就是 set(OpenCV_DIR "/home/concefly/Project/opencv-exp/opencv-3.4.12/\_output/share/OpenCV")

find_package( OpenCV REQUIRED ) 这一步执行完后,会设置 OpenCV_INCLUDE_DIRS 和 OpenCV_LIBS 两个全局变量,分别表示头文件路径和动态链接库路径。这时需要调用 include_directories 和 target_link_libraries 把它们加入到编译参数里。

add_executable(demo main.cpp) 则指示把 main.cpp 编译成 demo 可执行文件。

此时在当前目录下执行:

cmake . && make

则得到了文件名为 demo 的可执行文件。

执行 ./demo a.jpg,就可以看到 OpenCV 打开的图片展示窗口了。

当然这只是个 demo 演示,用于展示 OpenCV 编译和构建应用程序的一些环节,真正的项目会比这复杂的多,但基本原理是相通的。