尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Ubuntu 20.04 源码编译 OpenCV 3.3.1 全流程与避坑指南

Ubuntu 20.04 源码编译 OpenCV 3.3.1 全流程与避坑指南 简介针对 Ubuntu 20.04 重新适配的 OpenCV 3.3.1 资源包面向需要在较新系统上编译旧版 OpenCV 的开发者、人工智能与计算机视觉学习者。作者已修正 CODEC_FLAG_GLOBAL_HEADER、AVFMT_RAWPICTURE 未声明及 const char* 转 char* 等编译错误可直接配置编译。包内共 5630 个文件约 85.64MB以 cpp、hpp、h 等 C 源码与头文件为主含 py 脚本、java 接口、png/jpg 示意图、markdown 文档及 cmake 构建配置结构完整便于按模块查阅。已有 1780 人学习下载适合在 Ubuntu 20.04 上搭建 OpenCV 开发环境、研究旧版内部实现或开展图像处理实验。1. 为什么都 2024 年了还有人要在 Ubuntu 20.04 上装 OpenCV 3.3.1接手一台预装 Ubuntu 20.04 的机器apt install libopencv-dev装出来的是 4.2 版本但项目的 CMakeLists 里写死了find_package(OpenCV 3.3 REQUIRED)一编译就报OpenCV 3.3 not found。这种时候你只有两条路把项目几十个源文件的 API 全部迁移到 4.x或者给这台机器装一份 OpenCV 3.3.1。前者往往要改掉CV_LOAD_IMAGE_COLOR、cv::SIFT这类老接口后者只需要花一个下午编译。实际上到今天还有大量自动驾驶、SLAM、工业视觉项目锁死在 3.3.1 上——因为论文复现、老代码库、无人车竞赛的 baseline 都是在那个版本上跑的升级意味着重跑全部实验。这篇笔记面向的就是这批人需要在 Ubuntu 20.04 上装 old OpenCV 且不想被坑的开发者。2. 先看清 3.3.1 和 20.04 的兼容关系为什么不能直接 apt install2.1 Ubuntu 20.04 自带的 OpenCV 是什么为什么不够用Ubuntu 20.04 的官方源里带的是 OpenCV 4.2.0通过apt install libopencv-dev安装后头文件在/usr/include/opencv4/pkg-config的名字是opencv4。问题在于OpenCV 4.x 从目录结构到 API 都跟 3.x 有本质差异头文件路径从opencv2/变成了opencv4/opencv2/C API 里的CV_前缀宏大部分改成了cv::枚举contrib模块的模块名也做了调整。对一个三年前写的项目来说这些差异足以让它在编译阶段就倒下一大片。另一个现实问题是即使你愿意改代码OpenCV 4.2 在 Ubuntu 20.04 上通过 apt 装的版本是不带contrib模块的。而 3.3.1 那个年代的项目大量用到xfeatures2dSIFT、SURF、aruco、text这些 contrib 里的东西。apt 源里的 opencv 包不包含这些意味着你还得自己去编译 opencv-contrib——那既然都要编译了为什么不直接编一个完整的 3.3.1还有 ABI 层面的问题。OpenCV 3.3.1 编译时默认使用的是 C11 标准而 20.04 的默认 GCC 是 9.3编译出的二进制对 libstdc 的要求更高。老版本 OpenCV 编译出的.so和 20.04 上其他库的二进制兼容性在实际项目中经常因为符号版本问题出幺蛾子。所以我的建议是不要试图用 apt 曲线救国也不要下什么第三方编译好的包在 20.04 上老老实实从源码编这是唯一可控的路径。2.2 3.3.1 对系统的真实要求Python 版本、GCC、CUDA 边界OpenCV 3.3.1 是 2017 年 8 月发布的它的时代背景是 Ubuntu 16.04 和 18.04 盛行。放到 20.04 上有几个硬性边界需要先确认。Python 方面3.3.1 的 CMake 脚本对 Python 3 的支持远不如 4.x 成熟。如果你用-D PYTHON3_EXECUTABLE指定 Python 3.820.04 默认需要确保PYTHON3_INCLUDE_DIR和PYTHON3_LIBRARY都手动指对否则 CMake 配置阶段会显示Python3: NO最后编出来的库没有 cv2 模块。这是让很多人第一次装 3.3.1 就翻车的地方。GCC 方面20.04 的 GCC 9.3 编译 OpenCV 3.3.1 没有问题但要注意一个已知坑GCC 9 默认开启了-fcf-protection而 OpenCV 3.3.1 某些旧版本的构建脚本没处理这个 flag链接时可能报Property(P) section相关的错误。解决方式是在CMAKE_CXX_FLAGS里显式加上-fcf-protectionnone后面章节会细说。CUDA 方面如果你需要开 GPU 加速3.3.1 官方支持到 CUDA 8/9在 20.04 上装 CUDA 10.2 以上版本时OpenCV 3.3.1 的 CUDA 代码会因为 NVCC 版本太新而编译失败。常见做法是放弃 CUDA或者用 4.x 配合 contrib 模块重编——这也是很多老项目升级到 4.x 的真正原因。纯 CPU 场景下3.3.1 在 20.04 上没有不可逾越的障碍。2.3 资源从哪来官方源码与 contrib 的匹配原则OpenCV 3.3.1 的资源分两部分主仓库和 contrib 仓库。主仓库源码在 OpenCV 官方 GitHub 的3.3.1tag 上contrib 在 opencv_contrib 仓库的3.3.1tag 上。这里最重要的原则是主仓库和 contrib 的版本必须严格一致不能拿 3.3.1 的主仓库去配 3.4.x 的 contribCMake 配置阶段会直接报contrib modules are disabled或者编译期出现未声明标识符。下载方式上很多人习惯git clone -b 3.3.1 --depth 1这个方案在 GitHub 直连通畅时可用。但如果你在公司网络环境或者 GitHub 拉取经常中断可以直接下载 tar.gz 包——地址是github.com/opencv/opencv/archive/3.3.1.tar.gz和github.com/opencv/opencv_contrib/archive/3.3.1.tar.gz。下载后优先校验一下哈希值官方页面上有对应的 SHA-256避免拿到损坏的包编到一半才报错。另外注意一个细节opencv_contrib 的 3.3.1 tag 里modules/下某些模块比如xfeatures2d在编译时依赖 OpenCV 主仓库里的一些内部接口这些接口在后续版本中变动过。所以再次强调版本匹配是头等大事不要自作聪明去配不同版本。3. 源码编译 3.3.1 的核心步骤从依赖安装到 make install3.1 最小依赖集合装多了编译慢装少了编不过在 20.04 上编译 OpenCV 3.3.1依赖分必选和可选两类。必选依赖实际上只有几个build-essentialGCC/G/Make、cmake3.3.1 要求 CMake 2.8.12 以上20.04 自带的 3.16 够用、pkg-config。这三个是底线没有它们连 CMake 配置都过不去。可选依赖里我建议在第一次编译时全部装上避免后续重新配置libjpeg-dev libpng-dev libtiff-dev libavcodec-dev libavformat-dev libswscale-dev libgtk-3-dev libcanberra-gtk-module libv4l-dev libdc1394-22-dev。其中libgtk-3-dev尤其重要——它决定highgui模块能不能显示图片窗口。很多人编译没报错但运行时cv2.imshow直接报错或者不弹窗就是少了这个依赖。下面是安装命令建议按块执行方便排查哪一步出了问题# 基础编译工具链 sudo apt update sudo apt install -y build-essential cmake pkg-config # 图像编解码与 GUI 依赖 sudo apt install -y libjpeg-dev libpng-dev libtiff-dev sudo apt install -y libavcodec-dev libavformat-dev libswscale-dev sudo apt install -y libgtk-3-dev libcanberra-gtk-module sudo apt install -y libv4l-dev libdc1394-22-devlibdc1394-22-dev这个包在 20.04 上是存在的对应的是 IEEE 1394 相机接口协议库。如果你的项目用不到工业相机这个依赖可以跳过但它体积不大装上可以减少 CMake 检测阶段因缺少某个组件而导致的潜在告警。如果后续要用到 Python 绑定在编译 OpenCV 之前还要装 Python 开发头文件sudo apt install -y python3-dev python3-pip python3-numpypython3-dev提供 Python.h 头文件CMake 找不到它的时候即使你指定了 Python 路径配置阶段也会把 Python 支持顺手关掉。python3-numpy是 cv2 运行时必需的不然 import cv2 没问题但一调用数组转换就崩。3.2 CMake 配置这些参数决定你要不要返工进入源码目录之后创建一个独立的 build 目录我从来不在源码根目录下直接跑 cmake这样想清理重来的时候只删 build 就行然后执行一次配置。下面是我在 20.04 上为 3.3.1 准备的 CMake 命令纯 CPU 版本带 contrib 模块cmake -D CMAKE_BUILD_TYPERELEASE \ -D CMAKE_INSTALL_PREFIX/usr/local \ -D OPENCV_EXTRA_MODULES_PATH/path/to/opencv_contrib-3.3.1/modules \ -D WITH_TBBON \ -D WITH_V4LON \ -D WITH_GTKON \ -D WITH_OPENGLON \ -D BUILD_opencv_python2OFF \ -D BUILD_opencv_python3ON \ -D PYTHON3_EXECUTABLE$(which python3) \ -D PYTHON3_INCLUDE_DIR$(python3 -c from sysconfig import get_path; print(get_path(include))) \ -D PYTHON3_LIBRARY$(python3 -c import sysconfig; print(sysconfig.get_config_var(LIBDIR)))/libpython3.8.so \ -D INSTALL_C_EXAMPLESOFF \ -D INSTALL_PYTHON_EXAMPLESOFF \ -D BUILD_EXAMPLESOFF \ -D BUILD_TESTSOFF \ -D CMAKE_CXX_FLAGS-fcf-protectionnone ..关键参数说明OPENCV_EXTRA_MODULES_PATH指向 contrib 源码目录下的modules子目录。这个路径写错了配置阶段不会报错但你在编译 SIFT 相关代码时会发现cv::xfeatures2d根本不存在。WITH_TBBON开启 Intel TBB 线程库。20.04 上如果没有装 libtbb-dev这个选项会自动被置为 OFF。装了的话建议开对多线程图像处理有实打实的性能提升。PYTHON3_*三个参数这是最容易踩坑的一组。手动指定而不是依赖 CMake 自动探测是因为 CMake 在 3.16 版本上对 Python3 的 FindPythonInterp 机制常常拿到一个libpython3.8.a静态库或者干脆找不到LIBRARY导致 configure 阶段 Python3 显示为 NO。CMAKE_CXX_FLAGS-fcf-protectionnone针对 GCC 9 的兼容性 flag。不加这个编译到opencv_core的某些 CUDA 或者 OpenCL 相关文件时可能报can not be used when making a shared object或类似链接错误。配置完成后确认一下CMakeCache.txt里的关键值然后看一下终端输出的 Summary 部分。重点看这三行Python 3: YES、GTK: YES、xfeatures2d: YES在 contrib 模块列表里。如果 Python 显示 NO不要继续编译直接回上面检查 PYTHON3 参数路径是否正确。3.3 编译与安装用对核数少等半小时# 先查看 CPU 核心数 nproc # 建议使用 nproc-1 核编译留一核给系统 make -j$(($(nproc) - 1))OpenCV 3.3.1 的完整编译在 8 核 16G 内存的机器上大约需要 20-35 分钟。如果你的机器内存只有 8G建议make -j4否则编译到一半内存耗尽直接被 OOM Killer 干掉——这种情况很常见报错信息是Killed没有其他异常日志。编译过程中如果某个文件报错不要急着删整个 build 目录。先记录报错的文件路径和行号然后用make -j1重新编译让错误完整输出。绝大多数编译错误发生在opencv_contrib的模块里因为 contrib 代码的维护力度远不如主仓库在 GCC 9 上容易触发-Werror级别的告警。安装之前我习惯先编一个目标验证下make -j$(($(nproc) - 1)) sudo make install sudo ldconfigldconfig一定要执行否则新安装的/usr/local/lib下的.so文件不会被动态链接器索引到运行时会报libopencv_core.so.3.3: cannot open shared object file。执行完ldconfig后可以用ldconfig -p | grep opencv快速验证库是否被识别。如果/usr/local/lib不在默认搜索路径里还要检查/etc/ld.so.conf.d/下是否需要添加对应的 conf 文件。4. 解决 Python 绑定的老大难让import cv2指向你刚编译的 3.3.14.1 装完了 cv2 还是找不到或指向了系统其他版本的 OpenCV这是 OpenCV 安装教程里被问得最多的问题。编译安装了 3.3.1python3里import cv2却报ModuleNotFoundError: No module named cv2或者更诡异——cv2.__version__显示的是 4.2.0。后者说明你其实导入的是/usr/lib/python3/dist-packages/cv2/python-3.8/cv2.cpython-38-x86_64-linux-gnu.so那是 apt 之前装的那个 OpenCV 4.2 的 Python 绑定而不是自己编译的 3.3.1。自己编译的 Python 绑定默认安装在/usr/local/lib/python3.8/dist-packages/cv2/下如果改了CMAKE_INSTALL_PREFIX就对应不同路径。先确认这个文件是否存在ls /usr/local/lib/python3.8/dist-packages/cv2/ # 应该能看到 cv2.cpython-38-x86_64-linux-gnu.so 和 __init__.py确认存在之后需要把/usr/local/lib/python3.8/dist-packages加入 Python 的搜索路径。有几种方式我按推荐的优先级排列方式一推荐用环境变量对当前用户生效。在~/.bashrc里追加echo export PYTHONPATH/usr/local/lib/python3.8/dist-packages:$PYTHONPATH ~/.bashrc source ~/.bashrc方式二建软链接到全局 dist-packages。如果你希望所有用户都能 import 到这个 cv2sudo ln -s /usr/local/lib/python3.8/dist-packages/cv2 /usr/lib/python3/dist-packages/cv2注意这种方式可能导致和系统自带的 OpenCV 4.2 共存时出现版本对冲因为/usr/lib/python3/dist-packages下原来的 cv2 可能还在。建议先移除系统默认的 python3-opencv 包或者干脆用方式一隔离。方式三在 Python 虚拟环境里装这种方式最干净。用virtualenv创建新环境后把编译出来的 cv2 目录整个复制到虚拟环境的site-packages下python3 -m venv ~/cv2_env cp -r /usr/local/lib/python3.8/dist-packages/cv2 ~/cv2_env/lib/python3.8/site-packages/在虚拟环境里import cv2就不会被系统路径干扰。这个方案适合同一台机器上要同时用 OpenCV 3 和 4 的开发场景。4.2 用 CMake 的OPENCV_PYTHON3_VERSION参数控制绑定子版本OpenCV 3.3.1 的 Python 绑定默认只生成一个.so但如果你系统里有多个 Python 3.x 小版本CMake 可能会把绑定编译到它自己探测到的那个版本上。3.3.1 的 CMake 脚本里PYTHON3_PACKAGES_PATH和PYTHON3_VERSION都是可以手动指定的。举个例子如果你的默认python3是 3.8但 CMake 意外地探测到了 3.9 或者哪里的 3.7可以在配置阶段显式追加-D PYTHON3_VERSION3.8 \ -D PYTHON3_PACKAGES_PATH/usr/local/lib/python3.8/dist-packages注意 3.3.1 的 Python 绑定依赖 numpy 的接口版本。如果你系统里 numpy 版本高于 1.19某些函数内部的数组对象布局变了可能导致运行时崩溃。如果遇到cv2.imread后numpy.ndarray转换直接 Segmentation Fault大概率就是这个问题。解决方案是降级 numpypip3 install numpy1.19.5或者干脆用虚拟环境并在里面装指定版本。4.3 验证 cv2 是否处于正常状态的三个命令行测试装好之后不要急着跑项目先做三个快速测试。用命令行执行以下 Python 脚本python3 -c import cv2; print(cv2.__version__) # 期望输出: 3.3.1 python3 -c import cv2; print(cv2.buildInformation()[:500]) # 期望能看到 Python 3 相关段落的输出确认绑定的 Python 版本 python3 -c import numpy as np, cv2; img np.zeros((100,100,3), dtypenp.uint8); print(cv2.imencode(.jpg, img)[1].shape) # 期望输出: (x, y)说明编码器正常工作第三个测试非常重要它验证了 cv2 和 numpy 之间的数据类型转换是否正常。如果这一步报错后面跑任何图像处理项目都会在早期莫名其妙地崩溃。cv2.imencode比cv2.imshow更适合做验证因为 imshow 需要图形环境而服务器上通常没有。5. 避坑清单20.04 编译 3.3.1 的 5 个高频现场这些坑是我在这类环境里反复见到过的每一个都有人为之消耗过半天到一天的时间。按照出现频率排序。1. 编译时报错fatal error: boostdesc_bgm.i: No such file or directory现象编译到opencv_contrib/modules/xfeatures2d时文件找不到编译中断。原因OpenCV 的 GitHub 仓库没有把xfeatures2d里的大文件用 git 正常存储需要单独下载。官方在 contrib 仓库的 README 里有一个下载脚本但很多人不会注意到直接 clone 下来就编于是卡在这一步。解决从raw.githubusercontent.com/opencv/opencv_contrib/3.3.1/modules/xfeatures2d/src/路径下载对应的.i文件boostdesc_bgm.i、vgg_generated_120.i 等放到源码目录对应的src/下。这些文件约 7-8 个几十 MB下载时注意文件名大小写。2. CMake 配置阶段显示Python3: NO编译后没有 cv2 模块现象make install完成后/usr/local/lib/python3.8/dist-packages不存在或者只有cv2相关文件缺失。原因主要是 CMake 在配置阶段没有找到Python.h或者libpython3.8.so。20.04 上如果你只装了python3而没有装python3-dev就会出现这个情况。另一个原因是PYTHON3_LIBRARY指向了静态库。解决确保python3-dev已安装然后配置时指定PYTHON3_INCLUDE_DIR为python3 -c from sysconfig import get_path; print(get_path(include))的输出。如果指定后还是 NO在 build 目录下grep -i python CMakeCache.txt看是否有残留的错误缓存必要时删掉 build 目录重新配置。3. 运行时libopencv_core.so.3.3: cannot open shared object file现象编译安装后运行任何可执行文件动态链接器报错。原因/usr/local/lib不在/etc/ld.so.conf.d/的搜索路径里或者编译时CMAKE_INSTALL_PREFIX指定到了非标准路径。解决先执行sudo ldconfig如果问题依旧在/etc/ld.so.conf.d/下新建一个opencv.conf文件内容写入/usr/local/lib然后执行sudo ldconfig刷新。这种方式修改的是系统级配置对全部用户生效避免后续每个人各自设环境变量。4.cv2.imshow报错或无法打开窗口现象在带图形界面的 Ubuntu 20.04 上运行cv2.imshow窗口不弹出或者直接报cv2.error: The function is not implemented.原因编译时WITH_GTK没有被正确启用。常见原因有两个一是没装libgtk-3-devCMake 自动检测不到 GTK 支持把 highgui 对应的窗口功能编译成了一个空实现二是安装了 GTK2 而不是 GTK3而 OpenCV 3.3.1 的 CMake 默认优先探测 GTK3探测不到才退回 GTK2如果两个都没有就是空实现。解决确认libgtk-3-dev已安装然后在 build 目录里搜索WITH_GTK的值。如果确认安装了仍然显示未开启删除 build 目录重新配置。gtk 问题最容易在配置阶段被忽略因为它只影响 highgui 的 GUI 功能不影响编译本身。5. 和系统已有 OpenCV 4.x 的库文件冲突现象编译的 OpenCV 3.3.1 安装后用pkg-config --modversion opencv查看版本依然是 4.2 或者版本混乱。有的程序链接时报undefined reference to cv::Mat::Mat()或者链接到了多个版本的库运行时直接段错误。原因20.04 的 apt 源里如果有libopencv-dev会在/usr/include/opencv4/安装头文件pkg-config路径/usr/lib/x86_64-linux-gnu/pkgconfig/opencv4.pc会优先匹配。而你手动编译的安装在/usr/local/下路径优先级和 apt 安装的库冲突。解决两个方案任选其一。其一卸载系统 apt 安装的 opencv 相关包sudo apt remove libopencv-dev python3-opencv然后让/usr/local成为唯一来源。其二保留系统版本但用pkg-config --define-prefix或环境变量PKG_CONFIG_PATH把/usr/local/lib/pkgconfig添加到最前面。在 CMake 项目里可以强制指定OpenCV_DIR指向/usr/local/share/OpenCV。这两种方式需要根据自己的项目情况选稳一点的那种我多数时候选择卸载系统版本减少后续不可预期的问题。6. 多版本共存与快速验证把 3.3.1 装成一个可随时切换的独立环境最后一章聊聊怎么把 3.3.1 用得灵活。如果你的机器上同时有 4.x 和 3.3.1不想卸载任何一个最简单的做法是用 Docker 或者 chroot 隔离。Docker 方式是最省心的拉一个ubuntu:20.04镜像在里面按上面的流程编译一次然后把镜像保存。后续哪个项目要 3.3.1直接从镜像起容器宿主机上的 OpenCV 完全不受影响。如果不方便用容器还有一个比较轻量的方案编译时把CMAKE_INSTALL_PREFIX指定到独立目录比如/opt/opencv/3.3.1这样所有库文件和头文件都安装在那里不会污染/usr/local。使用时在 CMake 项目里设置cmake -D OpenCV_DIR/opt/opencv/3.3.1/lib/cmake/opencv4 ..注意一个细节OpenCV 3.3.1 安装后它的 CMake 配置目录是lib/cmake/opencv4不是lib/cmake/opencv。很多人在指定OpenCV_DIR时写成了.../lib/cmake/opencv导致find_package找不到。这个细节值得记一下。快速验证一个项目能否在新环境上跑起来我通常写一个最小的 C 测试程序验证函数调用链路是否正常// test_opencv.cpp #include opencv2/opencv.hpp #include opencv2/xfeatures2d.hpp #include iostream int main() { cv::Mat img cv::imread(test.jpg, cv::IMREAD_COLOR); if (img.empty()) { std::cout read image FAILED std::endl; return 1; } cv::Ptrcv::xfeatures2d::SIFT sift cv::xfeatures2d::SIFT::create(); std::vectorcv::KeyPoint kpts; sift-detect(img, kpts); std::cout read img.cols x img.rows , SIFT keypoints: kpts.size() std::endl; return 0; }编译这条命令特意用pkg-config验证库路径g test_opencv.cpp -o test_opencv \ $(pkg-config --cflags --libs opencv4) \ -L/opt/opencv/3.3.1/lib -Wl,-rpath,/opt/opencv/3.3.1/lib-Wl,-rpath是重点——它把运行时库搜索路径直接写进了二进制文件这样不管系统里有多少个 OpenCV 版本这个可执行文件运行时永远只找/opt/opencv/3.3.1/lib下的库。我有一次就栽在没加-rpath上程序在自己的终端跑得好好的部署到另一台机器上就报 libopencv 版本不匹配查了半天。这么多年的习惯是遇到老版本 OpenCV 依赖问题时先做版本隔离再设计编译参数最后才动手编译——顺序反了很容易白忙一场。希望这篇笔记能帮你少走一段弯路。本文还有配套的精品资源点击获取
返回列表