ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Linux下OpenCV 4.5.5预编译包:解压即用与C++工程配置

Linux下OpenCV 4.5.5预编译包:解压即用与C++工程配置 简介这是一份面向Linux平台C开发者的OpenCV 4.5.5预编译包在Ubuntu 21.04 64位系统下完成编译并验证可用特别适合不想从源码折腾编译、希望直接集成OpenCV做图像处理或视觉项目的开发者。压缩包共1426个文件约49.18MB包含489个头文件、动态库文件如libopencv_core、libopencv_imgproc等、大量示例源码与Python脚本以及丰富的测试图片、模型文件和xml/yml配置文件解压后即可在CMake工程中通过设置OpenCV_DIR快速引用。相比从源码编译动辄几小时且容易踩坑这份资源能显著节省环境配置时间。已有750人浏览学习配套的CMakeLists.txt使用说明清晰适合初学OpenCV的在校生和需要快速交付的工程师直接上手。 跟你说个真实经历。最早在Linux服务器上编译OpenCV我整整耗了一整天cmake配置好ippicv下载超时换源重下依赖齐了CPU编译又烤了一个多小时。等编完才发现没开CUDA只能再来一遍。从那时候起我就养成一个习惯——不是每个项目都需要从源码编译。我自己维护了一个OpenCV 4.5.5在Linux下编译好的包解压之后配好环境变量C工程里直接就能用。这篇文章就把这套“解压即用”的完整流程和排查经验写出来给不想在编译上浪费时间的人省点功夫。适合已经会用C、但每次搭OpenCV环境都要折腾好几个小时的开发者也适合需要在服务器上快速部署图像处理服务的场景。1. 为什么我强烈建议使用预编译OpenCV包1.1 源码编译为什么那么折腾想完全理解这套包的价值得先明白源码编译的坑到底在哪。最劝退的是时间。默认配置编译OpenCV 4.5.5在4核的机器上跑全量模块通常一小时起步如果还勾了dnn、cuda、contrib时间翻倍都有可能。编译过程中你基本干不了别的CPU风扇全程高转速出门买个咖啡回来都不一定编完。第二个坑是依赖。OpenCV依赖的可视化库、图像编解码库非常多系统里缺一个编译时不会立刻报错等编出来发现imread读不了png、highgui起不来窗口这种“半残”库最坑。你得回头重新查依赖、重新编译一来一回又是半天。我之前在纯净容器里编过一次缺libpng、libjpeg编完以后所有图片读写接口全部静默失败排查了很长时间才找到根因。第三个坑是版本污染。系统里可能已经存在apt装的OpenCV版本通常是4.2左右你再手编一个4.5.5装到/usr/local两个版本的动态库同时躺在系统里。动态库搜索顺序一乱程序就可能链接到旧的so上报出一堆莫名其妙的符号错误。这种问题比编译错误更难查因为报错信息不会直接告诉你“你装了两个OpenCV”。还有一个很关键的知识点OpenCV官方其实没有发布Linux下的预编译二进制包Windows平台倒是提供了安装程序Linux用户拿到的永远是源码。所以在Linux上别人分享的预编译包本身就是稀缺资源它的价值不只是省一次编译还省了后面调试环境的无数时间。1.2 为什么版本锁死4.5.5我自己维护这份包的时间点在4.5.5已经相当成熟。4.5.5属于4.x这条稳定线的中后段API稳定性经过大量验证网上的踩坑案例、源代码分析、技术博客都非常多遇到问题随便一搜就能找到答案。它支持C11和团队现有代码的兼容性很好。4.x的核心API从4.1到4.6变化其实不大你用4.5.5写的代码后面迁移到4.8或者5.x也相对平滑。另外一个容易忽略的点预编译包和系统的glibc版本强相关。编译器越新编出来的二进制对系统运行库的要求通常越高。选择4.5.5这个时期常见的GCC 9工具链编出来的库在Ubuntu 18.04、20.04、Debian 10/11这些常见发行版上都能跑向下兼容性最好。这也是为什么发布预编译包时版本和编译环境都要写清楚。如果发布者用很新的GCC 12编你系统里的libstdc版本不够老运行时就可能报GLIBCXX相关错误这个后面会详细讲。1.3 这套包适合谁不适合谁先说不适合的免得你走弯路。如果你的项目需要定制编译选项比如要开CUDA、要编contrib模块、要集成自研第三方库那么预编译包满足不了你这种情况下源码编译是唯一选择。另外如果你的目标机器是ARM架构或者系统的glibc特别老建议也老老实实自己编。适合的场景则很明确想快速跑图像处理demo、验证算法效果的C开发者在服务器上没有sudo权限、只能把环境装到用户目录的部署场景团队内部需要统一OpenCV版本避免每个人编译的库行为不一致。我个人一直以来的观点是预编译包解决的是“快速跑起来”的问题源码编译解决的是“完全掌控”的问题。前期图快用预编译包后期要上生产再回头研究编译参数完全不冲突。2. 解压之后包里面到底是什么2.1 整体目录结构与各目录的作用打开包之后你应该会看到类似下面的结构opencv-4.5.5/ ├── bin/ ├── include/opencv2/ ├── lib/ │ ├── libopencv_core.so.4.5.5 │ ├── libopencv_core.so │ ├── libopencv_imgproc.so.4.5.5 │ ├── libopencv_imgproc.so │ ├── libopencv_highgui.so.4.5.5 │ ├── libopencv_highgui.so │ ├── libopencv_imgcodecs.so.4.5.5 │ ├── libopencv_imgcodecs.so │ └── pkgconfig/ │ └── opencv4.pc └── share/OpenCV/ ├── OpenCVConfig.cmake └── ...bin目录下有opencv_version等工具用来验证版本include/opencv2是头文件编译期必须lib目录里是所有功能模块的so库。注意lib里同一份库会出现三个文件名比如libopencv_core.so.4.5.5是真正的库文件libopencv_core.so.405是SONAME链接libopencv_core.so是编译期链接用的不带版本号软链接。CMake和g在链接时找的是最后一个如果打包时没保留软链接编译阶段会直接报找不到库。share/OpenCV下面的OpenCVConfig.cmake是CMake识别包的关键这个文件决定了OpenCV_DIR应该指向哪里。lib/pkgconfig/opencv4.pc是给pkg-config用的说明文件里面记录了cflags和libs路径。一句话总结include是给编译器看lib是给链接器和运行器用share/OpenCV是给CMake和pkg-config用的。三者缺一个工程就配不起来。2.2 动手之前先检查系统环境拿到包的第一件事不是写代码而是确认运行环境没问题这一步能帮你省掉后面80%的排查时间。确认架构运行uname -m输出x86_64才匹配。确认编译器运行g --version如果版本低于GCC 7后面要注意GLIBCXX兼容性。检查动态库依赖进入解压目录后执行ldd lib/libopencv_core.so.4.5.5 | grep not found看看有没有缺失的系统库。如果ldd显示缺少东西需要先安装底层的系统运行库比如sudo apt update sudo apt install -y libgl1 libglib2.0-0 libgomp1 libpng-dev libjpeg-dev zlib1g-dev这些库是图像编解码、多线程的基础。在纯容器环境里特别容易缺缺了之后imread会静默失败所以提前检查很重要。3. 三步实操把预编译OpenCV接入C工程3.1 配置环境变量不要污染全局环境假设你把包解压到了/opt/opencv-4.5.5没有sudo权限就放~/opencv-4.5.5建议在包目录里创建一个env.sh脚本#!/bin/bash export OPENCV_ROOT/opt/opencv-4.5.5 export OpenCV_DIR$OPENCV_ROOT/share/OpenCV export OpenCV_DIR$OPENCV_ROOT export PKG_CONFIG_PATH$OPENCV_ROOT/lib/pkgconfig:$PKG_CONFIG_PATH export LD_LIBRARY_PATH$OPENCV_ROOT/lib:$LD_LIBRARY_PATH export PATH$OPENCV_ROOT/bin:$PATH然后执行source env.sh验证是否生效pkg-config --modversion opencv4 opencv_version两个命令都能输出4.5.5说明环境变量已经配好。为什么建议用单独的env.sh而不是直接写进.bashrc因为服务器上往往还要跑别的项目别人可能也在用OpenCV全局改环境变量很容易互相影响。独立的env.sh让不同项目可以切换不同版本需要的时候source一下不需要的时候就放在那儿不会改坏其他工程。再解释一下为什么OpenCV_DIR和OpenCV_DIR都写一遍。CMake在find_package时看的是OpenCV_DIR这个变量但很多旧工程或者老的CMake模块用的是OpenCV_DIR为了兼容两种写法干脆两个都export反正不会冲突。实际项目里如果cmake报找不到包直接在命令行再用-DOpenCV_DIR/opt/opencv-4.5.5/share/OpenCV指一次基本都能解决。这里还有一个动态库搜索顺序的问题程序运行时库的查找优先级大致是RPATH高于LD_LIBRARY_PATH然后是系统默认路径。如果某个可执行文件编译时写死了RPATH你后面export LD_LIBRARY_PATH也不一定生效。遇到“明明export了还是找不到库”的情况先去查一下工程里是不是写了RPATH这也是一个很隐蔽的坑。3.2 两种编译方式g直编和CMake工程如果只是写个验证demo用g一行搞定g main.cpp -o demo $(pkg-config --cflags --libs opencv4)注意这里查的是opencv4不是opencv。如果pkg-config没配好也可以手写编译参数g main.cpp -o demo -I/opt/opencv-4.5.5/include/opencv4 \ -L/opt/opencv-4.5.5/lib \ -lopencv_core -lopencv_imgproc -lopencv_imgcodecs真正做项目我更推荐CMake。这是完整的CMakeLists.txtcmake_minimum_required(VERSION 3.10) project(OpenCVDemo) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package(OpenCV REQUIRED) message(STATUS OpenCV version: ${OpenCV_VERSION}) include_directories(${OpenCV_INCLUDE_DIRS}) add_executable(demo main.cpp) target_link_libraries(demo ${OpenCV_LIBS})然后依次执行cmake -S . -B build -DOpenCV_DIR/opt/opencv-4.5.5/share/OpenCV cmake --build build ./build/demofind_package的查找逻辑其实不复杂先看OpenCV_DIR变量有没有设置有就去那个目录找OpenCVConfig.cmake没设置就去默认路径里找。所以cmake失败时第一反应就是确认OpenCV_DIR指向的目录里有没有对应的cmake配置文件。3.3 跑一个能验证核心模块的demo我建议用下面这个demo来验证它同时跑通了core、imgproc、imgcodecs三个模块#include opencv2/opencv.hpp #include iostream int main() { cv::Mat src cv::imread(test.jpg); if (src.empty()) { std::cerr can not load image std::endl; return -1; } cv::Mat gray, edge; cv::cvtColor(src, gray, cv::COLOR_BGR2GRAY); cv::Canny(gray, edge, 50, 150); cv::imwrite(edge.jpg, edge); std::cout OpenCV CV_VERSION works, image size: src.cols x src.rows std::endl; return 0; }这段代码里imread和imwrite来自imgcodecs模块cvtColor和Canny来自imgprocMat对象来自core。如果这三个模块都能正常运行说明整个OpenCV环境基本没有问题。运行成功后会输出类似OpenCV 4.5.5 works, image size: 640x480同时目录下多出一张edge.jpg。4. 常见报错与原理解析这5个坑我全踩过4.1 最常见的5个报错及排查思路第一个报错运行时提示error while loading shared libraries: libopencv_core.so.4.5.5: cannot open shared object file。原因很简单LD_LIBRARY_PATH没有包含OpenCV的lib目录或者你虽然export了但那个shell会话没有source。排查方法是先echo $LD_LIBRARY_PATH再看ldd ./demo | grep not found。解决就是source env.sh。但部署场景我更推荐在CMake里直接写死RPATHset(CMAKE_BUILD_RPATH /opt/opencv-4.5.5/lib)这样可执行文件自己知道去哪找库不依赖运行用户的shell环境对部署友好得多。第二个报错CMake配置阶段提示Could not find a package configuration file provided by OpenCV。原因基本是OpenCV_DIR没设置或者指向的目录不对。排查时先执行find / -name OpenCVConfig.cmake 2/dev/null看这个文件到底在哪一个目录然后把这个目录通过-DOpenCV_DIR指给CMake。如果还报错再检查你find_package里写的版本号和实际包版本是否一致。第三个报错运行时提示GLIBCXX_3.4.xx not found。原因是对方机器上的libstdc.so.6版本比编译这台机器旧。这属于预编译包跨机器使用的典型问题。排查strings /usr/lib/x86_64-linux-gnu/libstdc.so.6 | grep GLIBCXX_3.4.30如果搜不到对应版本就说明系统库确实不够新。解决方式是升级gcc或者找在更老系统上编译的包。这就是为什么发布预编译包的人喜欢用老系统编译——向下兼容性更好新系统能跑老库老系统跑不了新库。第四个报错imread读图返回空或者imshow直接崩掉。原因一般是图像编解码依赖的系统库缺失或者服务器上根本没有图形环境。解决方式补装libpng-dev、libjpeg-dev这类系统库服务器端如果只是处理图片文件流就别用imshowhighgui窗口模块在无显示环境下基本不可用。第五个报错程序编译链接到了错误的OpenCV版本行为诡异。原因往往是系统里存在多个OpenCVapt装了一份、conda环境里有一份、用户目录里还躺着一份。排查顺序which opencv_version pkg-config --modversion opencv4 grep OpenCV_DIR build/CMakeCache.txt解决方式是确保环境变量顺序正确在CMake里显式指定OpenCV_DIR同时在链接列表里用绝对路径避免让动态链接器“自由发挥”。4.2 多版本并存的项目级避坑技巧我在实际项目里维护过多个OpenCV版本并存的环境比较有效的一套做法是给每个版本建一个独立的env.sh比如env-455.sh、env-480.sh项目根目录放一个说明文档写清楚当前项目用的哪个版本。需要切换时直接source对应脚本就行不会改坏外面的环境。另外如果你从别人手里拿到预编译包第一件事建议看有没有附带的buildinfo.txt里面通常会写编译时间、GCC版本、配置选项、模块列表。判断一个包能不能用先看编译环境和你目标系统的兼容性再动手配置这样能少走很多弯路。我自己的习惯是拿到任何一个预编译OpenCV包第一件事永远是ldd而不是先写demo。依赖检查通过再配置CMake十分钟跑通依赖有缺口就先补系统库。顺序反了往往会被各种奇怪的报错绕进去。预编译包能帮你省掉编译时间但省不掉对环境和依赖的基础判断。把环境检查、变量配置、CMake查找这几条底层逻辑吃透换任何版本、换任何机器、哪怕换一个完全不同的图像库你都能走完整套接入流程。这种能力才是比压缩包本身更值钱的东西。本文还有配套的精品资源点击获取
返回列表