
简介OpenCV 4.10.0 Linux源码编译成品包面向需要直接调用OpenCV库进行图像处理与视觉算法开发的工程师和研究者。从中可以看到编译已覆盖核心模块与opencv_contrib扩展模块包含libopencv_imgproc、libopencv_dnn、libopencv_xfeatures2d、libopencv_tracking等一批.so动态库可直接配置链接路径使用同时包含静态库、头文件与Python绑定文件兼顾C与Python两种开发方式。压缩包共903个文件大小41.1MB文件类型以525个hpp头文件、57个so动态库、56个h头文件、91个pyi类型存根及py脚本、XML/CMake/YAML配置为主结构清晰便于按需取用。目前已有804人学习/下载。对于希望跳过依赖配置与编译报错阶段、快速获得可用OpenCV 4.10.0环境的开发者这份编译产物能明显缩短准备周期也为自定义二次编译提供了参考基线。 平时用OpenCV做视觉处理大多数时候靠pip一句pip install opencv-python就完事。但真要上生产环境、做嵌入式部署或者想用上contrib扩展库里的SIFT、ArUco这些模块跑现成的包就处处碰壁。所以这段时间我专门把OpenCV 4.10.0从官方源码完整编译了一遍从CMake配置到make安装全流程走通顺便把环境里各种依赖的坑也填了一遍。这篇文章就记录一下这次编译的完整过程、核心参数取舍以及调试时踩过的具体问题和排查思路给同样有计划自己编译OpenCV的朋友做个参考。这次编译主要解决三个问题第一需要启用OpenCV的contrib扩展模块实现SIFT特征提取功能官方预编译包不带这些第二需要调用摄像头硬件加速和FFmpeg视频流解码能力发行版自带的包经常把相关组件裁掉第三受够了每次换机器都要重新配一遍环境自己编译一次把opencv安装到系统目录之后整个项目组其他人直接引用即可。1. 编译前准备工作版本选择、依赖安装与目录规划1.1 为什么要自己编译而不是直接用官方预编译包先把一个基本概念讲清楚。OpenCV官方提供的安装包分两种一种是通过包管理器直接安装的二进制版本另一种是源码包需要自己动手编译。对于Windows平台官网直接提供编译好的exe安装程序装完配置环境变量就能用。Linux发行版也大多有预编译包比如Debian系下面的libopencv-dev。但预编译包有几个很尴尬的限制。首先是安装位置和编译选项都是别人定死的比如V4L2的支持、GStreamer的支持这些可能默认就没开启。更关键的是OpenCV的扩展模块opencv_contrib里面包含了人脸识别、文本检测、SIFT/SURF特征提取等大量实用算法但官方预编译版本基本都不包含。所以如果项目里要用到这些功能就必须自己从源码编译把contrib模块的源码一起加进去。还有一个容易被忽视的场景是交叉编译。比如要在ARM开发板上跑OpenCV通常是在Windows机器上编译ARM平台版本或者在x86的Linux主机上交叉编译ARM版本。这必须手动配置工具链和交叉编译参数是预编译包完全覆盖不了的。1.2 编译环境的依赖清单与版本核对开始编译之前建议先把编译器和依赖库装好。不同Linux发行版包名略有差异我这里以较典型的Ubuntu/Debian系为例。# 基础编译工具 sudo apt update sudo apt install -y build-essential cmake git pkg-config # OpenCV核心依赖 sudo apt install -y libjpeg-dev libpng-dev libtiff-dev sudo apt install -y libavcodec-dev libavformat-dev libavutil-dev libswscale-dev sudo apt install -y libgtk2.0-dev libcanberra-gtk-module libv4l-dev sudo apt install -y libeigen3-dev libtbb-dev这里说一下为什么这些依赖一个都不能省。libjpeg-dev、libpng-dev、libtiff-dev提供的是图像编解码能力没有它们后面编译出来的OpenCV连最基本的imread读取jpg/png图片都做不了只能支持bmp这类极少格式。libavcodec、libavformat这一组是FFmpeg的核心库负责视频文件解析和解码VideoCapture要读mp4、avi这类格式全靠它们。libgtk2.0-dev则是给imshow显示窗口用的HighGUI模块提供GTK支持少了它窗口显示功能会被直接禁用调试图像时非常难受。版本核对这一步容易被跳过但值得说一句。不同发行版带的依赖库版本差异很大尤其是在比较老的系统镜像上比如用Ubuntu 16.04这种不太新的版本系统自带的CMake版本可能只有3.5左右但OpenCV 4.10.0的构建脚本要求CMake最低版本是3.5.1以上有的模块甚至要求更高的版本。建议执行一下cmake --version确认版本号如果发现版本太低优先考虑增加一个apt源来升级CMake而不是直接从源码编译这样可以省下不少时间。1.3 源代码包获取方式与目录规划建议源码包的获取方式有两种。优先推荐从OpenCV官网下载release tar包地址是opencv.org/releases页面选择4.10.0版本然后下载source包。另一种方式是用git从GitHub克隆但release包相对更稳定且下载后自带完整的CMake工程结构没有中间提交状态带来的不确定性。下载完成后先校验一下文件完整性确保下载过程中没有损坏wget https://github.com/opencv/opencv/archive/refs/tags/4.10.0.tar.gz wget https://github.com/opencv/opencv_contrib/archive/refs/tags/4.10.0.tar.gz sha256sum opencv-4.10.0.tar.gz opencv_contrib-4.10.0.tar.gz这里要特别提醒一点官方release包跟contrib版本号必须严格对应。如果下载OpenCV 4.10.0的主包却用OpenCV 4.9.0的contrib包CMake配置阶段大概率会报版本不兼容的错误。我在编译早期版本时踩过这个坑当时提示的错误信息比较隐晦是modules/contrib/...下面某个头文件加载失败一开始完全没想到是版本不匹配的问题折腾了很久才发现根源。关于目录规划建议准备三个独立的目录source目录放源码build目录放编译中间产物install目录是最终的安装路径。这样做的目的很明确编译过程中会产生大量CMake缓存文件和.o目标文件如果把build目录放在源码目录内部一旦CMake缓存出了问题要清理重来很容易误删源码文件。用独立的build目录就可以随时删掉整个目录重新跑CMake完全不影响源码。我在生产实践中一般的目录结构如下mkdir -p ~/opencv_410/{source,build,install} tar -xzf opencv-4.10.0.tar.gz -C ~/opencv_410/source tar -xzf opencv_contrib-4.10.0.tar.gz -C ~/opencv_410/source mv ~/opencv_410/source/opencv-4.10.0 ~/opencv_410/source/opencv mv ~/opencv_410/source/opencv_contrib-4.10.0 ~/opencv_410/source/opencv_contrib cd ~/opencv_410/build2. CMake配置阶段核心参数拆解与选择思路2.1 为什么CMake配置是编译成败的关键OpenCV的编译流程里CMake配置这一步最决定生死。它做的事情是运行一系列自动检测脚本检查当前系统里有哪些依赖库哪些模块的编译条件是否满足然后根据这些检测结果生成Makefile或者Visual Studio工程文件。可以理解为对整个编译环境的全面体检。在CMake配置阶段我们需要通过-D参数指定一系列编译选项。这些选项决定了最终生成的OpenCV库包含什么功能、不包含什么功能。常见的预编译包之所以不包含某些功能本质上就是发布者配置CMake选项时没有启用这些功能。2.2 本次编译的核心CMake命令实例下面给出一段我在这次编译中实际使用的CMake配置命令并逐项做说明cd ~/opencv_410/build cmake -D CMAKE_BUILD_TYPERelease \ -D CMAKE_INSTALL_PREFIX~/opencv_410/install \ -D OPENCV_EXTRA_MODULES_PATH~/opencv_410/source/opencv_contrib/modules \ -D OPENCV_ENABLE_NONFREEON \ -D BUILD_TESTSOFF \ -D BUILD_EXAMPLESOFF \ -D BUILD_opencv_python3ON \ -D WITH_TBBON \ -D WITH_V4LON \ -D WITH_FFMPEGON \ -D WITH_GTKON \ -D WITH_OPENCLON \ -D ENABLE_CXX11ON \ -D OPENCV_GENERATE_PKGCONFIGYES \ ../source/opencv逐个说明这些参数的作用。CMAKE_BUILD_TYPERelease指定编译优化级别Release模式下编译器会用-O3级别的优化运行速度比Debug模式快很多。当然编译时间也更长但OpenCV这类图像处理库对性能敏感生产环境毫无疑问选Release。CMAKE_INSTALL_PREFIX是安装路径决定make install执行后头文件、库文件、cmake配置文件的落位位置。这里注意不要用系统默认的/usr/local做测试因为如果之后要卸载或更换版本没有明确的目录管理会比较麻烦。我习惯把安装目录规划在专用位置例如~/opencv_410/install后续通过环境变量或CMake的find_package路径去引用相对更容易管理。OPENCV_EXTRA_MODULES_PATH是核心中的核心这个参数把opencv_contrib扩展模块的路径传给CMake这样编译时就会把contrib下的模块一并构建。注意一定要把路径指到contrib源码下的modules目录而不是contrib的根目录。2.3 几个常用参数的取舍理由在参数的选择上有几个容易被忽略但实际效果差别巨大的选项值得单独展开讲讲。OPENCV_ENABLE_NONFREE这个开关开启后才会编译SIFT、SURF这些受专利保护的算法模块。在OpenCV 4.x版本之前SIFT算法因为有专利保护被放在opencv_contrib的xfeatures2d模块里用之前必须显式开启这个选项。虽然SIFT相关专利在2020年已经过期但OpenCV源码里仍然保留了这个开关默认处于关闭状态。所以如果项目里要用SIFT做特征匹配这个参数必须开启。我在编译时一开始漏了这个选项导致后面调用cv::SIFT::create()时直接报链接错误。BUILD_opencv_python3ON这个选项决定是否生成Python 3的绑定模块cv2。如果你需要同时给C和Python使用同一个OpenCV库这个选项很有用。但需要注意的是生成Python绑定需要系统里有Python 3的开发头文件CMake会自动检测如果检测不到会提示找不到PythonLibs然后禁用。可以先确认一下python3-dev是否已安装。OPENCV_GENERATE_PKGCONFIGYES这个选项在Linux下很有价值开启后会在安装目录里生成opencv4.pc文件配合PKG_CONFIG_PATH环境变量就可以用pkg-config --cflags --libs opencv4的方式获取编译参数。C项目用Makefile或者简单的编译命令时非常方便。BUILD_TESTSOFF和BUILD_EXAMPLESOFF这两个是加速选项。OpenCV源码自带大量test和examples代码编译它们会显著增加编译时间而多数情况下并不需要随库一起构建这些内容。同理也可以考虑关闭BUILD_PERF_TESTS。实测关闭后编译时间能缩短大约20%~30%。2.4 配置阶段的意外提示与处理CMake配置脚本执行过程可能耗时2到10分钟不等期间会输出大量检测日志。第一次编译的话建议不要直接跳到最后的配置日志就结束花几分钟浏览一下关键模块的检测结果确认Video I/O、FFMPEG、GTK这些选项的状态是YES而不是NO。一个常见情况是某个依赖库没装好CMake检测不到但它并不会直接报错终止而是默默把对应选项设置成NO把相关功能静默禁用。比如FFmpeg依赖没安装配置过程照样正常完成但生成的OpenCV库读取不了大多数视频格式。这种静默失败比直接报错更让人头疼因为编译安装全流程都顺利直到运行时才发现功能缺失。另外在配置阶段如果看到类似下面的警告信息不用过度担心Optional dependency (libgphoto2) is disabled.这是正常的提示Opencv会自动尝试检测一些可选的附加依赖如果系统没有安装它们就会以disabled状态跳过并不会影响核心功能。真正需要担心的是那些Looking for required libraries级别的错误。3. 编译与安装流程从make到环境变量配置3.1 编译命令与编译时间参考CMake配置完成确定日志输出里没有报错后就可以正式进入编译环节了。make -j4这里的-j4参数指定编译时使用的并行任务数。理论上任务数越大编译越快但要注意内存和CPU核心数的限制。如果机器是8核16G内存用-j8一般没问题。如果内存比较紧张比如只有4G用-j4已经是上限再高的并行度很可能触发internal compiler error: Killed这种崩溃往往是因为内存耗尽导致编译器进程被系统杀掉。编译时间方面以OpenCV 4.10.0配合contrib模块为例在四核i5处理器、8G内存的机器上完整编译大概需要15到25分钟。机器核数越多时间越短。期间终端会不断滚动编译日志如果某条日志卡住超过一两分钟不动可以切到另一个终端用top查看CPU占用确认编译进程还在正常工作多数时候是某个大文件编译比较慢而已。3.2 安装命令与安装目录结构编译完成后执行make install安装过程很快通常几十秒到两三分钟。安装完成后~/opencv_410/install目录下会生成lib、include、bin、share等子目录。lib目录里存放的是编译好的动态库.so文件include目录是头文件share目录下有CMake的配置文件OpenCVConfig.cmake这个文件是后续C项目里find_package(OpenCV)能够正常工作的关键。安装完成后建议验证一下库文件是否完整find ~/opencv_410/install/lib -name *.so* | head -20正常情况下会看到libopencv_core.so、libopencv_imgproc.so、libopencv_highgui.so等一大批动态库文件。如果contrib模块编译成功还会看到libopencv_stitching.so、libopencv_aruco.so等扩展模块的库文件。3.3 环境变量配置与版本冲突问题安装完成后需要把OpenCV的库路径加入动态链接器的搜索路径。这一步很关键否则编译好的程序运行时会出现error while loading shared libraries: libopencv_core.so.410: cannot open shared object file之类的错误。环境变量配置方式echo export LD_LIBRARY_PATH~/opencv_410/install/lib:$LD_LIBRARY_PATH ~/.bashrc echo export PKG_CONFIG_PATH~/opencv_410/install/lib/pkgconfig:$PKG_CONFIG_PATH ~/.bashrc source ~/.bashrc这里要注意动态库搜索的优先级问题。如果系统里之前通过apt安装过旧版OpenCV比如/usr/lib/x86_64-linux-gnu/下已经有libopencv_core.so动态链接器通常会优先在LD_LIBRARY_PATH指定的目录中查找其次才是系统默认路径。上述配置实际上是把自定义目录的优先级提到了系统目录之前。如果希望更彻底的隔离可以在编译时就直接把CMAKE_INSTALL_PREFIX设成独立的目录。在Windows下没有LD_LIBRARY_PATH的概念对应的操作是把安装路径下的bin目录或者编译生成的bin目录添加到系统环境变量Path中。原理相同都是为了在运行时找到对应的DLL文件。3.4 C项目引用自编译OpenCV的两种方式编译好OpenCV之后C项目要正常引用有两种方式。第一种是使用CMake的find_package机制。在项目的CMakeLists.txt中set(OpenCV_DIR ~/opencv_410/install/lib/cmake/opencv4) find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) target_link_libraries(myproject ${OpenCV_LIBS})关键是set(OpenCV_DIR ...)这一行它告诉CMake去哪里找OpenCVConfig.cmake文件。如果跳过这一步CMake会在默认路径下寻找大概率找到旧版本甚至找不到。第二种是使用pkg-config方式。因为之前配置了OPENCV_GENERATE_PKGCONFIGYES可以用g -o test test.cpp $(pkg-config --cflags --libs opencv4)这种方式适合快速测试小代码片段的场景缺点是不方便移植到跨平台构建环境。4. OpenCV_contrib扩展模块与版本兼容性细节4.1 contrib模块能带来哪些具体能力opencv_contrib是OpenCV的扩展模块仓库里面包含大量官方主仓库之外的算法实现。除了前面提到的SIFT、SURF特征检测之外还有几个项目里常用的模块值得关注。aruco模块用于ArUco码检测工业视觉里的相机标定、姿态估计经常用到。face模块提供人脸识别算法LBPH、EigenFace、FisherFace注意很多人会把它跟主仓库里的objdetect模块混淆后者主要是基于Haar特征的人脸检测两者的定位完全不同。text模块做文本检测与识别是OCR工作的基础组件。xfeatures2d模块是SIFT、SURF、BRISK等经典特征算法的集合地虽然SIFT专利过期了但代码组织结构仍然保留在contrib仓库中。我这次编译时重点使用的是SIFT特征检测和ArUco码定位所以contrib模块对这次编译来说不是锦上添花而是刚需。4.2 版本匹配的隐形陷阱贡献模块的版本匹配严格程度往往很容易被忽视。OpenCV主仓库和opencv_contrib仓库的版本号必须严格一一对应下载release包时4.10.0主包必须配4.10.0的contrib包。在某些开源项目里不同版本之间互相混用可能仍然能编译通过但OpenCV这里不行配置阶段会无法通过或者编译阶段报出一堆匪夷所思的API不匹配错误。从源码包的大小也能看出一些迹象。OpenCV主仓库源码包压缩后大概80MB左右解压后接近1GB包含大量历史文档和测试数据。contrib源码包也在几十MB级别。如果下载的release包体积明显偏小比如只有几十KB大概率是下载到了错误的文件。4.3 编译contrib模块时常见的头文件缺失问题贡献模块编译时还有一个高频报错尤其是编译早期版本的contrib时更容易出现。报错信息形如fatal error: boostdesc_bgm.i: No such file or directory或者fatal error: vgg_generated_48.i: No such file or directory这些问题通常发生在从GitHub克隆或者下载的contrib源码包不完整时。这些.i文件是预生成的训练数据被存放在contrib仓库里的modules/xfeatures2d/src目录下但有时因为文件较大或者某些镜像站同步不完整导致下载的源码包中缺失这些文件。排查网站时先确认这些目录下的文件是否齐全如果确实缺失最简单的办法是回到官网重新下载release tar包不要用git克隆的方式省事。因为git稀疏检出时可能不会把所有大的数据文件都拉下来。5. 编译加速、故障排查与经验总结5.1 编译缓慢的加速技巧OpenCV核心库加上contrib模块源码规模非常庞大全部编译需要比较长的时间。除了前面提到的开启BUILD_TESTSOFF、BUILD_EXAMPLESOFF减少编译内容之外还有几个加速手段可以用。使用ccache编译缓存工具。安装后在CMake配置时加入-D CMAKE_CXX_COMPILER_LAUNCHERccache这样重复编译时相同编译单元会直接命中缓存后续增量编译速度提升非常明显。实测在频繁切换分支、反复修改CMake选项的场景下有ccache能节省一半以上的重复编译时间。关闭不必要的第三方库检测与编译。BUILD_opencv_python2、BUILD_JAVA、BUILD_opencv_java_bindings_generator这类选项如果Z世代用不上直接关掉。Java绑定模块编译耗时也不短而且在纯C项目里毫无用处。5.2 常见编译报错与排查速查表根据网上大量编译反馈以及我自己的经验将高频故障整理成速查表格供大家对照排查报错信息或现象常见原因解决办法ippicv_2021.10.0_lnx_x64_general.tgz: No such fileIPPICV依赖包下载失败CMake配置时联网拉取失败手动从此依赖的官方下载地址下载该压缩包放进~/.cache/opencv/4.x/对应目录后重新cmakefatal error: boostdesc_bgm.i: No such file or directorycontrib源码包不完整或版本不匹配重新下载对应版本的完整贡献模块tar包error: CODEC_ID_H264 was not declared in this scopeFFmpeg版本过老或不兼容升级FFmpeg相关开发库或调整WITH_FFMPEG选项cannot find -lGL缺少OpenGL相关库sudo apt install libgl1-mesa-dev libglu1-mesa-devNo package gstreamer-1.0 foundGStreamer开发包未安装安装libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev或关闭WITH_GSTREAMER编译时内存溢出被kill并行任务数过多导致内存不足降低make -j的并行数或增加交换分区Module opencv_contrib not foundOPENCV_EXTRA_MODULES_PATH路径错误确认指向的是contrib源码下的modules目录这里重点提一下ippicv下载失败的问题。OpenCV 4.10.0默认会使用Intel的IPP加速库CMake配置时它试图从一个外网地址下载预编译的ippicv压缩包。如果网络状况不稳定下载速度慢甚至超时CMake配置过程就会卡住很久甚至直接失败。解决办法是先手动下载好对应的ippicv包放到~/.cache/opencv/4.x/目录下之后重新执行CMake配置就能识别到。这一步可以离线完成不需要额外开启什么网络设置。5.3 安装完成后验证与典型调用示例编译安装完成后建议先跑一个小例子验证整个工具链是否正常。下面是一段最基础但覆盖了库引用全流程的C代码#include opencv2/opencv.hpp #include iostream int main() { cv::Mat img(480, 640, CV_8UC3, cv::Scalar(100, 100, 255)); std::cout OpenCV version: CV_VERSION std::endl; std::cout Image size: img.cols x img.rows std::endl; cv::Ptrcv::Feature2D sift cv::SIFT::create(); std::vectorcv::KeyPoint keypoints; sift-detect(img, keypoints); std::cout SIFT keypoints: keypoints.size() std::endl; return 0; }编译这段代码时用CMake方式cmake_minimum_required(VERSION 3.10) project(opencv_test) set(OpenCV_DIR ~/opencv_410/install/lib/cmake/opencv4) find_package(OpenCV REQUIRED) add_executable(opencv_test main.cpp) target_link_libraries(opencv_test ${OpenCV_LIBS})如果SIFT相关模块编译失败或者OPENCV_ENABLE_NONFREE没有开启这段代码在编译链接阶段就会报undefined reference to cv::SIFT::create()。如果编译通过了但运行时报libopencv_core.so.410: cannot open shared object file的错误对应的排查方向就是动态库搜索路径的配置。5.4 我的最终体验与几点实用建议整个过程完整走下来印象最深的几点经验值得单独记录下来。编译前尽量把依赖一次性装全不要编译到一半发现缺库再补装。看似省事实际上每次补完依赖都要重新执行CMake配置配置阶段又会触发一次耗时较长的检测流程一来一回反而更费时间。CMake配置日志值得好好保存一份。编译完成之后如果写了安装文档或者部署手册把当时配置的命令和关键日志归档起来后续在另一台机器上复现编译会顺利很多也能帮助排查版本更新的差异。如果项目比较固定建议一开始就把OpenCV做成共享库还是静态库的方向想清楚。共享库的优点是链接快、占磁盘空间小但部署到其他机器时必须带上对应的.so文件并配置好搜索路径。静态库把BUILD_SHARED_LIBS设为OFF编译产物更大但部署时只在可执行程序里打入所有依赖的代码省去了运行时各种动态库搜索的麻烦。对有独立交付需求的项目来说静态编译反而是更省心的选择。OpenCV的源码编译本身并不复杂本质上就是配置好CMake参数、处理掉依赖库版本问题、把编译流程跑通。但这个过程中积累的对构建系统、依赖关系管理的理解对之后处理其他C项目同样有帮助。希望这篇记录能帮你少走点弯路。如果你在编译中还遇到其他奇怪的报错欢迎在评论区把日志贴出来一起看。本文还有配套的精品资源点击获取