☰
Ubuntu下源码编译OpenCV 4.5.0完整流程与环境配置
2026/9/30 1:27:53 网站建设 项目流程

1. 为什么我不用apt install libopencv-dev,非要源码编译

先说一个很现实的问题:Ubuntu 20.04的apt源里其实自带OpenCV,一个sudo apt install libopencv-dev就能搞定,很多人一看这么省事就直接装了。但我建议你别这么干,至少在你打算认真用C++做视觉开发的前提下,源码编译是更值得走的一条路。

apt源里的OpenCV版本是4.2.0,跟我们要搭建的4.5.0差了三个小版本。听起来差距不大,但OpenCV从4.2到4.5之间改了很多API行为,尤其是DNN模块、相机标定相关的接口有过调整,网上很多新教程和开源项目都基于4.4以上版本写的。你用4.2去编译别人的项目,经常会出现函数签名对不上、找不到头文件这类问题,排查起来非常浪费时间。

更重要的是,apt安装的OpenCV是不带opencv_contrib扩展模块的,而contrib里有SIFT、SURF这些经典特征点算法,还有aruco、xfeatures2d、text这些实用模块。如果你后面做AR、做物体识别、做特征匹配,这些模块基本是绕不开的。虽然可以单独装libopencv-contrib-dev,但我实测下来,apt源里的contrib跟主库版本匹配有时候会有问题,不如源码编译一次搞定,版本自己把控,想开哪个模块就开哪个。

还有一点,源码编译可以自己控制优化选项。比如你想开TBB多线程加速、想开Eigen矩阵库、想把OpenCL的离线缓存打开,这些在apt包里都是默认配置,没得选。源码编译的好处就是CMake配置完全由你掌控,编译出来的是“为你这台机器定制”的库,性能上通常会更好一点。

当然,源码编译也有代价,最大的代价就是时间和磁盘空间。完整编译一次4.5.0大概需要30到60分钟,取决于你的CPU核心数和内存大小,安装完占用的空间大约1.5GB到2GB。如果你的项目只是简单调个接口、跑个demo,那apt安装确实更省事;但如果你确定要在OpenCV上做一段时间开发,那今天这篇完整流程就非常有参考价值了。

我当前使用的系统环境是Ubuntu 20.04.6 LTS,内核版本5.15,GCC版本9.3.0,CMake版本3.16.3,这些是Ubuntu 20.04默认软件源里的版本。OpenCV 4.5.0是2020年10月发布的版本,跟这套工具链的兼容性非常稳定,实测编译过程中没有遇到任何编译器版本相关的问题。

2. 编译前的依赖准备:缺了这些库,后面全是坑

很多人编译OpenCV失败,不是CMake配置写错了,而是系统里缺依赖库。OpenCV的源码编译虽然会自己下载一些第三方库,但大部分底层的图像编解码、视频处理、GUI支持库都是依赖系统自带的。缺了某个库,CMake配置阶段通常不会报错,顶多是在输出的表格里显示某个模块为NO,但等到你真正运行时才发现功能缺失,这才是最头疼的。

2.1 基础工具链:build-essential和cmake

第一个要装的是编译工具链,这个没什么好说的,GCC和G++是编译OpenCV源码的基础,CMake是构建系统的核心。

sudo apt update sudo apt install -y build-essential cmake git pkg-config

这里我特别提一下pkg-config,很多人容易忽略它。OpenCV编译完成后,我们需要通过pkg-config来让编译器自动找到OpenCV的头文件和库文件路径。如果没有安装pkg-config,后面的环境配置会非常麻烦,而且在CMake中find_package(OpenCV)的查找过程也会受到影响。

2.2 图像编解码库:JPEG、PNG、TIFF

OpenCV处理图像文件时,需要依赖系统的编解码库。虽然OpenCV内部自带了一些基础的编解码实现,但为了最佳兼容性和性能,官方推荐安装系统的开发库。

sudo apt install -y libjpeg-dev libpng-dev libtiff-dev

