简介:面向Windows 10 64位环境下使用MinGW编译器整合OpenCV 3.2.0与Qt 5.9.6的开发者,解决两者协同编译与链接配置繁琐的问题。资源共245个文件,以145个hpp、57个h头文件提供完整API声明,配合17个dll动态库与16个a导入库,可直接在Qt工程中完成链接,省去从源码自行CMake编译的漫长过程,包体约10.61MB。目前已有242人学习下载。基于这套已编译好的OpenCV库,读者可快速搭建图像处理与界面开发环境,直接调用core、imgproc、highgui、features2d等模块,实现图像显示、特征检测等典型功能;压缩包内头文件、库文件与少量示例exe分层存放,并附带cmake配置文件,既能直接嵌入项目,也可作为对比验证MinGW+Qt配置是否正确的排错参考,适合C++/Qt开发者作为环境基石。
1. 拿到 OpenCV 3.2.0 却卡在 Qt 5.9.6:问题不在 OpenCV,在编译器
官方 OpenCV 的 Windows 预编译包只带 MSVC 运行时,装完 Qt 5.9.6 后用 MinGW 套件一链接,报错一屏接一屏——这正是我最早干这活儿的真实状态。不给样例代码、不给现成 lib 的话,Qt 里imread都调不通。问题的根源在于 MSVC 和 MinGW 两套 ABI 不能互通,你必须在 Windows 上自己用 MinGW 编译一份 OpenCV 3.2.0,并保证它认识 Qt 5.9.6 的头文件和链接库,最后 Link 成一个能用 Qt 窗口显示的imshow。这篇文章就把这套做法完整拆开,环境准备、CMake 配置、编译参数、以及我踩过的几个最疼的坑,全部写给你。
先说结论:这条路走得通,但版本必须咬死——OpenCV 3.2.0、Qt 5.9.6、MinGW 530 的搭配在 Win10 x64 上是可以一次跑通的。我后面所有步骤都以这个组合为准,你换任何一个版本,编译选项和对错都会不一样。这篇文章适合三类人:被undefined reference to折磨的新手、想搞清楚WITH_QT到底干什么的熟手、以及正在订制 OpenCV 功能模块的开发者。
2. 为什么必须自己编:MSVC 和 MinGW 的 ABI 差异与版本咬合
2.1 msvc 与 mingw 的 ABI 之争,为什么不能混用
MSVC 和 MinGW 虽然都能生成 Windows 上的 x86 代码,但二者的 C++ ABI 不兼容:名字修饰规则不同、异常处理模型不同、标准库的实现也不同。你在 MSVC 编译的 OpenCV 里链接 MinGW 的 Qt,轻则链接失败,重则cv::Mat的内存布局对不上直接崩。Qt 5.9.6 官方安装包会在Tools目录带一份 MinGW 530,而 OpenCV 3.2.0 官方只发布 MSVC 版,所以最常见做法就是你跑到 Qt 安装目录的Tools\mingw530_32里找编译器,然后完全用这套 MinGW 重新编 OpenCV。
这套工具链的版本匹配逻辑是这样的:Qt 5.9.6 官方包分了msvc2015、msvc2013、mingw530_32三个目录,其中 MinGW 目录的编译器是 32 位。如果你主机是 Win10 64 位,还在 64 位上跑 Qt Creator 的 MinGW 套件,那编译器必须换成 64 位版 MinGW-w64。我自己用的是x86_64-8.1.0-posix-seh-rt_v6-rev0,这个版本跟 Qt 5.9.6 的库匹配良好,OpenCV 3.2.0 也认。
注意:不要混用 32 位 Qt 库和 64 位 OpenCV 库。要么全 32 位,要么全 64 位,这是后续所有编译报错的前提条件。
2.2 版本咬合的硬参数:OpenCV 3.2.0 的 CMake 要求
OpenCV 3.2.0 的 CMake 最低版本要求是 2.8.12,但我建议直接用 3.10 以上的版本,因为 CMake 对 MinGW Makefiles 生成器的支持在 3.10 之后才稳定。Qt 5.9.6 自带的 CMake 是 3.6,碰巧能用,不过我在实际构建中会发现 OpenCV 3.2.0 的某些模块(比如opencv_dnn)在 CMake 3.6 下会出现奇怪的生成失败,换成 CMake 3.10 就消失。
另外,OpenCV 3.2.0 的opencv_world选项在 3.2 版本之后才引入,3.2.0 本身是不支持合并成一个世界库的,这会导致你最后在 Qt 工程里要一个个链十几个模块 lib。我现在更习惯的做法是用BUILD_SHARED_LIBS=ON,让编译产物是 DLL,这样 Qt 工程里只需要链opencv_core320.dll、opencv_imgproc320.dll对应的导入库,运行时所有依赖模块都会被 Qt 自己加载,省去静态库那堆opencv_*的烦恼。
2.3 编译前的检查清单
在正式开始编译之前,我建议你把下面这张表核对一遍。很多编译失败不是命令的问题,而是前期环境埋的雷。
| 检查项 | 期望值 | 说明 |
|---|---|---|
| Qt 安装路径 | 无中文无空格 | 例如D:\Qt\Qt5.9.6,有空格会 CMake 解析出错 |
| MinGW 编译器 | 与 Qt 库位数一致 | 32 位 Qt 用 530_32,64 位用 x86_64-posix-seh |
| CMake 版本 | ≥ 3.10 | Qt 自带的 3.6 能用但坑多 |
| 源代码目录 | 无中文 | OpenCV 源码目录含中文会导致make阶段失败 |
| 构建目录 | 与源码目录分开 | 例如D:\opencv\build_mingw_qt,源码在D:\opencv\source |
这套检查做完,再往下走就不会在莫名其妙的地方翻车。我一般在构建目录名字里直接写清楚mingw和qt两个标签,这样以后回来重编的时候一眼就知道当时是给谁编的。
3. 用 CMake 配置 OpenCV 3.2.0:从下载源码到生成 Makefile
3.1 准备源码与 contrib 模块
OpenCV 3.2.0 的源码需要从 GitHub 的opencv仓库切3.2.0标签,同时把opencv_contrib仓库也切到3.2.0。注意为什么不直接下官方 release 包?因为 3.2.0 的 release zip 里不带 contrib,而 SIFT、SURF 这些非自由算法全部在 contrib 的xfeatures2d模块里。如果你要用特征点匹配,必须把OPENCV_EXTRA_MODULES_PATH指向 contrib 的 modules 目录。
git clone https://github.com/opencv/opencv.git cd opencv git checkout 3.2.0 git clone https://github.com/opencv/opencv_contrib.git cd opencv_contrib git checkout 3.2.0这两步的先后顺序很重要,先切 OpenCV 主仓再切 contrib,能保证两个仓库的提交时间点一致。我踩过的一个坑是:直接 clone 最新的 contrib 跟 3.2.0 的 OpenCV 放一起编译,xfeatures2d的 CMake 会报错找不到opencv_core的某些接口函数。版本切齐之后,还需要把 contrib 里的modules路径单独记下来,因为 CMake 的OPENCV_EXTRA_MODULES_PATH需要精确指向这个目录。
3.2 CMake 配置关键参数
配置这一步是整个流程的命门。你需要用cmake-gui而不是命令行,因为 OpenCV 3.2.0 的 CMake 缓存变量太多了,GUI 里能看到所有WITH_*和BUILD_*的当前状态,避免漏项。打开cmake-gui,选择源码目录和构建目录,点 Configure 之后选生成器:必须要选MinGW Makefiles,不要选Eclipse CDT4 - MinGW那个,因为 OpenCV 3.2.0 对后者的支持不够完整,生成出来的 Makefile 经常缺依赖。
下面这组是我反复验证过的可用配置:
cmake -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_C_COMPILER=D:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/gcc.exe \ -DCMAKE_CXX_COMPILER=D:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/g++.exe \ -DCMAKE_MAKE_PROGRAM=D:/mingw-w64/x86_64-8.1.0-posix-seh-rt_v6-rev0/mingw64/bin/mingw32-make.exe \ -DWITH_QT=ON \ -DWITH_OPENGL=ON \ -DWITH_OPENMP=ON \ -DWITH_IPP=OFF \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DOPENCV_EXTRA_MODULES_PATH=D:/opencv_contrib/modules \ D:/opencv/source这段命令的逻辑说明:CMAKE_C_COMPILER和CXX_COMPILER必须显式指定,因为 CMake 默认会去 PATH 里找gcc.exe,如果找不到就会退回 Visual Studio 生成器,导致整个配置失败。CMAKE_MAKE_PROGRAM指定mingw32-make.exe,注意不是mingw32-make的 jom——jom 是 MSVC 的并行 make,MinGW 不认。WITH_QT=ON是本文的核心开关,开启后 OpenCV 的highgui模块会用 Qt 作为 GUI 后端,这样imshow出来的窗口就是 Qt 风格的,而且能跟 Qt 的信号槽机制混用。
3.3 路径变量检查
Configure 完成后,cmake-gui 里会出现一组Qt5_DIR、Qt5Core_DIR、Qt5Gui_DIR缓存变量。如果这些变量是空的,说明 CMake 没找到 Qt 5.9.6,需要手动指定:
Qt5_DIR=D:/Qt/Qt5.9.6/5.9.6/mingw53_32/lib/cmake/Qt5如果填完这个变量还找不到,多半是 Qt 安装时没选 MinGW 组件,只装了 MSVC 版本。Qt 5.9.6 的安装器支持自定义组件,MinGW 530 在 Tools 目录里,Qt 库在5.9.6/mingw53_32目录里,这两个装齐了才能往下走。确认这些变量全部变成Found状态后,再点 Generate,Makefile 就出来了。
4. 编译、安装与 Qt 工程集成
4.1 mingw32-make 并行编译与常见编译日志排查
生成 Makefile 之后,进入构建目录执行编译。不推荐直接用mingw32-make不带参数的跑,这个命令在 Windows 上默认只单核编译,OpenCV 全量编下来三四个小时都是正常的。我用的是-j8显式指定 8 线程:
cd D:/opencv/build_mingw_qt mingw32-make -j8编译过程中如果出现multiple definition of ...,不是代码问题,是并行编译时 CMake 的依赖没生成全。解决办法是先不带-j跑一次,等 CMake 把依赖.d文件生成完,再并行跑第二次。更常见的错误是fatal error: QtCore/qglobal.h: No such file or directory,这个就是Qt5_DIR变量没指对,或者 Qt 头文件路径里带了空格导致 Makefile 里C:/Program Files被截断。我一般习惯把 Qt 装到D:\Qt这种无空格路径下,能省掉一半编译报错。
编译完成后,执行安装:
mingw32-make install默认安装目录会是D:/opencv/build_mingw_qt/install,你也可以用CMAKE_INSTALL_PREFIX提前指定,比如D:/opencv_mingw_qt。安装产物里有include、x64/mingw/lib和x64/mingw/bin三个目录,lib 里是libopencv_core320.dll.a这种 GNU 风格导入库,bin 里是opencv_core320.dll这种运行时文件。
4.2 Qt 5.9.6 工程里链接 OpenCV 的 CMake 写法
Qt 工程这边,我习惯在.pro里直接写INCLUDEPATH和LIBS,不用pkg-config,因为 Windows 上的 MinGW 环境经常没有pkg-config,或者路径变量设不对。下面是一个能跑的CMakeLists.txt写法,如果你用的是 qmake,可以平移成.pro的写法:
cmake_minimum_required(VERSION 3.10) project(opencv_qt_demo) set(CMAKE_CXX_STANDARD 11) set(OpenCV_DIR "D:/opencv_mingw_qt") find_package(OpenCV REQUIRED) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) find_package(Qt5 5.9 REQUIRED COMPONENTS Core Gui Widgets) add_executable(opencv_qt_demo main.cpp) target_link_libraries(opencv_qt_demo ${OpenCV_LIBS} Qt5::Core Qt5::Gui Qt5::Widgets )这里最关键的是OpenCV_DIR必须指向你make install安装后的目录,而不是源码目录。CMake 的FindOpenCV.cmake会在这个目录下找OpenCVConfig.cmake,这个文件记录着编译时的全部路径和库列表。安装目录不对的话,find_package(OpenCV REQUIRED)会直接报Could NOT find OpenCV。
如果OpenCV_LIBS展开出来是一堆opencv_core;opencv_imgproc;...;opencv_highgui,注意它们不带路径前缀,CMake 会通过OpenCV_DIR里的导入目标自动解析。假如你的编译器跟 OpenCV 编译时不一致,链接阶段会报libstdc++-6.dll not found,这个后面避坑章细说。
4.3 运行时 DLL 路径与 Qt 插件目录
编译链接都过了,运行还可能要处理 DLL 搜索路径。MinGW 的 DLL 不像 MSVC 那样自动复制到 exe 目录,Qt Creator 运行的时候会设置PATH环境变量,但不会自动把opencv_*.dll加进去。我把 OpenCV 的bin目录加到系统PATH里:
set PATH=D:/opencv_mingw_qt/x64/mingw/bin;%PATH%同时 Qt 的bin目录和mingw53_32/bin目录也需要在 PATH 里,因为imshow需要 Qt 的qwindows.dll插件才能弹窗。如果qwindows.dll找不到,运行时会静默失败——窗口不弹,程序不退出,什么都不报,玄学得很。这个问题的调试手段是看 Qt 应用的debug输出,有个警告提示This application failed to start because no Qt platform plugin could be initialized。
5. 避坑:六条血泪经验,每一条都对应一次真实翻车
5.1 现象:CMake 报了dependent '..\..\..\Qt\5.15.2\msvc2019_64\include\QtWidgets' does not exist
这个报错在热搜里出现频率很高。原因是你用 MinGW 套件的时候,CMake 找到了 MSVC 编译的 Qt 5.15.2 库。Qt 安装器默认装 MSVC 版本,你后来又手动装了 MinGW 版本,两个版本的Qt5Config.cmake都注册进了系统,CMake 优先找到了 MSVC 那个。解决方式是命令行里显式传Qt5_DIR指向 MinGW 版本,而不是让 CMake 自己找。我一般把 Qt 的qmake.exe路径直接写到批处理脚本里,每次配置前set QTDIR=D:\Qt\Qt5.9.6\5.9.6\mingw53_32,再set PATH=%QTDIR%\bin;%PATH%,CMake 就只会看到这一个 Qt。
5.2 现象:undefined reference to _imp__ZN2cv6imreadERKNS_6StringEi
这个是最经典的 MinGW 交叉编译错误。_imp_前缀说明你要链接的是一个 DLL 的导入库,但 OpenCV 3.2.0 静态库的导出符号没有这个前缀。你大概率在 CMake 里BUILD_SHARED_LIBS被设成了OFF,编译出来的是libopencv_core.a静态库,但你的链接语句里还写着opencv_core320.dll.a。解决方式是编译时确认BUILD_SHARED_LIBS=ON,或者打开cmake-gui看这个变量到底是不是 ON——我见过有人命令行传了变量,但 GUI 缓存没刷新,执行时还是 OFF。
5.3 现象:Qt Creator 能编译,但不能运行,提示The process was ended forcefully
这个通常发生在你的程序里cv::imshow开了窗口,又在同一个函数里调了 Qt 的QDialog::exec()。OpenCV 3.2.0 的highgui在 Qt 后端启用了无限循环的事件处理,两个事件循环嵌套就把程序卡死。解决方式是避免在 Qt 的槽函数里直接调用imshow,而是把Mat数据发到 Qt 窗口那边绘制。更简单的方法是用cv::namedWindow加WINDOW_NORMAL,再把QApplication的事件循环挂到QTimer里,不过这个写法复杂,我的习惯是捕获到Mat后放进QImage显示,完全不用imshow。
5.4 现象:运行时报找不到 opencv_core320.dll,但 DLL 明明放在 exe 同目录
MinGW 的 DLL 搜索顺序跟 MSVC 不一样,MSVC 先看 exe 所在目录,MinGW 的dlwin32运行时环境变量处理在某些情况下会先找PATH。你在 exe 同目录放了 DLL 不行,得把 DLL 路径写进PATH。还有一种情况是 Qt Creator 的运行环境跟 shell 环境不一致,Qt Creator 是在启动时捕获PATH的,你改了系统环境变量之后要重启 Qt Creator 才生效。我一般在 Qt Creator 的「运行」设置里手动把bin目录加进去,跟系统 PATH 无关。
5.5 现象:编译 OpenCV 时ippicv下载失败,卡住不动
OpenCV 3.2.0 的构建步骤会自动下载 IPP ICV 包,这个文件托管在 SourceForge 上,网络差的时候会一直卡在下载阶段,CMake 不报错也不继续。解决方式是手动下载ippicv_2017u3_win_ttv1(3.2.0 对应的版本)放到opencv/.cache目录,注意路径要对着opencv/3rdparty/ippicv/downloader.cmake里写的校验路径。更省事的做法是直接-DWITH_IPP=OFF,因为 OpenCV 3.2.0 里 IPP 对普通图像处理加速并不明显,关了还能省 1 个 GB 的编译产物。
5.6 现象:OpenCV 装好了 Python 却报No module named 'cv2'
这是我后来写 Python 验证脚本时踩的。OpenCV 3.2.0 用 MinGW 编出来的是 C++ 库,Python 接口需要单独BUILD_opencv_python3=ON。如果你没开这个选项,中文互联网上的教程会告诉你去pip install opencv-python,但那装的是 MSVC 编译的轮子,跟 MinGW 没关系。正确处理方式是编译时打开BUILD_opencv_python3,并且把 Python3 的EXECUTABLE路径指给 CMake,然后make产物里会出现cv2.pyd,拷到site-packages就能用了。
6. 验证一条链路的完整闭环:从视频帧采集到 Qt 窗口显示
6.1 一个能同时打开摄像头和 Qt 窗口的工程
要真正验证这套 MinGW + Qt 5.9.6 + OpenCV 3.2.0 是否打通,我建议不要只跑imshow静态图,做一个小而完整的「视频帧采集 → Mat 转 QImage → 窗口绘制」闭环。这个闭环能同时验证摄像头驱动、Qt 窗口插件、DLL 路径、帧格式转换四件事,四件都过了,你的环境就真的没问题了。
#include <QApplication> #include <QLabel> #include <QTimer> #include <opencv2/opencv.hpp> int main(int argc, char *argv[]) { QApplication app(argc, argv); cv::VideoCapture cap(0); if (!cap.isOpened()) return -1; QLabel label; label.resize(640, 480); label.show(); QTimer timer; QObject::connect(&timer, &QTimer::timeout, [&]() { cv::Mat frame; cap >> frame; if (frame.empty()) return; cv::cvtColor(frame, frame, cv::COLOR_BGR2RGB); QImage qimg(frame.data, frame.cols, frame.rows, frame.step, QImage::Format_RGB888); QPixmap pix = QPixmap::fromImage(qimg); label.setPixmap(pix); }); timer.start(33); return app.exec(); }这段代码的逻辑是:QTimer每 33 毫秒触发一次,从VideoCapture读一帧,然后用cvtColor把 OpenCV 默认的 BGR 顺序转成 Qt 需要的 RGB,再把Mat的数据指针传给QImage。注意QImage的构造里传了frame.step,这是因为cap >> frame出来的 Mat 每行可能有内存对齐 padding,不传step的话图像会有横向偏移。QImage构造完毕后转换成QPixmap上屏,QLabel只是最简容器,你可以换成任何自绘 widget。
如果你跑这个程序发现窗口全黑但程序不崩,先检查摄像头索引,cap(0)在部分笔记本上是红外摄像头而不是 RGB 摄像头。换成cap(1)试试,或者枚举一下cap.get(CV_CAP_PROP_FRAME_WIDTH)看返回值。实在不行就换成读视频文件:
cv::VideoCapture cap("D:/test.mp4");这样能把摄像头驱动的干扰因素排除掉,单独验证 OpenCV 解码和 Qt 显示链路。
6.2 验证清单:编译期、链接期、运行期三段式检查
完整跑通之后,我习惯按下面这张表做三段式收尾,专门排查环境是否还有没暴露的雷:
| 阶段 | 检查项 | 预期结果 |
|---|---|---|
| 编译期 | find_package(OpenCV REQUIRED) | 不报错,OpenCV_VERSION为 3.2.0 |
| 编译期 | find_package(Qt5 5.9 REQUIRED) | 找到的是 MinGW 版本,非 MSVC |
| 链接期 | 链接命令里opencv_*全部带dll.a后缀 | 无undefined reference |
| 运行期 | QPixmap能正常显示 | 窗口正常弹,无黑屏 |
| 运行期 | 任务管理器里能看到opencv_core320.dll已加载 | 无 DLL 加载失败 |
从那次以后,我每次给 Qt 配 OpenCV 都强制把环境检查、CMake 配置、链接确认三步走一遍,省掉了大量后期调试时间。尤其是以后你再碰到有用 VS2022 配 OpenCV 4.x 的需求时,这几步的思维照样通用。希望帮到你。
本文还有配套的精品资源,点击获取