搞过几年计算机视觉开发的人,对 Ubuntu 18.04 + OpenCV 4.5 这个组合应该不陌生。Opencv4.5 在 2020 年底发布,是 4.x 系列里综合体验比较舒服的版本:DNN 模块已经足够成熟,SIFT 等算法不需要再单独打补丁,编译配置也相对干净。这篇文章想分享的,不是网上那种复制粘贴的三行命令,而是一份我在不同机器上反复验证过的完整流程,包含依赖选型、CMake 参数含义、编译踩坑记录和安装后的验证方法。不管你是要给自己的视觉项目搭环境,还是正在配置相机雷达联合标定工具链,照着做基本都能顺利落地。
先交代一下我的习惯:OpenCV 4.5 我从不建议直接用 apt 或 pip 的预编译包,除非你只是临时跑个 demo。真正要用于项目开发、需要自己编译算法模块、接摄像头驱动、做 CUDA 加速或者深度集成的场景,源码编译反而更省心。这篇文章面向的是 Ubuntu 18.04 上需要认真使用 OpenCV 的开发者,包括正在折腾自动驾驶标定工具的同学,我会从零开始把每一步都拆开讲清楚。
1. 安装思路:源码编译还是包管理器
1.1 为什么我坚持源码编译
很多朋友第一次装 OpenCV,最先尝试的是pip install opencv-python或sudo apt install libopencv-dev。这两种方式确实省事,但对真正做项目的人来说,坑在后面。
先看 pip 版本。pip 装的是 pre-built wheel,优点是快,缺点是看不到编译选项。比如你后面做视频处理,可能需要 FFmpeg 后端、GStreamer 后端,或者想用 OpenCV 的 contrib 模块里的 ArUco、SIFT,pip 默认包往往是裁剪过的。更麻烦的是,pip 版 OpenCV 的cv2模块和系统里的库文件可能来自不同构建,一旦项目需要混合编译 C++ 和 Python,版本错位问题会让人一头雾水。
再看 apt 版本。Ubuntu 18.04 软件源里的 OpenCV 是 3.2 版本,和 4.5 的 API 有差异不说,很多新特性根本用不了。而且 apt 版 OpenCV 在编译时未必开启了全部优化,比如WITH_TBB、WITH_OPENMP这些性能开关,默认可能没打开。
所以我的建议很明确:如果你要长期做视觉开发,一步到位源码编译。虽然第一次编译需要二三十分钟,但编译出来的 OpenCV 完全可控,什么模块开启、什么功能关闭、装到什么路径,全在你自己手里。后面项目出了诡异问题,排查起来心里也有底。
1.2 版本选择和 4.5 带来的变化
选 4.5 而不是最新的 4.x 或 5.x,核心原因通常是项目依赖链。很多老项目是基于 18.04 搭的,比如相机激光雷达联合标定工具链里的部分底层库,对 OpenCV 版本敏感。4.5 正好处在一个平衡点:API 稳定,Python 接口齐全,DNN 模块支持主流模型格式,contrib 里的 ArUco、Barcode、文本检测等模块也很成熟。
相比更早的 4.1、4.2,OpenCV 4.5 有几个我实际用下来感知最明显的变化:
- SIFT、SURF 这些非自由算法不需要自己编译 xfeatures2d 补丁,contrib 模块直接集成,但需要在 CMake 里显式开启
OPENCV_ENABLE_NONFREE=ON。 - DNN 模块对 ONNX 模型的支持更完善,很多 PyTorch 导出的模型可以直接加载。
- 对 18.04 自带的 GCC 7.5 编译器兼容性极好,编译过程比新版 OpenCV 少很多编译错误。
opencv.pc等 pkg-config 文件支持更友好,配置 C++ 项目非常方便。
如果你刚接触 OpenCV,或者被很多“新版本教程”绕晕了,直接从 4.5 上手是稳妥的选择。
2. 环境准备:先把系统基础打好
2.1 更新系统与安装编译工具链
拿到一台干净的 Ubuntu 18.04,第一件事不是急着下载 OpenCV 源码,而是把系统的编译环境补全。很多人编译失败,根本不是 OpenCV 的问题,而是缺少基础依赖。
打开终端,先把软件源更新到最新状态:
sudo apt update sudo apt upgrade -y注意upgrade可能会改动内核包,如果是服务器环境建议谨慎,但一般开发机没什么问题。之后安装编译工具链:
sudo apt install -y build-essential cmake git pkg-configbuild-essential包含 GCC、G++、make,这是编译 C/C++ 代码的底子。cmake版本在 18.04 默认源里是 3.10.2,对 OpenCV 4.5 来说足够用。pkg-config后面检查安装是否正确时要用到。
提示:如果后面 CMake 报错说版本太低,可以考虑用 pip 安装新版 cmake,但我测试下来 Ubuntu 18.04 自带的 3.10.2 完全能编译 OpenCV 4.5,不需要多此一举。
2.2 图像、视频、GUI 依赖的安装细节
OpenCV 是个库,它要处理图像、视频和窗口显示,所以对应底层依赖一个都不能少。我第一次装的时候漏了libgtk-3-dev,结果编译出来cv2.imshow一调用就崩溃,排查了很久才发现是 GUI 后端没装全。
推荐按分组安装:
# 图片格式支持 sudo apt install -y libjpeg-dev libtiff5-dev libpng-dev # 视频处理和摄像头支持 sudo apt install -y libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libxvidcore-dev libx264-dev # GUI 显示(imshow等功能) sudo apt install -y libgtk-3-dev # 数值优化库(提升处理速度) sudo apt install -y libatlas-base-dev gfortran # 更多格式支持(jpeg2000, openexr等) sudo apt install -y libwebp-dev libopenexr-dev libgphoto2-dev这里重点解释几个容易忽略的依赖。
libavcodec-dev、libavformat-dev、libswscale-dev对应 FFmpeg 的底层库,如果没装,OpenCV 的VideoCapture读视频文件能力会被大幅削弱,可能只能读 AVI,MP4 直接打不开。libv4l-dev是 V4L2 摄像头接口的支持库,不给它装上,USB 摄像头读取会各种花屏、打不开。
libgtk-3-dev用来提供 OpenCV 的 HighGUI 窗口显示能力。如果你不装,CMake 会退回使用 Qt 或者完全不启用 GUI,这样imshow、waitKey全废。做视觉调试的时候不能弹窗显示图像,效率会非常低。
libatlas-base-dev和gfortran属于数学优化库,OpenCV 上层大量矩阵运算可以借助 ATLAS 或 OpenBLAS 加速。装了以后图像处理速度会有可感知的提升。
2.3 Python 开发环境和 numpy
如果你计划使用 Python 调用 OpenCV,这一步很重要。
Ubuntu 18.04 默认带了 Python 3.6。OpenCV 4.5 对 Python 3.6 的兼容性没有问题,但建议先把 Python 开发头文件和 pip 工具装好:
sudo apt install -y python3-dev python3-pip python3-numpypython3-dev提供 Python.h,编译 OpenCV 的 Python 绑定模块时必须要用到。python3-numpy用 apt 安装是因为系统级别的 numpy 比较稳定,能避免一些 pip 和系统环境混用的坑。
如果你有多个 Python 环境(比如 Anaconda),强烈建议在编译 OpenCV 之前确定好要用哪个 Python。因为 CMake 会自动检测系统里的 Python 解释器,如果环境变量VIRTUAL_ENV或CONDA_PREFIX存在,它会去绑定对应的 Python。这个绑定关系一旦定下来,OpenCV 的 Python 模块就只对这个 Python 环境生效。
注意:如果你的项目打算用 Anaconda 里的 Python,请在 CMake 配置之前先
conda activate切换好环境。我就因为忘记切换,编译出的 cv2 装到了系统 Python 里,conda 环境怎么 import 都报错。
3. 源码下载与 CMake 配置
3.1 版本对应关系:OpenCV 与 Contrib 包缺一不可
OpenCV 4.5 发布后,opencv_contrib 仓库会同步发布相同版本的模块包。contrib 里包含了大量扩展模块,比如 ArUco 标记检测、SFM、文本识别、人脸识别等。官方主仓库默认不会编译这些模块,只有通过OPENCV_EXTRA_MODULES_PATH指定路径才能把它们加进来。
下载源码时,最稳妥的做法是用 Git 切到对应 tag:
cd ~ git clone https://github.com/opencv/opencv.git cd opencv git checkout 4.5.0 cd ~ git clone https://github.com/opencv/opencv_contrib.git cd opencv_contrib git checkout 4.5.0两个仓库必须切到同一个版本 tag。如果一个是 4.5.0,另一个是 4.5.1,CMake 配置阶段极有可能因为模块接口不匹配而报错。我这里以 4.5.0 为例,如果你希望用 4.5.1、4.5.2,改成对应 tag 即可。
如果你所在的网络环境访问 GitHub 太慢,可以下载压缩包,但注意 opencv 和 opencv_contrib 的压缩包版本号也要严格一致。下载完成后放在同一个父目录下,方便后面 CMake 引用路径。
3.2 CMake 参数逐个解释,避免“知其然不知其所以然”
进入源码目录,创建 build 目录:
cd ~/opencv mkdir build && cd build然后执行 CMake 配置命令。下面是我实测稳定可靠的一组参数:
cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D WITH_TBB=ON \ -D WITH_V4L=ON \ -D WITH_QT=OFF \ -D WITH_GTK=ON \ -D WITH_OPENGL=ON \ -D WITH_OPENMP=ON \ -D OPENCV_ENABLE_NONFREE=ON \ -D OPENCV_GENERATE_PKGCONFIG=YES \ -D OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules \ -D BUILD_EXAMPLES=OFF \ -D BUILD_TESTS=OFF \ ..逐个解释一下关键参数:
CMAKE_BUILD_TYPE=RELEASE:编译优化等级,发布版能跑满 CPU 性能。debug 版会在运行时输出大量调试信息,通常没必要。CMAKE_INSTALL_PREFIX=/usr/local:安装路径。默认就是 /usr/local,头文件放/usr/local/include,动态库放/usr/local/lib。自己指定也可以,但后续要额外配置 PKG_CONFIG_PATH。WITH_TBB=ON:启用 Threading Building Blocks,Intel 的并行计算库,从 4.5 开始推荐开启,很多算法能自动利用多核并行。WITH_V4L=ON:启用 Video for Linux 摄像头支持。WITH_GTK=ON:使用 GTK 作为 GUI 后端。如果你的机器环境里 GTK 编译依赖没装全,这里会检测失败并退回其他后端,日志里会显示GUI: GTK+ : NO,这时候回去补装依赖。WITH_QT=OFF:如果不需要 Qt 界面集成,建议关掉,避免两个 GUI 后端互相干扰。WITH_OPENMP=ON:OpenMP 并行支持,配合多核 CPU,很多矩阵操作的性能提升明显。OPENCV_ENABLE_NONFREE=ON:这个非常关键。不开启它,SIFT 和 SURF 即便在 contrib 模块里也无法使用。项目里要跑特征点匹配的同学,这个参数一定别忘。OPENCV_GENERATE_PKGCONFIG=YES:4.5 系列编译后默认会生成opencv4.pc文件,方便 pkg-config 使用。OPENCV_EXTRA_MODULES_PATH=~/opencv_contrib/modules:指向 contrib 模块路径。BUILD_EXAMPLES=OFF、BUILD_TESTS=OFF:关闭示例和测试,大幅缩短编译时间。
CMake 执行完成后,仔细看输出信息。重点确认三处:
Python 3: YES,对应版本是否是你要用的 Python。GUI: GTK+ : YES,GUI 后端是否生效。FFMPEG: YES,视频后端是否生效。
如果这三处有 NO 或版本不对,先不要急着继续,回到上一步补依赖再重新执行 cmake。
3.3 执行编译:线程数和内存管理
CMake 配置完成后,正式编译:
make -j$(nproc)nproc会返回 CPU 核心数。不过这里有个经验值:如果你的物理内存低于 8GB,建议不要用全部核心,make -j4更稳妥。因为 OpenCV 编译过程中,编译单个.cpp文件可能吃掉 1-2GB 内存,同时开太多线程会导致内存耗尽、直接 OOM Kill。
我之前在一台 4 核 8GB 的笔记本上用过-j4,一切正常。换到 2 核 4GB 的老机器上同样用-j4,编译到一半卡死,后来降成-j2才顺利跑完。
编译过程可能需要十到二十分钟。可以去做点别的,但时不时看一眼终端,确认没有报错。如果编译中断,重新执行相同命令即可,CMake 会在中断点继续,不会从头开始。
编译完成后,安装:
sudo make install安装过程通常很快,就是把编译好的动态库和头文件拷贝到/usr/local对应目录。
4. 环境变量与安装验证
4.1 动态库路径配置
安装完成后,Linux 系统默认不一定能找到/usr/local/lib下的 OpenCV 动态库。如果直接编译测试程序,可能会遇到cannot find -lopencv_world或者运行时error while loading shared libraries。
解决方法是把库路径加入动态链接器配置。先创建一个配置文件:
sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'然后更新动态链接库缓存:
sudo ldconfigldconfig是必须执行的,不执行的话配置不会生效。执行完后,可以检查一下库是否能被找到:
ldconfig -p | grep opencv正常情况下能看到一堆 libopencv_core、libopencv_imgproc 等动态库路径。
接下来配置 pkg-config。OpenCV 4.5 编译时设置了OPENCV_GENERATE_PKGCONFIG=YES,所以系统里会有opencv4.pc文件。为了让 pkg-config 能发现它,设置环境变量:
export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH如果你希望每次打开终端都生效,把它写入~/.bashrc:
echo 'export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH' >> ~/.bashrc source ~/.bashrc然后验证 pkg-config 是否能正确返回 OpenCV 版本:
pkg-config --modversion opencv4如果输出4.5.0,说明环境配置成功。
4.2 C++ 测试程序验证安装
光看版本号还不够,最好写一个完整的测试程序,确认头文件、链接库和运行都没问题。
创建一个test.cpp:
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat image(480, 640, CV_8UC3, cv::Scalar(0, 0, 255)); std::cout << "OpenCV version: " << CV_VERSION << std::endl; std::cout << "Image size: " << image.cols << " x " << image.rows << std::endl; cv::Mat gray; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); std::cout << "Grayscale size: " << gray.cols << " x " << gray.rows << std::endl; return 0; }编译命令:
g++ test.cpp -o test $(pkg-config --cflags --libs opencv4)如果编译通过并且运行输出OpenCV version: 4.5.0,说明 C++ 环境完全正常。
很多教程无视 pkg-config,直接写一大串-I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_core -lopencv_imgproc -lopencv_highgui,也能编译,但容易漏库。用 pkg-config 是从项目配置角度最不容易出错的方案。
4.3 Python 接口验证
如果你编译时检测到了 Python 3,安装完成后,Python 环境里会生成cv2模块。验证方法很直接:
import cv2 print(cv2.__version__) print(cv2.getBuildInformation())输出的版本号是4.5.0就代表成功。getBuildInformation()里能看到完整的编译参数,比如 FFMPEG、GTK、TBB 是否生效。
这里有一个容易疑惑的问题:你可能会发现cv2.__file__指向的是/usr/local/lib/python3.6/dist-packages/cv2/python-3.6/cv2.cpython-36m-x86_64-linux-gnu.so,这是源码编译默认安装路径。如果你之前 pip 安装过 opencv-python,它会在site-packages下留下一个cv2,这时候 import 的到底是哪个?简单说,谁在PYTHONPATH里或者谁排在 sys.path 前面,就加载谁。建议源码编译完,把 pip 版的 opencv-python 卸载干净:
pip3 uninstall opencv-python opencv-contrib-python避免后面调试项目时出现版本错乱。
5. 常见问题与排查实录
5.1 编译中途容易遇到的经典报错
编译 OpenCV 很少有一帆风顺的,下面几个是我遇到最多的情况。
第一个是boostdesc_bgm.i等文件缺失的报错。这个问题在使用 contrib 模块时非常常见。本质是 contrib 仓库里部分算法的原始训练数据文件没有被正常打包。解决方法可以从网上找对应的.i文件,放到opencv_contrib/modules/xfeatures2d/src/目录下,再重新编译。如果是新版本,这个情况稍好一些,但 4.5 时代确实还有人遇到。
第二个是内存不足导致编译进程被杀。错误信息通常是virtual memory exhausted或者直接被系统 OOM 杀死。我在 2GB 内存的机器上试过,确实必现。解决办法是增加临时 swap:
sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile编译完可以视情况关闭 swap,这能有效防止 g++ 在编译高内存消耗的模块时崩溃。
第三个是Qt5WebKitWidgets之类缺失导致WITH_QT=ON时报错。如果你不需要 Qt,直接像我前面参数那样设WITH_QT=OFF就好了。不要盲目追求“功能全开”,稳定才是第一位。
5.2 头文件和动态库找不到
编译测试程序时如果报fatal error: opencv2/opencv.hpp: No such file or directory,要么是安装不完整,要么是头文件路径没被找到。
首先看一下/usr/local/include下是否有opencv4/opencv2目录。OpenCV 4.x 的头文件默认放在/usr/local/include/opencv4/opencv2下。如果存在,说明安装没问题,是编译命令没指定-I路径。换成 pkg-config 模式编译就不会有这个困扰。
运行时如果报error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file,那是动态库路径没生效。回到 4.1 节,确认/etc/ld.so.conf.d/opencv.conf是否已添加/usr/local/lib,并且执行过ldconfig。
提示:如果改完配置还不行,可以临时用
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH验证,但这个变量只对当前终端有效,不建议作为长期方案。
5.3 Python 环境多版本冲突
系统同时存在多个 Python 时,CMake 可能绑定到错误的 Python 版本。我在一台装有 Anaconda 的机器上,明明用系统 python3,但 CMake 自动检测到了 conda 里的 Python 3.8,结果编译出的 cv2 只能在 conda 环境里 import。
解决方案很粗暴:CMake 时手动指定 Python 解释器、库和 include 路径:
cmake -D PYTHON_DEFAULT_EXECUTABLE=$(which python3) \ -D PYTHON3_EXECUTABLE=$(which python3) \ -D PYTHON3_INCLUDE_DIR=$(python3 -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())") \ -D PYTHON3_LIBRARY=$(python3 -c "import sysconfig; print(sysconfig.get_config_var('LIBDIR'))")/libpython3.6m.so \ ...配置完成后,在 CMake 输出里明确核对 Python 版本和路径是否一致,再继续编译。
5.4 FFmpeg、GTK 等扩展功能未生效
编译完成后,如果你用cv2.VideoCapture读不了 MP4,或者cv2.imshow弹不出窗口,大概率是编译时 FFmpeg 或 GTK 没有被检测到。
在 CMake 配置输出里搜索FFMPEG和GTK,看到NO就要回头补依赖。常见原因是 apt 安装依赖之前你已经执行过 cmake,导致缓存里残留了旧的检测结果。这时候需要把 build 目录缓存清掉重新配置:
rm -rf build mkdir build && cd build cmake ...开发中最容易忽略的点就是“依赖装晚了”,然后一直沿用旧的 cache,排查半天以为代码有问题,其实重新 cmake 就解决了。
6. 实际使用中的几点建议
6.1 多项目共存时如何隔离 OpenCV 版本
编译完成不代表万事大吉。OpenCV 4.5 装到/usr/local后,全局生效。如果后面某个项目需要 OpenCV 3.x,安装到/usr/local会把 4.5 覆盖掉,比较麻烦。
我的做法是给不同版本指定不同的安装前缀。比如 4.5 装到/usr/local/opencv4.5:
cmake -D CMAKE_INSTALL_PREFIX=/usr/local/opencv4.5 ...编译项目时,通过-I/usr/local/opencv4.5/include/opencv4和-L/usr/local/opencv4.5/lib指定路径,或者临时设置PKG_CONFIG_PATH指向对应的 pkgconfig 目录。这样不同项目各用各的 OpenCV,互不干扰。
用 CMake 管理 C++ 项目的同学,还可以在CMakeLists.txt里这样写:
set(OpenCV_DIR "/usr/local/opencv4.5/lib/cmake/opencv4") find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) target_link_libraries(your_target ${OpenCV_LIBS})6.2 编译优化参数还能加什么
如果你的机器有 NVIDIA 显卡,并且计划跑深度学习推理,可以考虑在 CMake 时加入 CUDA 支持:
-D WITH_CUDA=ON \ -D WITH_CUDNN=ON \ -D OPENCV_DNN_CUDA=ON \ -D CUDA_ARCH_BIN=7.5CUDA_ARCH_BIN要按显卡的算力填写,比如 RTX 2070 Super 是 7.5,RTX 3080 是 8.6。填错的话虽然能编译,但运行时可能无法调用 GPU 设备。
有 NVIDIA 显卡还能启用WITH_CUBLAS和WITH_CUFFT,对图像处理和矩阵运算有帮助。
如果机器上没有 NVIDIA 平台,千万别开 CUDA 相关参数,否则 CMake 检测阶段直接报错或者编译出来的库运行不稳定。
6.3 安装完成后备份编译产物
最后分享一个我自己的习惯。编译好的 OpenCV 4.5,我会把/usr/local/lib下的 libopencv 相关 so 文件、/usr/local/include/opencv4头文件和lib/cmake/opencv4目录一起打包留底:
tar -czf opencv4.5_ubuntu18.04_backup.tar.gz \ /usr/local/lib/libopencv* \ /usr/local/include/opencv4 \ /usr/local/lib/cmake/opencv4等哪一天系统重装、或者另一台同版本机器要复用,直接把备份释放回去,再补一个ldconfig就能重新用,不用再花二三十分钟重新编译。这个方法在团队协作维护多台开发机时特别实用。
我自己在几年的开发里,用这套流程装过的机器包括笔记本、台式机、工控机和服务器,除了极少数硬件特殊的情况,基本都是一遍过。Ubuntu 18.04 的生命周期虽然逐步进入尾声,但大量存量项目依然跑在这个系统上,OpenCV 4.5 作为它们的视觉底层,仍然会存在很长时间。希望这篇记录能在你安装配置的时候帮你省点时间,少踩点我当年踩过的坑。