这里有个细节值得说一下:libjpeg-dev和libpng-dev是几乎所有图像处理项目的基础,但libtiff-dev经常被忽略。如果你的项目需要处理卫星影像、医学图像这种高深度图像格式,TIFF支持是必须的。我当初第一次编译OpenCV时就没装TIFF库,结果CMake配置阶段输出显示TIFF: NO,我也没当回事,直到后来用cv::imread读一张.tif格式的16位深度图像,读出来全是黑的,排查了好久才发现是因为没装TIFF支持。

2.3 视频处理库:FFmpeg全家桶

视频读写是OpenCV的核心功能之一,尤其是在做视频分析、摄像头采集这类项目时。OpenCV通过FFmpeg来实现视频文件的解码和编码,所以FFmpeg相关的开发库必须装齐。

sudo apt install -y libavcodec-dev libavformat-dev libswscale-dev libv4l-dev libxvidcore-dev libx264-dev

我建议把这几个库一起装掉,不要只装libavcodec-dev和libavformat-dev。特别说一下libx264-dev,如果缺了它,OpenCV的VideoWriter在写MP4格式视频时会提示找不到对应的编码器,运行时会直接抛异常。而且H.264编码是目前最通用的视频编码格式,不装的话视频处理功能等于废了一半。

另外libv4l-dev是Video4Linux的开发库,这个库关系到OpenCV能否通过V4L2接口访问USB摄像头。如果你之后要做树莓派或者Linux工控机上的摄像头采集,这个库是必须的。

2.4 GUI与显示依赖:GTK和Canberra

OpenCV的highgui模块负责窗口显示、鼠标键盘事件处理,它有两种后端可以选择:GTK和Qt。Ubuntu桌面版默认使用GTK,所以我这里选择的是GTK3。

sudo apt install -y libgtk-3-dev libcanberra-gtk-module

这里有一个我踩过的坑:只装libgtk-3-dev,不装libcanberra-gtk-module,编译能通过,cv::imshow显示窗口也没问题,但是运行时会提示Gtk-WARNING **: 无法找到主题引擎,窗口打开后还会伴随着一个警告声音。虽然不影响功能,但每次都刷这个警告真的很烦人。libcanberra-gtk-module就是用来解决这个声音和主题问题的。

CMake配置阶段会检测GTK版本,如果检测到GTK3,在输出表格中会显示GUI: GTK+ 3.x。如果你在配置输出里看到的是GTK+: NO,那编译出来的OpenCV虽然能用但无法显示图像窗口,这个问题后面会讲怎么排查。

2.5 数学与线性代数库:ATLAS、LAPACK、Eigen

OpenCV在很多算法中需要用到矩阵运算,虽然它自己实现了部分线性代数功能,但调用系统优化过的BLAS/LAPACK库可以获得更好的性能。

sudo apt install -y libatlas-base-dev liblapacke-dev libeigen3-dev

这里libatlas-base-dev是ATLAS的BLAS实现,liblapacke-dev提供了LAPACK的C接口,这两个主要用于优化矩阵运算性能。libeigen3-dev是Eigen模板库,OpenCV在calibrateCamera、findFundamentalMat等几何计算中会用到Eigen来进行矩阵运算。

2.6 Python开发库(可选,建议装)

虽然我们主打C++环境,但OpenCV编译时如果检测到Python3的开发环境,会自动生成Python绑定。这其实是个额外福利,同一个编译版本既能给C++用,也能给Python用,两边版本完全一致,不会出现Python环境和C++环境OpenCV版本不一致导致的行为差异。

sudo apt install -y python3-dev python3-numpy python3-pip

如果你确定自己完全不需要Python接口,可以在后面CMake配置时用-D BUILD_opencv_python3=OFF来关闭,但如果你想留个后路,建议保留这个功能。我自己的习惯是保留的,因为有时候快速验证一个算法效果,用Python写demo比C++快得多。

依赖库装完之后,我建议先重启一下终端或者重新登录,确保环境变量生效,避免后面编译时出现奇怪的问题。

3. 源码下载与CMake配置:几个关键参数的意义

依赖库准备好之后,就是下载OpenCV源码和配置CMake了。这个阶段决定了你的OpenCV最终长出什么样,所以每一步都值得认真对待。

3.1 下载主库和contrib扩展库

OpenCV的源码托管在GitHub上,我使用的是官方4.5.0稳定版。直接clone或者下载tag包都行,我习惯用git clone,方便以后切分支。

