1. 项目概述:为什么要在Ubuntu 18.04上折腾C++版OpenCV4?
如果你正在看这篇文章,大概率是刚接触计算机视觉,或者需要在Linux环境下部署一个稳定的视觉项目。Ubuntu 18.04 LTS(长期支持版)是一个经典且稳定的选择,很多工业项目和学术环境至今仍在使用它。而OpenCV作为计算机视觉领域的“瑞士军刀”,其C++接口在性能和控制力上有着Python接口无法比拟的优势,尤其是在处理实时视频流、部署到嵌入式设备或对算法延迟有严苛要求的场景下。
然而,在Ubuntu上从源码编译安装C++版的OpenCV4,对于新手来说,绝对是个“劝退级”的挑战。你可能会遇到依赖库缺失、CMake配置报错、版本冲突、编译失败等一系列问题。网上的教程五花八门,有的过于简略跳过了关键步骤,有的又因为系统环境差异而无法复现。今天,我就以一个踩过无数坑的过来人身份,带你手把手、无死角地完成在Ubuntu 18.04上编译安装OpenCV4(C++接口)的全过程。我们不仅要把流程走通,更要理解每一个步骤背后的“为什么”,确保你下次遇到问题能自己排查。
2. 环境准备与依赖库的“全家桶”安装
编译OpenCV就像盖房子,依赖库就是地基和砖瓦。缺了任何一块,房子都盖不起来,或者盖起来也不稳。Ubuntu 18.04自带的软件源版本比较老,我们需要先更新,然后安装一整套编译工具和图像/视频处理库。
2.1 系统更新与基础编译工具链
首先,打开终端,执行以下命令更新软件包列表并升级现有软件。这一步能确保我们从一个比较新的起点开始,减少因系统组件过旧导致的兼容性问题。
sudo apt update sudo apt upgrade -y接下来,安装最核心的编译工具。build-essential是一个元数据包,它会自动安装GCC、G++、make等C/C++编译的核心工具。没有它,后续的CMake配置和源码编译都无法进行。
sudo apt install -y build-essential2.2 CMake的版本抉择与安装
OpenCV使用CMake作为其构建系统。Ubuntu 18.04默认仓库里的CMake版本(3.10.x)对于OpenCV4来说太老了,可能会导致一些新特性无法启用或编译错误。因此,我们需要安装一个较新版本的CMake。这里我推荐安装CMake 3.16.3,这是一个在稳定性和功能上比较平衡的版本,与OpenCV4兼容性很好。
网络上有很多关于“如何将ubuntu中cmake降到3.16.3”的搜索,这恰恰说明了版本选择的重要性——不是越新越好,而是合适才好。我们通过官方Kitware仓库来安装:
# 卸载旧版本(如果存在) sudo apt remove --purge -y cmake # 添加Kitware的APT仓库并安装指定版本 wget -O - https://apt.kitware.com/keys/kitware-archive-latest.asc 2>/dev/null | gpg --dearmor - | sudo tee /etc/apt/trusted.gpg.d/kitware.gpg >/dev/null sudo apt-add-repository 'deb https://apt.kitware.com/ubuntu/ bionic main' sudo apt update sudo apt install -y cmake=3.16.3-0kitware1ubuntu18.04.1安装完成后,使用cmake --version验证,应该显示版本为3.16.3。
注意:如果你后续还需要用CMake编译其他项目,这个版本是足够通用的。如果遇到特定项目要求更高版本,可以届时再考虑升级,但OpenCV4用3.16.3是经过大量实践验证的稳定组合。
2.3 安装OpenCV核心依赖库
OpenCV的功能模块众多,每个模块都依赖特定的第三方库。以下命令会安装图像编解码、视频I/O、图形界面、优化计算等核心依赖。请务必一次性安装,避免反复查找缺失的库。
sudo apt install -y \ pkg-config \ libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \ libxvidcore-dev libx264-dev \ libjpeg-dev libpng-dev libtiff-dev \ libgtk-3-dev \ libatlas-base-dev gfortran \ libtbb2 libtbb-dev \ libdc1394-22-dev \ libopenexr-dev \ libgstreamer-plugins-base1.0-dev libgstreamer1.0-dev关键依赖解析:
- libjpeg-dev, libpng-dev, libtiff-dev:用于读取和写入JPEG、PNG、TIFF等常见图像格式。
- libavcodec-dev, libavformat-dev:FFmpeg的组件,让OpenCV能够读写几乎所有的视频文件格式(如MP4、AVI)和从摄像头捕获视频流。
- libgtk-3-dev:提供HighGUI模块的图形界面支持(如
imshow函数显示的窗口)。如果你只在服务器无图形界面环境下使用,可以改为安装libgtk2.0-dev或不装(通过CMake关闭GUI),但通常建议装上以备不时之需。 - libtbb-dev:Intel Threading Building Blocks,用于提供多线程并行优化,能显著提升OpenCV在多核CPU上的性能。
- libatlas-base-dev, gfortran:为OpenCV的线性代数运算核心提供优化。ATLAS是一个优化的BLAS/LAPACK库,比默认的实现更快。
3. 源码获取与CMake配置的艺术
依赖装好了,接下来就是获取源码并进行“裁剪”,即通过CMake配置,决定编译哪些功能,链接哪些库。
3.1 下载OpenCV与OpenCV Contrib源码
OpenCV的主仓库包含了稳定、核心的模块。而OpenCV Contrib仓库则包含了许多前沿、实验性或专利保护的模块,如人脸识别、文本检测、深度神经网络等。为了获得完整的功能,我们通常两者都编译。
选择一个有足够空间(建议至少预留5-6GB)的目录,执行:
# 创建工作目录并进入 mkdir ~/opencv_build && cd ~/opencv_build # 克隆OpenCV主仓库(这里我们选择4.5.5这个稳定版本) wget -O opencv.zip https://github.com/opencv/opencv/archive/4.5.5.zip unzip opencv.zip # 克隆OpenCV Contrib仓库(版本必须与主仓库对应) wget -O opencv_contrib.zip https://github.com/opencv/opencv_contrib/archive/4.5.5.zip unzip opencv_contrib.zip使用wget下载zip包并解压,比直接用git clone整个历史记录要快,也节省空间。解压后,你会得到opencv-4.5.5和opencv_contrib-4.5.5两个文件夹。
3.2 CMake配置:关键参数详解
这是整个安装过程中最核心、最容易出错的一步。CMake配置决定了最终编译出的OpenCV库包含哪些功能,性能如何,以及如何与你的系统集成。
首先,在opencv-4.5.5目录下创建一个构建目录,并进入:
cd ~/opencv_build/opencv-4.5.5 mkdir build && cd build然后,执行CMake命令。下面是一个经过优化的配置命令,我逐条解释其含义:
cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D INSTALL_C_EXAMPLES=OFF \ -D INSTALL_PYTHON_EXAMPLES=OFF \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D OPENCV_EXTRA_MODULES_PATH=~/opencv_build/opencv_contrib-4.5.5/modules \ -D BUILD_EXAMPLES=OFF \ -D WITH_TBB=ON \ -D WITH_V4L=ON \ -D WITH_QT=OFF \ -D WITH_GTK=ON \ -D WITH_OPENGL=ON \ -D WITH_FFMPEG=ON \ -D ENABLE_CXX11=ON \ -D BUILD_opencv_python2=OFF \ -D BUILD_opencv_python3=OFF \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_DOCS=OFF \ -D BUILD_opencv_java=OFF \ -D BUILD_SHARED_LIBS=ON \ -D OPENCV_ENABLE_NONFREE=OFF ..核心参数解析:
-D CMAKE_BUILD_TYPE=RELEASE:编译为发布版本,编译器会进行最高级别的优化(如-O3),移除调试信息,生成的库文件更小、运行更快。如果是开发调试,可改为DEBUG。-D CMAKE_INSTALL_PREFIX=/usr/local:指定安装路径。/usr/local是Linux系统存放本地安装软件的标准路径,其下的lib和include目录会被编译器默认搜索。-D OPENCV_GENERATE_PKGCONFIG=ON:极其重要!这个选项会生成一个opencv4.pc文件。pkg-config是一个帮助你在编译时自动添加正确头文件路径和链接库参数的工具。打开它,后续你自己写C++项目链接OpenCV时会轻松百倍。-D OPENCV_EXTRA_MODULES_PATH:指定Contrib模块的路径。这样CMake就会把Contrib里的模块也纳入编译范围。-D WITH_TBB=ON:启用前面安装的Intel TBB库进行并行优化。-D WITH_FFMPEG=ON:启用FFmpeg支持,用于视频编解码。确保之前已安装相关dev包。-D BUILD_opencv_python3=OFF:我们只安装C++版本,所以关闭Python绑定编译,可以大幅缩短编译时间。如果你也需要Python接口,可以打开,但需要提前配置好Python3的开发环境。-D BUILD_SHARED_LIBS=ON:编译为动态链接库(.so文件)。这样多个程序可以共享内存中的同一份库代码,节省空间。如果希望编译成静态库(.a文件)以便于程序分发,可以设为OFF,但静态链接会使你的可执行文件体积巨大。-D OPENCV_ENABLE_NONFREE=OFF:是否启用包含专利算法的模块(如SIFT、SURF)。出于专利和法律风险考虑,默认关闭。如果你确定需要在学术研究中使用,可以设为ON,但请注意合规性。
执行完CMake命令后,终端会输出大量信息。请务必滚动检查最后部分,确保没有红色的“NOT FOUND”错误。重点关注FFmpeg、GTK、TBB等关键依赖是否被正确找到。输出结尾应该类似这样:
-- Configuring done -- Generating done -- Build files have been written to: /home/yourname/opencv_build/opencv-4.5.5/build4. 编译与安装:耐心与资源的博弈
配置成功后,build目录下会生成Makefile。接下来就是漫长的编译过程,耗时取决于你的CPU核心数和性能,通常在30分钟到2小时不等。
4.1 启动编译进程
使用make命令开始编译,-j参数后面跟的数字表示并行编译的作业数,一般设置为你的CPU逻辑核心数,可以最大化利用CPU资源,显著加快编译速度。你可以用nproc命令查看核心数。
# 使用所有可用的CPU核心进行编译 make -j$(nproc)编译过程中,终端会持续滚动输出信息。如果遇到错误而停止,最常见的错误是:
- 内存不足:编译OpenCV非常消耗内存,尤其是链接阶段。如果内存小于4GB,建议减少
-j后的数字,比如make -j2,甚至直接make(单线程)。 - 依赖缺失:如果出现某个头文件找不到或某个函数未定义的错误,通常是对应的
-dev开发包没有安装。你需要根据错误信息,回头去安装对应的依赖库。
4.2 安装与系统集成
编译成功后(看到100%完成),就可以安装了。安装命令会将编译好的库文件、头文件等复制到之前CMAKE_INSTALL_PREFIX指定的路径(这里是/usr/local)。
sudo make install安装完成后,需要更新系统的动态链接库缓存,让系统立刻知道新库的存在。
sudo ldconfig4.3 验证pkg-config配置
之前我们打开了OPENCV_GENERATE_PKGCONFIG,现在来验证它是否工作。查询OpenCV4的编译参数:
pkg-config --cflags --libs opencv4如果配置正确,你会看到一长串输出,包含了-I/usr/local/include/opencv4这样的头文件路径和-lopencv_core -lopencv_imgproc ...这样的链接库列表。这个命令的输出,正是你后续在自己C++项目中编译时需要添加的参数。
5. 测试安装:从“Hello World”到图像处理
理论千万遍,不如跑一遍。我们来创建两个测试程序验证安装是否成功。
5.1 基础测试:读取并显示一张图片
首先,找一个测试图片(比如test.jpg)放到你的工作目录。然后创建一个test_display.cpp文件:
#include <opencv2/opencv.hpp> #include <iostream> int main() { // 读取图片 cv::Mat image = cv::imread("test.jpg"); // 检查图片是否成功加载 if(image.empty()) { std::cout << "Could not open or find the image!" << std::endl; return -1; } // 创建一个窗口并显示图片 cv::namedWindow("Display Window", cv::WINDOW_AUTOSIZE); cv::imshow("Display Window", image); // 等待按键,否则窗口会一闪而过 cv::waitKey(0); return 0; }使用以下命令编译它。注意,这里直接使用了pkg-config的输出作为编译参数,这是最规范的方式。
g++ test_display.cpp -o test_display `pkg-config --cflags --libs opencv4`运行程序:
./test_display如果弹出一个窗口并显示了你的测试图片,那么恭喜你,OpenCV C++环境基本配置成功!
5.2 进阶测试:摄像头捕获与边缘检测
为了测试更复杂的功能(视频I/O和图像处理),我们写一个从摄像头实时读取视频并进行Canny边缘检测的程序。
#include <opencv2/opencv.hpp> int main() { // 打开默认摄像头(索引为0) cv::VideoCapture cap(0); if(!cap.isOpened()) { std::cerr << "Error: Cannot open the camera!" << std::endl; return -1; } cv::Mat frame, edges; while(true) { cap >> frame; // 从摄像头捕获一帧 if(frame.empty()) break; // 转换为灰度图 cv::cvtColor(frame, edges, cv::COLOR_BGR2GRAY); // 应用高斯模糊降噪 cv::GaussianBlur(edges, edges, cv::Size(7,7), 1.5, 1.5); // 进行Canny边缘检测 cv::Canny(edges, edges, 0, 30, 3); // 显示原图和边缘检测结果 cv::imshow("Original", frame); cv::imshow("Canny Edges", edges); // 按ESC键退出 char c = (char)cv::waitKey(30); if(c == 27) break; } cap.release(); cv::destroyAllWindows(); return 0; }同样方式编译运行:
g++ test_camera.cpp -o test_camera `pkg-config --cflags --libs opencv4` ./test_camera如果能看到两个窗口,一个显示摄像头原始画面,一个显示实时边缘检测效果,那么视频捕获和核心图像处理模块都工作正常。
6. 集成开发环境(IDE)配置指南
在终端里用g++编译小项目没问题,但开发大型项目时,一个好用的IDE至关重要。这里以最流行的VSCode为例。
6.1 VSCode C++开发环境搭建
首先,确保已安装VSCode和C/C++扩展(Microsoft官方发布)。然后,关键是为你的项目配置c_cpp_properties.json文件,让VSCode的智能感知(IntelliSense)能找到OpenCV的头文件。
在你的项目根目录下创建.vscode文件夹,并在其中创建c_cpp_properties.json:
{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/usr/local/include/opencv4", // OpenCV头文件路径 "/usr/include" // 系统头文件路径 ], "defines": [], "compilerPath": "/usr/bin/g++", "cStandard": "c11", "cppStandard": "c++11", "intelliSenseMode": "linux-gcc-x64", "configurationProvider": "ms-vscode.cmake-tools" // 如果使用CMake Tools扩展 } ], "version": 4 }6.2 使用CMake管理项目(推荐)
对于C++项目,直接使用CMake管理是最专业的方式。在你的项目根目录创建CMakeLists.txt:
cmake_minimum_required(VERSION 3.10) project(YourOpenCVProject) # 设置C++标准 set(CMAKE_CXX_STANDARD 11) # 查找OpenCV包,REQUIRED表示必须找到 find_package(OpenCV REQUIRED) # 添加头文件目录 include_directories(${OpenCV_INCLUDE_DIRS}) # 添加可执行文件 add_executable(test_display test_display.cpp) # 链接OpenCV库 target_link_libraries(test_display ${OpenCV_LIBS})在VSCode中安装“CMake Tools”扩展。打开包含CMakeLists.txt的文件夹,VSCode会自动检测并提示你配置。选择“GCC”作为工具链,然后配置(Configure)和构建(Build)即可。这种方式完全避免了手动输入复杂的g++命令,并且可以方便地管理多文件项目。
7. 疑难杂症与深度排错指南
即使按照步骤操作,你也可能遇到问题。这里汇总了常见错误及其解决方案。
7.1 编译阶段错误
错误1:fatal error: opencv2/opencv.hpp: No such file or directory
- 原因:编译器找不到OpenCV头文件。
- 解决:
- 确保已成功执行
sudo make install。 - 检查头文件是否在
/usr/local/include/opencv4下。如果不在,检查CMake的CMAKE_INSTALL_PREFIX设置。 - 编译时,使用
`pkg-config --cflags opencv4`来获取正确的-I参数,或者确保你的CMakeLists.txt正确使用了find_package(OpenCV)。
- 确保已成功执行
错误2:undefined reference tocv::imread(...)... collect2: error: ld returned 1 exit status
- 原因:链接器找不到OpenCV的库文件,即链接错误。
- 解决:
- 确保编译命令中包含了
`pkg-config --libs opencv4`的输出。 - 运行
sudo ldconfig更新库缓存。 - 检查
/usr/local/lib目录下是否存在libopencv_*.so文件。
- 确保编译命令中包含了
错误3:CMake配置时大量依赖显示NO,特别是FFmpeg相关。
- 原因:对应的开发包未安装,或者系统存在多个版本冲突。
- 解决:根据CMake输出提示,安装缺失的
-dev包。对于FFmpeg,Ubuntu 18.04可能需要添加universe仓库:sudo add-apt-repository universe && sudo apt update,然后重新安装libavcodec-dev等包。
错误4:编译过程中内存不足(被kill),尤其是在链接阶段。
- 原因:并行编译作业数太多,内存耗尽。
- 解决:
- 减少
make -j后面的数字,例如make -j2或直接make(单线程)。 - 如果物理内存小,可以尝试增加交换空间(Swap)。
- 在CMake配置时,可以尝试关闭一些不急需的模块(如
-D BUILD_opencv_world=OFF),但这不是根本解决办法。
- 减少
7.2 运行阶段错误
错误1:运行程序时提示error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file: No such file or directory
- 原因:系统动态链接器找不到新安装的库。
- 解决:
- 执行
sudo ldconfig刷新缓存。 - 如果还不行,检查
/etc/ld.so.conf或/etc/ld.so.conf.d/下的文件,确保包含了/usr/local/lib。可以创建一个新文件/etc/ld.so.conf.d/opencv.conf,内容为/usr/local/lib,然后再次运行sudo ldconfig。
- 执行
错误2:摄像头测试程序无法打开摄像头(cap.isOpened()返回false)。
- 原因:权限问题或驱动问题。
- 解决:
- 将当前用户加入
video组:sudo usermod -a -G video $USER,然后注销并重新登录生效。 - 尝试使用V4L2后端:在代码中
cv::VideoCapture cap(0, cv::CAP_V4L2);。 - 检查是否有其他程序占用了摄像头。
- 将当前用户加入
7.3 性能与优化问题
问题:程序运行感觉卡顿,CPU占用高。
- 排查:
- 检查编译类型:确认CMake时使用的是
-D CMAKE_BUILD_TYPE=RELEASE,而不是DEBUG。Release版本有大量优化。 - 启用并行化:确保CMake中
WITH_TBB=ON,并且在代码中对循环等操作考虑使用OpenCV的并行框架。 - 检查算法:像
cv::Canny这样的函数本身计算量较大。对于实时视频,可以尝试降低处理帧率或图像分辨率。 - 硬件加速:如果你的CPU支持AVX2等指令集,可以在CMake时尝试添加
-D CPU_BASELINE=AVX2来启用,但需注意兼容性(这就是网络热词中“cmake avx2 failed”可能遇到的问题,如果编译失败,则移除该选项)。
- 检查编译类型:确认CMake时使用的是
8. 项目维护与进阶路线
成功安装只是第一步。要让OpenCV在你的项目中稳定、高效地工作,还需要一些维护技巧和进阶知识。
8.1 多版本管理与切换
你的系统里可能未来需要安装不同版本的OpenCV。强烈不建议直接覆盖安装。更优雅的做法是:
- 自定义安装路径:编译时通过
-D CMAKE_INSTALL_PREFIX=/opt/opencv-4.5.5安装到独立目录。 - 环境变量控制:通过设置
PKG_CONFIG_PATH、LD_LIBRARY_PATH和CPLUS_INCLUDE_PATH来切换不同版本。# 临时切换到自定义路径的OpenCV export PKG_CONFIG_PATH=/opt/opencv-4.5.5/lib/pkgconfig:$PKG_CONFIG_PATH export LD_LIBRARY_PATH=/opt/opencv-4.5.5/lib:$LD_LIBRARY_PATH - CMake优先查找:在你的项目CMakeLists.txt中,使用
set(OpenCV_DIR /opt/opencv-4.5.5/lib/cmake/opencv4)来强制指定查找路径。
8.2 精简安装与定制编译
如果你的应用场景明确,不需要所有功能,可以在CMake阶段关闭大量模块以大幅缩短编译时间、减少库体积。例如,一个只做图像处理的服务器应用,可以关闭:
-D WITH_GTK=OFF(无GUI)-D WITH_FFMPEG=OFF(无需视频)-D BUILD_opencv_videoio=OFF-D BUILD_opencv_highgui=OFF- 在CMake GUI或终端交互模式中,搜索
BUILD_opencv_和WITH_开头的选项,将其不需要的设为OFF。
8.3 从源码安装的深层次价值
也许你会问,为什么不用sudo apt install libopencv-dev?那个方法确实简单,但存在巨大局限:
- 版本老旧:Ubuntu 18.04仓库中的OpenCV版本是3.2,缺少DNN模块等大量4.x版本的新特性。
- 功能残缺:不包含Contrib模块,很多先进的算法无法使用。
- 无法定制:不能选择开启或关闭特定功能,无法进行针对性的优化。
从源码编译虽然过程繁琐,但它给了你完全的控制权。你可以在编译时针对你的CPU指令集(如SSE4.2, AVX2)进行优化,可以精确选择需要的模块,可以集成最新的补丁和Contrib算法。这对于追求极致性能或需要特定功能的项目来说,是唯一的选择。
整个流程走下来,你应该已经拥有了一个完全受控、功能完备的OpenCV 4.5.5 C++开发环境。记住,在Linux下从源码构建大型库是开发者的一项基本技能,这次经历积累的经验和解决问题的思路,在你未来面对其他类似软件(如PCL、ROS等)的安装时,会变得游刃有余。遇到问题别慌,仔细阅读错误信息,善用搜索引擎和社区,你遇到的坑,大概率前人都已经踩过并留下了解决方案。