简介:基于跨平台应用框架Qt6.2.2与开源计算机视觉库OpenCV4.5.5,采用MinGW编译工具链构建的OpenCV预编译库资源包,面向需要在Qt项目中集成OpenCV的Windows开发者,尤其适合使用MinGW环境、希望省去复杂编译配置的初学者与项目团队。资源包含可直接链接的静态库、动态库及完整头文件,覆盖图像处理、特征检测、深度学习推理等常用模块,可用于快速搭建人脸识别、物体检测、图像分割等视觉应用。整个压缩包约308.46MB,共包含12280个文件,文件类型涵盖源代码文件(cpp、hpp、h)、编译产物(obj、a、dll)、构建脚本(cmake、make)以及测试图片(png、jpg)等,便于开发时查阅和调试。包内已集成OpenCV核心模块及dnn、aruco等扩展模块,使用者在Qt Creator中只需配置.pro文件的包含目录与库依赖,即可直接调用,无需再自行执行CMake配置和make编译。已有1102人学习下载,适合希望快速搭建Qt与OpenCV开发环境、专注于视觉功能实现的开发者。 这段时间我把 Qt 6.2.2 和 OpenCV 4.5.5 的环境重新搭了一遍,和之前用 MSVC 编译套件不同,这次全程改用 MinGW 工具链自己编译 OpenCV 库。折腾过程中踩了不少坑,也把整个链路重新梳理清楚了,这篇文章就完整记录一下我是怎么从零把这套环境跑通的,给同样在用 Qt 做图像处理、又不想被官方预编译包绑定的人做个参考。
先说结论:Qt 官方下载页提供的 OpenCV 预编译库是 MSVC 2019 版本,和 Qt 6.2.2 自带的 MinGW 11.2.0 工具链在 ABI 层面不兼容,直接拿来链接会报一堆 undefined reference。所以如果你确定用 MinGW 开发,唯一靠谱的路线就是自己编译一份 OpenCV 库。这篇文章的核心就是解决这个事:从 CMake 配置、MinGW 编译参数,到最终在 Qt 工程里链接、发布,完整走一遍。
1. 为什么非要自己编译 OpenCV
1.1 MSVC 和 MinGW 的 ABI 差异到底在哪
很多初学者最容易忽略的问题,就是编译器的“血统”必须一致。MSVC 是微软自家的 C++ 编译器,MinGW 是 GCC 在 Windows 平台上的移植版本,两者虽然都能生成 x86/64 的机器码,但底层的二进制接口规则完全不同。我这里不绕弯子,直接说最核心的几个差异点:
- C++ 符号修饰规则不同:同一个函数,MSVC 编译出来的符号名和 MinGW 编译出来的符号名完全不一样,链接器在解析时找不到对应符号,就会爆 undefined reference。
- 标准库实现不同:MSVC 绑定的是微软的 STL,MinGW 绑定的是 libstdc++,两种标准库的类内存布局、异常处理机制都有差异,混着用轻则运行崩溃,重则直接编译失败。
- 导入库格式不同:Windows 下链接动态库需要的是 .lib(MSVC 用)或 .dll.a(MinGW 用),官方预编译包只提供了 .lib,MinGW 的链接器根本认不了。
用一个生活化的类比就是:都是拧螺丝,但一个用十字螺丝刀、一个用六角扳手,工具规格不匹配,硬拧的结果就是滑丝。所以 Qt 里如果用 MSVC 套件开发,官方 OpenCV 包没问题;一旦切到 MinGW 套件,就必须自己编译。
1.2 Qt 6.2.2 + OpenCV 4.5.5 + MinGW 这套组合选型的理由
版本选型其实不是随便拍脑袋定的。我在选型时主要考虑三点:
- Qt 6.2.2:这是 Qt 6 系列第一个 LTS 版本,工具链集成最完整,官方在线安装器里直接带 MinGW 11.2.0 64-bit 套件,不需要额外去装编译器,开箱即用。
- OpenCV 4.5.5:4.5.x 系列整体处于功能稳定期,CMake 配置不再像 3.x 那样需要手工处理一堆依赖,尤其是
WITH_QT选项在 4.5 版本上和 Qt6 的兼容性已经做得比较成熟。再往上 4.6、4.7 我也试过,编译能过,但 Qt 模块的高gui显示反而容易出现 QOpenGLWidget 相关的兼容问题,所以最终锁定了 4.5.5。 - MinGW 11.2.0:随 Qt 6.2.2 官方分发的版本,GCC 版本足够新,支持 C++17,OpenCV 4.5.5 的所有模块都能正常编译,不用自己折腾环境变量。
1.3 编译前要准备的完整工具清单
在正式开始之前,先把工具链备齐。我列一下我当时准备的清单:
| 工具 | 版本 | 用途 |
|---|---|---|
| Qt 6.2.2 | 含 MinGW 11.2.0 64-bit 组件 | 提供 Qt 库和编译器 |
| OpenCV 源码 | 4.5.5 | 编译目标,必须下载源码包,不能用预编译包 |
| CMake | 3.22 及以上 | 生成 Makefile 和构建配置 |
| Python | 3.x(可选) | 如果不需要 Python 接口,可以忽略 |
| 7-Zip | 最新版 | 解压源码包,Windows 自带解压对超大 zip 容易出错 |
OpenCV 源码从官网下载就行,注意选Sources版本,文件名类似opencv-4.5.5.zip。下载后建议放在一个纯英文路径下,比如D:\opencv\src,不要放在带中文或空格的路径里,否则后面 CMake 配置阶段会出现各种奇怪问题。
2. CMake 配置阶段的几个关键细节
2.1 目录结构规划
这个看似不起眼,实际影响挺大。我习惯这样规划目录:
D:\opencv ├── src # OpenCV 源码解压目录 └── build-mingw # CMake 构建目录(独立于源码目录)构建目录和源码目录分开是基本操作,这样源码目录不会被 CMake 生成的缓存文件污染,后面想换个编译器重新编译,只需新建一个 build 目录,互不影响。我见过有人直接在源码目录里点 Configure,结果出了问题想重新来,源码目录里散落了一堆 CMakeCache,清理起来非常痛苦。
2.2 用 CMake 指定编译器的正确姿势
打开 CMake GUI 后,填好源码目录和构建目录,第一次点击 Configure 时,CMake 会弹出选择生成器的对话框。这里有一个关键操作:生成器必须选择“MinGW Makefiles”,而不是默认的 Visual Studio 系列或 NMake Makefiles。
选完生成器后,CMake 还会要求指定 C 和 C++ 编译器。这里要手动指向 Qt 安装目录下的工路,注意路径不能写错。我当时如果记得没错,路径类似这样:
C:/Qt/6.2.2/mingw_64/bin/gcc.exe C:/Qt/6.2.2/mingw_64/bin/g++.exe这里我重点提醒一下:很多人卡在 Configure 报错找不到编译器,就是因为直接用了系统默认的 cl.exe(MSVC)或者干脆没装编译器。CMake 默认会尝试检测系统编译器,但 Qt 的 MinGW 不在系统 PATH 里,所以必须手动指定,这一步省不了。
2.3 关键 CMake 参数解析和建议值
Configure 阶段会生成一堆缓存参数,我这里只挑影响最大的几个说。参数设置不好,轻则编译时间翻倍,重则整个构建失败甚至运行时崩溃。
| 参数名 | 建议值 | 说明 |
|---|---|---|
| CMAKE_BUILD_TYPE | Release | 不设置的话默认是空,会导致一些优化参数没生效,编译出的库性能差一截 |
| CMAKE_PREFIX_PATH | C:/Qt/6.2.2/6.2.2/mingw_64 | 让 CMake 能自动找到 Qt 6 的安装路径,这样编译 OpenCV 的 Qt 模块时才能正确链接 |
| WITH_QT | ON | 启用 Qt 后端,cv::imshow 显示窗口会走 Qt 渲染 |
| WITH_OPENGL | ON | Qt 后端依赖 OpenGL,建议开启 |
| WITH_IPP | OFF | Intel 的加速库,不开能大幅减少编译时间,对普通场景性能影响不大 |
| WITH_CUDA | OFF | 没有 NVIDIA GPU 需求就关掉,省一大半编译时间 |
| BUILD_EXAMPLES | OFF | 官方示例代码量很大,编译它们纯粹浪费时间 |
| BUILD_TESTS | OFF | 测试模块同理,关掉 |
| BUILD_opencv_python3 | OFF | 用不到 Python 绑定就关掉,否则还会额外要求 numpy |
这些参数里最容易被忽略的是CMAKE_PREFIX_PATH。如果不设置这个,CMake 在检测 Qt 6 时大概率会失败,然后 WITH_QT 就自动变回 OFF,编译出来的 OpenCV 库虽然能处理图像,但完全没有图形显示能力,跑 cv::imshow 直接崩。我第一次编译时就犯了这个问题,后面排查了很久才意识到是 CMake 没找到 Qt 库目录。
参数确认无误后,点击 Generate 生成 Makefile。这一步如果报错,仔细看日志,通常都是上面几个路径问题,解决掉再重新 Configure 即可。
3. 正式编译的完整过程和避坑记录
3.1 编译前必须使用的终端环境
Generate 完成后,很多人的第一反应是打开 CMD 直接敲 make。这里又有一个大坑:千万不要用系统自带的 CMD 或 PowerShell 编译。因为 MinGW 的编译器、链接器等工具链程序不在系统 PATH 里,你直接敲 mingw32-make 会提示找不到命令。
正确做法是:从 Windows 开始菜单打开 Qt 自带的终端快捷方式,名字一般是Qt 6.2.2 (MinGW 11.2.0 64-bit)。这个终端会自动配置好 PATH、QTDIR 等环境变量,你再执行编译命令就不会有问题。我一般这样操作:
cd /d D:\opencv\build-mingw mingw32-make -j8-j8是最重要的参数,意思是同时用 8 个编译线程,能显著缩短编译时间。这个数字建议不要超过 CPU 物理核数的两倍,我本机是 8 核 16 线程,用-j8比较平衡;如果内存只有 8G,建议降到-j4,防止编译过程中内存爆炸。整个 OpenCV 4.5.5 编译下来,我实测大约 35 到 50 分钟,具体看机器配置。
3.2 编译完成后如何找到库文件
编译成功后,OpenCV 生成的库文件默认分散在两个目录:
D:\opencv\build-mingw\bin:存放所有 DLL 动态库D:\opencv\build-mingw\lib:存放链接用的导入库,格式为libopencv_core455.dll.a
这里有个很容易搞混的概念。MinGW 下链接 OpenCV 时,LIBS里写的是lib目录下的.dll.a文件,而不是bin目录下的.dll。.dll.a是导入库,告诉链接器“这个符号在这个 DLL 里”,相当于 MSVC 下的.lib文件。如果你在LIBS里直接写 DLL 的路径,编译时会报错或根本无法解析符号。
3.3 验证编译结果是否可用
编译完成后,建议先做一个最小验证,确认库有没有问题。我习惯写一个最简单的 C++ 文件:
#include <opencv2/opencv.hpp> #include <iostream> int main() { std::cout << "OpenCV version: " << CV_VERSION << std::endl; cv::Mat mat(100, 100, CV_8UC3, cv::Scalar(0, 255, 0)); cv::imwrite("test.png", mat); std::cout << "Test image saved." << std::endl; return 0; }在 Qt 终端里编译:
g++ -o test test.cpp -I D:/opencv/build-mingw/include -L D:/opencv/build-mingw/lib -lopencv_core455 -lopencv_imgcodecs455能输出版本号并生成 test.png,就说明这套库可以用。这一步一定要做,不要直接闷头往大项目里集成,到时候链接报错根本分不清是库的问题还是自己工程配置的问题。
4. 在 Qt 6.2.2 工程中集成编译好的 OpenCV
4.1 .pro 文件的配置写法
库编译好了,接下来就是接入 Qt 工程。我这里拿一个普通的 QWidget 工程举例,.pro文件的关键配置如下:
QT += core gui widgets TARGET = OpenCVTest TEMPLATE = app INCLUDEPATH += D:/opencv/build-mingw/include LIBS += -LD:/opencv/build-mingw/lib \ -lopencv_core455 \ -lopencv_imgproc455 \ -lopencv_highgui455 \ -lopencv_imgcodecs455注意几点:
INCLUDEPATH指向的是 include 目录,里面包含了opencv2头文件目录。LIBS里-L指定库搜索路径,-l指定链接哪个库,库名要去掉lib前缀和.dll.a后缀。-lopencv_highgui455是必须的,如果只处理图像不显示窗口可以不要,但大部分场景都要。
4.2 代码层面的几个实际坑点
集成阶段最容易出问题的不只是链接配置,还有代码编写习惯。我直接给一段可用的示例:
#include <QApplication> #include <QFileDialog> #include <QLabel> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication a(argc, argv); // 弹出文件选择对话框,获取图片路径 QString filePath = QFileDialog::getOpenFileName( nullptr, "选择图片", ".", "Images (*.png *.jpg *.bmp)"); if (filePath.isEmpty()) { return 0; } // OpenCV 读取和处理 cv::Mat image = cv::imread(filePath.toStdString()); if (image.empty()) { return 0; } cv::Mat gray; cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY); // 转换为 QImage 显示在 QLabel 上 cv::Mat rgb; cv::cvtColor(gray, rgb, cv::COLOR_GRAY2RGB); QImage qimg(rgb.data, rgb.cols, rgb.rows, static_cast<int>(rgb.step), QImage::Format_RGB888); QLabel label; label.setPixmap(QPixmap::fromImage(qimg.copy())); label.show(); return a.exec(); }这里我想重点说两个坑:
第一个坑:OpenCV 的 imread 在 Windows 下不支持中文路径。如果你的图片路径里带中文,比如D:\图片\test.jpg,imread会直接返回空 Mat,而且不会报任何错误。这个问题网上讨论很多,4.5.5 版本依然存在。规避方案是:用QFileDialog拿到路径后,先用QFile把文件读成二进制,再通过cv::imdecode解码,绕开imread的文件名解析逻辑。
QFile file(filePath); if (!file.open(QIODevice::ReadOnly)) return 0; QByteArray data = file.readAll(); std::vector<uchar> buf(data.begin(), data.end()); cv::Mat image = cv::imdecode(buf, cv::IMREAD_COLOR);第二个坑:QImage 和 cv::Mat 数据格式转换。Qt 的QImage::Format_RGB888是 RGB 顺序,而 OpenCV 默认 BGR 顺序,直接转换色彩会错乱。必须先cv::cvtColor做一下通道转换,否则图像显示后红蓝通道是反的。这个几乎每个人都会踩一次。
4.3 发布时 DLL 的处理方式
Qt 工程编译通过后,要发布给别人用,需要把必需的 DLL 都放到 exe 同目录。Qt 自带的依赖可以交给工具处理,在 Qt 终端里执行:
windeployqt OpenCVTest.exe这个命令会自动把 Qt 相关的 DLL 复制到 exe 目录。然后还需要手动把 OpenCV 的 DLL 也拷过去:
cp D:/opencv/build-mingw/bin/opencv_core455.dll . cp D:/opencv/build-mingw/bin/opencv_imgproc455.dll . cp D:/opencv/build-mingw/bin/opencv_highgui455.dll . cp D:/opencv/build-mingw/bin/opencv_imgcodecs455.dll .更省事的做法是直接把D:/opencv/build-mingw/bin加入系统 PATH 环境变量,这样运行时会自动搜索到,但考虑到分发时目标机器不一定有这个目录,最稳妥的还是把 DLL 放在 exe 同级目录。
5. 常见问题与排查技巧实录
5.1 问题速查表
这里把我编译、集成、运行过程中遇到过的典型问题整理成了一张表,方便大家对照排查:
| 症状 | 原因 | 解决方案 |
|---|---|---|
| CMake Configure 报错找不到编译器 | 没有手动指定 MinGW 的 gcc/g++ | 重新 Configure,指定 C/C++ 编译器路径 |
| 编译时提示找不到 Qt6 相关模块 | CMAKE_PREFIX_PATH 没设置或路径错误 | 在 CMake 里设置 CMAKE_PREFIX_PATH 指向 Qt 安装目录 |
| 链接阶段大量 undefined reference | 编译器不一致(MSVC 的库用来链接 MinGW 工程) | 换用自己编译的 MinGW 版 OpenCV 库 |
| 运行时报找不到 DLL | 系统 PATH 没包含 OpenCV 的 bin 目录 | 把 bin 目录加入 PATH,或拷贝 DLL 到 exe 目录 |
| cv::imread 返回空 Mat | 图片路径带中文或文件不存在 | 用 QFile 读取后 imdecode,避免中文路径 |
| 图像显示颜色偏蓝偏红 | QImage 和 cv::Mat 的 RGB/BGR 通道顺序不一致 | 先 cv::cvtColor 转换到 RGB 再转 QImage |
| 编译过程耗时过长 | 开了 WITH_IPP、WITH_CUDA、BUILD_EXAMPLES 等 | 关掉非必要模块,只保留核心功能 |
5.2 一个非常隐蔽的坑:TMP 目录和编译失败
还有一个问题不太容易想到,就是编译过程中如果系统临时目录空间不足,mingw32-make会在某个模块编译到一半时突然报错,错误信息通常指向一个临时文件无法创建。我自己的 C 盘剩余空间当时不太够,编译 OpenCV 的 dnn 模块时经常挂掉,后来把环境变量TMP和TEMP指向了空间宽裕的 D 盘,重新编译就顺利通过了。如果你在编译中途频繁失败,可以优先检查临时目录空间和位置。
5.3 关于 Debug 和 Release 库混用
OpenCV 编译时如果只选了 Release,生成的库就只有一份。Qt 工程里如果同时存在 Debug 和 Release 两个构建版本,建议都链接同一个 Release 库,不要在 Debug 工程里链 Release 库的同时又在 Release 工程里链 Debug 库,很容易出现运行时行为不一致的问题。我一般只编译 Release 库,Qt 工程也统一用 Release 构建,省事且性能好。Debug 库的链接调试需求不是没有,但正常业务开发用不上,不用强行追求两套库。
最后分享一点个人体会
整套流程走下来,我最深的感受是:编译 OpenCV 本身就是个体力活,真正的门槛并不在于 Make 命令敲得对不对,而在于对整个工具链的“血统”有没有清楚的认识。MSVC 的库给 MinGW 用会挂,MinGW 编译时找不到 Qt 路径会挂,DLL 没放到运行目录也会挂,这些坑背后其实是同一个逻辑——把编译器家族、头文件、导入库、运行时 DLL 这四者的路径和类型完全对齐,整套环境就稳了。
经验上,我强烈建议第一次编译时不要贪多,把 CUDA、Python、IPP 这些用不到的特性全关掉,先把最基础的核心模块编译出来,跑通最小示例后再按需补加模块。另外,CMake 配置确认无误后,可以把关键配置保存成一个脚本文件,下次要重装环境时直接批量执行,省得重新在 GUI 里点一遍。
如果你正准备在 Qt 6.2.2 下用 MinGW 编译 OpenCV 4.5.5,照着这篇文章的顺序走一遍,基本不会出大问题。中间如果卡住了,先对照排查表找原因,大概率是某个路径没对上或者某个参数开错了。祝编译顺利。
本文还有配套的精品资源,点击获取