cd ~ mkdir -p opencv_build && cd opencv_build git clone -b 4.5.0 --depth 1 https://github.com/opencv/opencv.git git clone -b 4.5.0 --depth 1 https://github.com/opencv/opencv_contrib.git

如果你没有安装git,或者直接用浏览器下载zip包也可以,但记得主库和contrib的版本必须保持一致,4.5.0的主库对应4.5.0的contrib。版本不对应会出现模块加载失败或编译错误,这个问题在GitHub的issue区经常有人遇到,本质上就是版本不匹配导致的。

两个源码目录要放在同一级目录下,比如都放在~/opencv_build里。这样后面CMake配置时OPENCV_EXTRA_MODULES_PATH的参数路径就很直观。

3.2 CMake配置:先看参数再看命令

在跑CMake命令之前,我先解释一下几个关键参数的作用,这样你后面自己调整时也知道该改什么。

cd opencv && mkdir -p build && cd build cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=~/opencv_build/opencv_contrib/modules \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D BUILD_EXAMPLES=OFF \ -D WITH_TBB=ON \ -D WITH_EIGEN=ON \ -D WITH_V4L=ON \ -D OPENCV_ENABLE_NONFREE=ON \ ..

逐个说一下这些参数的含义:

  • CMAKE_BUILD_TYPE=RELEASE:编译Release版本,编译器会开启O3优化,运行性能最好。OpenCV没有Debug版本调试的硬需求,正式开发都用Release。
  • CMAKE_INSTALL_PREFIX=/usr/local:指定安装路径,默认就是/usr/local,头文件装到/usr/local/include,库文件装到/usr/local/lib。
  • OPENCV_EXTRA_MODULES_PATH:指定contrib模块的路径,这个就是刚才下载的扩展模块目录。
  • OPENCV_GENERATE_PKGCONFIG=ON:这个参数非常关键。OpenCV 4.x版本默认不再生成opencv4.pc文件,但是C++开发中我们经常需要用pkg-config来获取编译参数。如果不把这个选项打开,后面用pkg-config --cflags --libs opencv4时会提示找不到文件,还得手动配置环境变量,非常麻烦。
  • BUILD_TESTS=OFF和BUILD_PERF_TESTS=OFF:关闭测试模块和性能测试模块。这两个模块编译非常耗时,而且对开发没有直接用处,强烈建议关掉。我做过对比,开和不开的编译时间能差15到20分钟。
  • WITH_TBB=ON:启用Intel TBB多线程库,OpenCV的并行计算框架会使用TBB来加速,在多核CPU上效果明显。这个依赖需要额外安装,不过Ubuntu仓库里有现成的包。
sudo apt install -y libtbb-dev
  • WITH_EIGEN=ON:启用Eigen矩阵库,主要在几何计算和相机标定模块中使用,刚才依赖阶段已经安装过了。
  • WITH_V4L=ON:启动V4L2接口支持,访问USB摄像头必开。
  • OPENCV_ENABLE_NONFREE=ON:这个参数比较特殊,SIFT、SURF这些算法因为专利原因被归为non-free模块,默认是编译不了的。如果你需要使用这些特征点算法,必须把这个参数打开。

配置完成后,CMake会在终端输出一份非常详细的配置报告,里面包含所有模块的启停状态。我建议你花半分钟扫一遍关键项,确认一下GUI: GTK+ 3.x、Video I/O: FFMPEG、TIFF: YES这些都已启用。如果某个模块显示NO,说明对应的系统依赖库没装好,此时不要急着编译,先把依赖补齐再重新CMake,不然编译完了功能还是缺失的。

另外提一个细节:CMake配置阶段会联网下载一些依赖文件,比如ippicv这种Intel预编译的二进制包。如果你的网络状况不好,下载可能会很慢甚至失败。如果卡在下载阶段,可以多试几次或者手动下载放到指定缓存目录,这一步对国内网络环境是一个常见的卡点。

4. make编译的体能考验:内存管理、swap与时长预判

CMake配置完成后,输出了一堆编译指令,真正的考验才刚开始。你用make命令编译OpenCV,考验的不仅是CPU性能,还包括内存够不够用。

4.1 选择合适的并行编译参数

make支持-j参数来指定并行编译的任务数,最直接的做法是把它设成CPU核心数:

make -j$(nproc)

这个命令会自动获取你的CPU逻辑核心数,然后用这个数量并行编译。比如8核16线程的CPU,nproc返回16,make就会同时跑16个编译任务。

但这里有个非常大的坑:并行编译任务开的越多,内存占用就越高。OpenCV每个编译任务大约需要1GB内存,如果你的是8GB内存的机器,开16个并行任务,内存很容易被吃满,然后触发系统OOM Killer,编译进程会被直接杀掉。轻则某个.o文件编译失败,重则整个构建系统崩溃,你还得重新make。

所以我的建议是:内存16GB以上,可以放心用make -j$(nproc);内存8GB,建议用make -j4;内存4GB的机器,老老实实用make -j2。编译慢一点没问题,总比编译到一半崩溃要强。

有一个小技巧,如果你想确认自己的机器有多少内存,可以用free -h查看,不要只看CPU核心数就盲目开并行。

4.2 swap空间不足的问题

如果你的机器内存确实很小,比如4GB或8GB,而你又想加快编译速度,可以临时增加swap空间。这个做法我自己试过,效果立竿见影。

sudo fallocate -l 4G /swapfile sudo chmod 600 /swapfile sudo mkswap /swapfile sudo swapon /swapfile

这样临时创建4GB的swap空间,相当于给编译过程增加了4GB的“内存额度”。编译完成后可以留着,也可以执行sudo swapoff /swapfile && sudo rm /swapfile删掉。

但我还是要提醒一句:增加swap只是治标不治本,如果编译任务并行数太多,系统在swap和物理内存之间频繁换页,反而会拖慢编译速度。最稳妥的做法就是降低-j参数,让每个编译任务稳定吃满内存即可。

4.3 编译时间的预判与控制

编译时间受CPU性能影响非常大。我在一台i7-9700K(8核8线程)、16GB内存的机器上,make -j8编译OpenCV 4.5.0大概需要25到35分钟,编译日志滚动得飞快。在笔记本的i5-8250U上,make -j4大概需要50分钟左右,风扇会一直高速运转。

编译过程中会看到大量的[ XX%] Building CXX object modules/core/CMakeFiles/opencv_core.dir/src/xxx.cpp.o这类日志,进度从0%到100%逐步推进。第一次编译到100%时那种感觉还是挺爽的,但也不要太心急,编译过程中偶尔卡在某个文件上几秒钟是正常现象,尤其是一些模板实例化特别多的文件,比如core模块里的matrix_decomp.cpp,单文件编译时间可能超过一分钟。

这里有个经验分享:如果你中途发现CMake配置有问题,不要等编译完,直接Ctrl+C停掉,删掉build目录重新配置就行。OpenCV的构建系统不支持改CMake参数后增量编译,改了参数后很多源文件会被强制重新编译,时间成本反而更高。

4.4 编译完成后的安装

编译进度到100%后,执行安装命令:

sudo make install

sudomake install```正确写法是sudo make install,中间有空格。这一步会把头文件复制到/usr/local/include/opencv4,把编译好的.so库文件复制到/usr/local/lib,同时会把opencv4.pc文件放到/usr/local/lib/pkgconfig`目录下。

安装过程一般一两分钟就完成了,如果终端没有任何报错,说明OpenCV已经成功装到系统里了。

最后执行一下配置动态库,让系统能找到刚刚安装的OpenCV共享库:

sudo ldconfig

ldconfig会更新系统的动态链接库缓存,告诉系统新装到/usr/local/lib的.so文件可以被程序引用。这一步如果不做,运行OpenCV程序时会提示error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file: No such file or directory。

5. 环境配置的最后一公里:pkg-config、库路径与OpenCV_DIR

编译安装完成不等于环境搭好了,还差最后一步:让系统能够顺利找到OpenCV的头文件和库文件。这一步配置不好,你写C++代码时即便#include <opencv2/opencv.hpp>了,编译器也不知道去哪儿找这些头文件。

5.1 使用pkg-config验证安装

如果你在CMake配置时像我一样开启了OPENCV_GENERATE_PKGCONFIG=ON,那么安装后可以执行:

pkg-config --modversion opencv4

如果返回4.5.0,说明pkg-config已经能识别OpenCV了。再执行一下:

pkg-config --cflags --libs opencv4

你会看到输出的编译参数,类似这样:

-I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_dnn -lopencv_highgui -lopencv_ml -lopencv_objdetect -lopencv_photo -lopencv_stitching -lopencv_video -lopencv_calib3d -lopencv_features2d -lopencv_flann -lopencv_videoio -lopencv_imgcodecs -lopencv_imgproc -lopencv_core

有了这些参数,你后续编译C++程序时就不需要手动指定一堆-I和-l参数了,直接用pkg-config引用即可。

5.2 手动配置PKG_CONFIG_PATH

如果你在pkg-config --modversion opencv4时报错提示找不到opencv4.pc文件,先确认一下这个文件是否存在:

ls /usr/local/lib/pkgconfig/opencv4.pc

如果文件存在,说明pkg-config默认没有搜索这个路径。此时需要手动添加环境变量:

export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig:$PKG_CONFIG_PATH

为了永久生效,把这行加到~/.bashrc文件末尾,然后source ~/.bashrc。

5.3 配置OpenCV_DIR供CMake查找

现在很多C++项目使用CMake构建,CMake通过find_package(OpenCV REQUIRED)来查找OpenCV,查找时依赖的就是OpenCV_DIR这个变量,它指向包含OpenCVConfig.cmake文件的目录。

OpenCV安装后,OpenCVConfig.cmake文件位于/usr/local/lib/cmake/opencv4目录下(某些版本在/usr/local/share/OpenCV下)。在CMakeLists.txt中,我们通常这样写:

find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) add_executable(my_app main.cpp) target_link_libraries(my_app ${OpenCV_LIBS})

如果CMake配置时报错找不到OpenCV,可以在CMakeLists.txt中显式指定:

set(OpenCV_DIR /usr/local/lib/cmake/opencv4)

或者运行时传参:

cmake -DOpenCV_DIR=/usr/local/lib/cmake/opencv4 ..

这里有个经验之谈:不要试图手动设置OpenCV_INCLUDE_DIRS和OpenCV_LIBS,直接依赖于find_package返回的变量即可。因为find_package(OpenCV)会自动检测头文件和库文件路径,包括库文件之间的依赖关系,手动指定容易漏掉链接库,导致编译时各种undefined reference。

6. 编写测试程序验证整个工具链

环境搭建完成,写个简单的程序验证一下是否运转正常。这一节我会给出一个相对完整的测试流程,从单文件编译到CMake编译都覆盖到,确保你的环境真的“能跑”。

6.1 测试程序:读取一张图片并显示

先找一张图片放到测试目录里,比如test.jpg,然后写一个最简单的程序:读取这张图片,打印图像尺寸信息,并用窗口显示出来。

#include <opencv2/opencv.hpp> #include <iostream> int main(int argc, char** argv) { if (argc < 2) { std::cerr << "Usage: ./display_image <image_path>" << std::endl; return -1; } cv::Mat image = cv::imread(argv[1], cv::IMREAD_COLOR); if (image.empty()) { std::cerr << "Failed to load image: " << argv[1] << std::endl; return -1; } std::cout << "Image loaded. Size: " << image.cols << "x" << image.rows << ", channels: " << image.channels() << std::endl; cv::imshow("Display Image", image); cv::waitKey(0); cv::destroyAllWindows(); return 0; }

这个程序虽然简单,但涵盖了OpenCV中最核心的三个操作:cv::Mat作为图像数据结构、cv::imread读图、cv::imshow显示窗口。如果这三步都能正常运行,说明你的环境基本没有问题。

6.2 直接用g++编译

不依赖任何构建工具,直接用g++编译最直观:

g++ display_image.cpp -o display_image $(pkg-config --cflags --libs opencv4)

编译成功后,运行:

./display_image test.jpg

如果弹出一个窗口显示了图片,控制台打印出图像尺寸,说明你的OpenCV环境完全正常。

这里有个编译注意事项:$(pkg-config --cflags --libs opencv4)一定要放在源文件后面。很多刚学C++的朋友习惯写成g++ $(pkg-config --cflags --libs opencv4) display_image.o -o app,这会导致链接阶段找不到OpenCV的函数定义,报一堆undefined reference的错误。GCC的链接顺序是从左到右扫描的,库必须放在引用它的源文件或目标文件之后。

6.3 用CMake写正式的构建脚本

单文件用g++编译没问题,但如果项目文件多了,还是老老实实用CMake。下面是一个最简的CMakeLists.txt:

cmake_minimum_required(VERSION 3.10) project(OpenCVTest) set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(OpenCV REQUIRED) add_executable(display_image display_image.cpp) target_link_libraries(display_image ${OpenCV_LIBS})

编译方式:

mkdir -p build && cd build cmake .. make ./display_image ../test.jpg

如果你的系统中OpenCV_DIR查找没问题,这套流程应该是丝滑通过。如果报错找不到OpenCV,就在CMakeLists.txt里加上set(OpenCV_DIR /usr/local/lib/cmake/opencv4),或者指定绝对路径,再重新配置。

6.4 验证扩展模块是否生效

前面我们编译了contrib扩展模块,现在验证一下SIFT特征点算法能不能用。写一个简单的测试程序:

#include <opencv2/opencv.hpp> #include <opencv2/xfeatures2d.hpp> #include <iostream> int main() { cv::Mat image = cv::Mat::zeros(100, 100, CV_8UC1); auto sift = cv::SIFT::create(); std::vector<cv::KeyPoint> keypoints; sift->detect(image, keypoints); std::cout << "SIFT keypoints detected: " << keypoints.size() << std::endl; return 0; }

编译运行:

g++ test_sift.cpp -o test_sift $(pkg-config --cflags --libs opencv4) ./test_sift

如果输出SIFT keypoints detected: 0,说明SIFT模块正常加载。如果编译时报错找不到xfeatures2d.hpp,说明contrib模块没有编译成功,需要回到CMake配置阶段检查OPENCV_EXTRA_MODULES_PATH参数。

7. 运行时常见报错与我的排查链路

环境搭好、第一个程序跑通之后,开发过程中大概率会遇到各种运行时报错。下面这几个是我在OpenCV C++开发中经常遇到的,也好几个是网上提问频率很高的问题。我把自己在实际排查过程中的思路写出来,你遇到了可以照着查。

7.1 error while loading shared libraries

运行程序时提示:

error while loading shared libraries: libopencv_core.so.4.5: cannot open shared object file: No such file or directory

这个报错的意思是系统在运行程序时找不到OpenCV的动态链接库。原因就是安装后没有执行sudo ldconfig,或者OpenCV不是安装在系统默认搜索路径下。

排查链路:

ldconfig -p | grep opencv

如果输出为空,说明系统缓存里没有OpenCV库。再检查库文件是否存在:

ls /usr/local/lib/libopencv_core.so*

如果文件存在,立刻执行sudo ldconfig,再运行程序。如果还是报错,确认/usr/local/lib是否在/etc/ld.so.conf.d/的搜索路径里,必要时在/etc/ld.so.conf.d/下新建一个opencv.conf文件,内容是/usr/local/lib,然后重新sudo ldconfig。

7.2 fatal error: opencv2/opencv.hpp: No such file or directory

编译时提示找不到头文件,说明编译器不知道OpenCV头文件在哪。

排查链路:

ls /usr/local/include/opencv4/opencv2/opencv.hpp

确认头文件存在后,检查编译命令里的-I参数。如果用pkg-config,重新执行pkg-config --cflags opencv4确认是否输出-I/usr/local/include/opencv4。如果pkg-config里没有,极有可能是PKG_CONFIG_PATH没配好,参考前面第三节的设置方式。

还有一个容易被忽略的细节:头文件路径是/usr/local/include/opencv4,不是/usr/local/include。这意味着在代码中#include <opencv2/opencv.hpp>是正确的写法,但编译参数必须加上-I/usr/local/include/opencv4。有些教程给你配的是-I/usr/local/include,这种情况下编译器只能找到opencv2目录的上级路径,还是报找不到头文件。

7.3 undefined reference to cv::imread

编译到了链接阶段,报一堆undefined reference to cv::xxx错误。

这个问题的核心是链接阶段少了库文件,或者库文件顺序不对。先说顺序:在g++命令行中,库文件参数-lopencv_core等必须放在源文件(或.o文件)之后。GCC的链接器是从左到右扫描的,如果前面的目标文件引用了后面的库中的符号,链接器才能找得到。

再说库文件:$(pkg-config --libs opencv4)输出的是一大串-lopencv_xxx,如果输出为空,说明pkg-config有问题,回到上一步排查。

7.4 imshow窗口正常打开,但显示全黑或报GTK警告

窗口正常弹出来了,但显示的内容是黑的,或者在终端刷一堆GTK警告。

如果是GTK警告,参考前面装libcanberra-gtk-module来解决。如果是显示全黑,先检查一下cv::imread是不是返回了空图像。这段代码就很有代表性:

cv::Mat img = cv::imread("test.png"); if (img.empty()) { std::cerr << "Failed to load image" << std::endl; return -1; }

为空的原因通常是图像路径不对,或者图像格式缺少对应的编解码库。比如你没装libpng-dev,那么读取PNG格式时颜色通道可能异常或者读取失败。用file test.png查看图片的真实格式,再检查编译时CMake配置报告里PNG: YES/NO。

有一个很常见的迷惑现象:程序读取一张照片,用cv::imshow显示出来,窗口显示一切正常,但保存成JPEG后用图片查看器打开发现旋转了90度。这是因为现代手机和相机拍摄的照片会带有EXIF方向信息,OpenCV默认是不处理EXIF方向的。如果你想自动修正方向,需要额外写代码解析EXIF,或者用cv::rotate手动旋转。

7.5 摄像头打不开或打开后一片黑

用VideoCapture打开USB摄像头,常见情况有两种:cap.open(0)返回false且打不开,或者能打开但读出的帧全黑。

先看这个排查链路:

lsusb

确认摄像头被系统识别后,再看看/dev/video0是否存在:

ls /dev/video*

如果/dev/video0存在但权限不够,通常的表现是open失败。把你当前用户加入video组:

sudo usermod -a -G video $USER

然后注销重新登录。

如果权限没问题但还是打不开,检查驱动支持。很多免驱UVC摄像头在Ubuntu下是即插即用的,但也有一些老的摄像头需要专用驱动。这时可以先跑一下Cheese(Ubuntu自带的摄像头应用)来测试摄像头本身是否可用,如果Cheese能显示画面,说明OpenCV层面的配置有问题,重点检查CMake配置报告中的V4L/V4L2: YES/NO。

全黑的问题通常出在摄像头没有正确曝光或者自动白平衡还没稳定,可以尝试打开后用cap.set(cv::CAP_PROP_FRAME_WIDTH, 640)和cap.set(cv::CAP_PROP_FRAME_HEIGHT, 480)设置一个较低的分辨率,有些摄像头在高分辨率下会出现帧率过低导致读帧超时。

8. 进阶建议:版本管理、卸载清理和日常使用小技巧

环境搭好之后,长期开发过程中还有一些细节值得注意。这些内容官方文档不会写,但实际开发中确实遇到的频率比较高。

8.1 管理系统里同时存在的多个OpenCV版本

如果你之前用apt装过OpenCV 4.2,这次又用源码编译安装了4.5.0,系统里会有两套OpenCV并存。apt版本的头文件在/usr/include/opencv4,源码装的在/usr/local/include/opencv4;库文件分别在/usr/lib/x86_64-linux-gnu/和/usr/local/lib。

默认情况下,编译器搜索头文件的顺序是/usr/local/include在前,/usr/include在后,所以源码编译的4.5.0会优先生效。ld链接器搜索库文件的顺序也类似,/usr/local/lib优先于/usr/lib。所以大多数场景下,你用的就是新编译的4.5.0。

如果你想切换回apt版本,编译时指定:

g++ main.cpp -I/usr/include/opencv4 -L/usr/lib/x86_64-linux-gnu -lopencv_core ...

但不建议你这么折腾,容易把自己搞懵。最稳妥的做法是:确定要源码编译,就彻底卸载apt版本。

sudo apt remove libopencv-dev libopencv-contrib-dev

如果你不确定系统中哪些包与OpenCV相关,用dpkg -l | grep opencv查看,把相关的全部移除。

8.2 卸载源码安装的OpenCV

如果需要清理源码编译安装的OpenCV,进入之前配置时的build目录执行:

cd ~/opencv_build/opencv/build sudo make uninstall

如果build目录已经不在了,也可以手动删除安装的文件:

sudo rm -rf /usr/local/include/opencv4 sudo rm -rf /usr/local/lib/cmake/opencv4 sudo rm -rf /usr/local/lib/pkgconfig/opencv4.pc sudo rm -f /usr/local/lib/libopencv_* sudo ldconfig

注意删除libopencv_*时要注意,如果系统里还有其他软件依赖OpenCV,删掉后它们也会运行不了。这个命令我建议你在确认无误后再执行。

8.3 把OpenCV编译命令封装成脚本

如果你需要在多台Ubuntu机器上搭建相同的环境,每次手动敲几十条命令很烦。把整个过程写成一个shell脚本是个不错的选择,也方便团队内部共享。大致骨架如下:

#!/bin/bash set -e echo "[INFO] Installing dependencies..." sudo apt update sudo apt install -y build-essential cmake git pkg-config \ libjpeg-dev libpng-dev libtiff-dev \ libavcodec-dev libavformat-dev libswscale-dev libv4l-dev \ libxvidcore-dev libx264-dev \ libgtk-3-dev libcanberra-gtk-module \ libatlas-base-dev liblapacke-dev libeigen3-dev \ libtbb-dev python3-dev python3-numpy echo "[INFO] Downloading OpenCV 4.5.0..." mkdir -p ~/opencv_build && cd ~/opencv_build git clone -b 4.5.0 --depth 1 https://github.com/opencv/opencv.git git clone -b 4.5.0 --depth 1 https://github.com/opencv/opencv_contrib.git echo "[INFO] Configuring..." cd opencv && mkdir -p build && cd build cmake -D CMAKE_BUILD_TYPE=RELEASE \ -D CMAKE_INSTALL_PREFIX=/usr/local \ -D OPENCV_EXTRA_MODULES_PATH=~/opencv_build/opencv_contrib/modules \ -D OPENCV_GENERATE_PKGCONFIG=ON \ -D BUILD_TESTS=OFF \ -D BUILD_PERF_TESTS=OFF \ -D WITH_TBB=ON \ -D WITH_EIGEN=ON \ -D WITH_V4L=ON \ -D OPENCV_ENABLE_NONFREE=ON \ .. echo "[INFO] Building..." make -j$(nproc) echo "[INFO] Installing..." sudo make install sudo ldconfig echo "[INFO] Done. OpenCV 4.5.0 installed."

脚本中使用set -e确保任何一步出错就立即停止,避免后面的步骤基于错误状态继续执行,最后可以省去很多由于“上次没装成功,这次接着跑”导致的诡异问题。

8.4 用VSCode提升C++开发体验

环境本身搭好了,开发工具也值得花点时间配置。如果你习惯用Visual Studio Code,装上C/C++扩展插件后,在c_cpp_properties.json里指定:

{ "configurations": [ { "name": "Linux", "includePath": [ "${workspaceFolder}/**", "/usr/local/include/opencv4" ], "defines": [], "compilerPath": "/usr/bin/g++", "cStandard": "c11", "cppStandard": "c++14", "intelliSenseMode": "linux-gcc-x64" } ], "version": 4 }

这样VSCode的智能提示就能正确识别#include <opencv2/opencv.hpp>,代码补全和错误检查都可以正常使用了。这个配置我每次搭完环境都会顺手配上,因为如果没有includePath,VSCode里所有OpenCV相关代码都会标红波浪线,写代码的时候非常干扰注意力。

另外推荐在VSCode里配置一下CMake Tools插件,配合上面给的CMakeLists.txt模板,按F7就能直接编译,F5调试,比在终端里手工敲命令高效很多。

最后再说一个小技巧:OpenCV 4.5.0在Release模式下编译的程序,二进制体积会比较大,这是正常的,因为cv::Mat这类模板类在很多地方会实例化出大量代码。如果最终部署时对体积敏感,可以在CMake中加入-DCMAKE_BUILD_TYPE=MinSizeRel,或者使用strip命令裁剪符号表,能显著减小可执行文件体积。不过对于学习和开发阶段,这个优化可以等真正做产品时再考虑。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询