简介:面向Windows 10 64位下使用MinGW编译器开发Qt 5.9.6与OpenCV 3.2.0整合应用的开发者,这套预编译资源直接提供编译产物,可省去从源码配置CMake的繁琐步骤,解决OpenCV与Qt环境匹配难的问题。压缩包共245个文件,包含145个hpp、57个h头文件,以及17个dll动态库、16个a导入库,另有5个可执行示例、4个cmake配置文件和1个txt说明文档,整体仅10.61MB,体积轻量,适合快速引入工程。资源中附带的exe示例可用于验证OpenCV与Qt的链接是否成功,库文件结构清晰,直接复制到对应目录并配置环境变量即可调用。目前已有242人学习下载,适合具备Qt基础、又希望使用OpenCV图像处理功能的C++开发者作为参考基底,在其上构建带界面的视觉应用。
1. 从OpenCV 3.2.0 + MinGW + Qt 5.9.6 这个组合说起
如果你在Win10上想把OpenCV 3.2.0和Qt 5.9.6放到同一个程序里用,十有八九会卡在同一个地方:OpenCV官方发布的Windows预编译包是MSVC编译器产物,而Qt 5.9.6官方自带的是MinGW工具链。MSVC的库文件(.lib)和MinGW的导入库(.a)完全不是一套ABI,直接混用会得到几百个“未定义引用”的链接错误。所以这个标题看起来是三个名词的拼接,实际是在问一件事:怎么用MinGW自己编译出能跟Qt 5.9.6好好相处的那一版OpenCV。这篇文章就是把这条路从原理到落地走一遍,适合那些被imshow弹不出Qt窗口、链接报错、DLL找不到,或者单纯不想用MSVC开发Qt项目的人。
2. 为什么必须自己编译:MSVC与MinGW的ABI鸿沟,以及Qt后端的价值
2.1 官方预编译包为什么不能直接用
OpenCV官网在3.2.0时代只提供两个Windows安装包:一个是Win pack,另一个是Win pack(带contrib)。这两个都是MSVC 2015编译的。MSVC和MinGW是两套完全不同的编译器体系,差异不只是“能不能编译”。第一层差异是C++的二进制接口(ABI):MSVC的符号修饰规则和MinGW的GCC不一样,extern "C"以外的C++导出符号在链接时无法互相解析。第二层是运行时库:MSVC默认链接msvcp140.dll和vcruntime140.dll,而MinGW链接libstdc++-6.dll和libgcc_s_dw2-1.dll。第三层是导入库格式:MSVC的.lib遵循COFF格式,MinGW的链接器只认.a或直接解析DLL导出表。所以哪怕你用MSVC编译出一个DLL,再让MinGW程序去显式加载,也会因为依赖链不一致而崩溃。
可能有人会想:那我不就用Qt的MSVC版就好了吗?确实,Qt官方同时提供MSVC版和MinGW版。但很多人的选择是被迫的——项目里已有第三方库只给了MinGW编译产物,或者客户指定的运行环境不允许装VC Redist,又或者是Qt Creator里默认的套件就是MinGW。这时候,OpenCV就必须自己从源码编译,跟你的MinGW编译器重新对齐。
2.2 Qt 5.9.6与OpenCV GUI后端的匹配逻辑
OpenCV的highgui模块默认在Windows上使用Win32原生窗口,也就是cv::imshow弹出的窗口背景是系统样式的。但如果你在CMake里开启了WITH_QT=ON,highgui就会改用Qt的窗口系统,好处很明显:窗口支持菜单栏、工具栏、状态栏,缩放和渲染由Qt接管,而且能跟同一进程里的QWidget界面共享事件循环。对于做桌面应用的人来说,这比Win32原生窗口舒服得多。
OpenCV 3.2.0匹配Qt 5.9.6的难点在于版本对齐。Qt 5.9.6是LTS,官方带的MinGW版本是5.3.0,也就是mingw53_32目录。而OpenCV 3.2.0发布时的MinGW分支还停留在4.x和5.2时代,源码本身没有对GCC 7+做什么特别支持,反而相对保守。所以用Qt自带的MinGW 5.3.0编译OpenCV 3.2.0,是网上被验证过次数最多的组合,也是踩坑最少的一条路。
2.3 一个容易被忽略的点:Qt库自身的编译器匹配
除了OpenCV需要配MinGW之外,你还要保证Qt库本身也是MinGW编译的。Qt安装目录里5.9.6/mingw53_32是MinGW版,msvc2015是MSVC版。如果你拿MSVC版的Qt库去链接MinGW编译的OpenCV,CMake会报Qt5::Core的导入库不兼容。正确的做法是让整条工具链统一:OpenCV用MinGW编译,Qt也用MinGW版,应用程序同样用MinGW。这条统一性,我在第一次自己编译时没注意,结果浪费了三个小时找了一个根本不存在的符号库问题。
提示:开始之前,先确认你的Qt套件是MinGW,而不是MSVC。菜单“工具→选项→Kits”里能看到编译器前缀,通常是
g++而不是cl。
3. 搭建MinGW编译环境并生成CMake配置:从工具链到Makefile
3.1 从Qt 5.9.6安装目录确认MinGW版本
如果你已经装了Qt 5.9.6,那么MinGW编译器通常就在Qt安装目录的Tools文件夹下,比如C:\Qt\Qt5.9.6\Tools\mingw530_32。打开这个目录,确认有bin\g++.exe。这个版本和Qt库编译时使用的完全一致,不用再单独去MinGW官网下载。如果你还没装Qt,建议直接下载Qt 5.9.6的在线安装包,并勾选“MinGW 5.3.0 32-bit”和“Qt 5.9.6”组件。注意Qt 5.9.6自带的是32位工具链,编译出来的OpenCV也是32位,这在Win10上运行没有任何问题,但别指望它能用超过4GB内存。
我一般会额外确认一下gcc --version的输出:MinGW 5.3.0对应的GCC版本是5.3.0,如果你看到“gcc (x86_64-posix-seh)”,说明你装的是64位的MinGW,与Qt自带的mingw530_32不是一套东西,两者混用会导致链接失败。所以环境里的PATH顺序很重要,最好把Qt自带的Tools\mingw530_32\bin放在所有其他MinGW路径之前。
3.2 下载OpenCV 3.2.0源码与CMake
编译OpenCV需要源码工程,不是预编译包。去OpenCV的GitHub仓库下载3.2.0的source包,解压到一个没有空格和中文的目录,比如C:\opencv\source。注意要先解压到英文路径,因为MinGW的make对带空格路径的处理一直不稳定。CMake需要3.5以上版本,我建议用3.10或3.12这类比较稳定的版本,去CMake官网下载安装包,安装时勾选“Add CMake to the system PATH”。这样后面可以直接在命令行用cmake。
OpenCV 3.2.0的源码结构里,modules\highgui负责GUI,modules\imgproc负责图像处理。编译整个OpenCV会包含几十个模块,但我们只需要核心模块和Qt支持。后面CMake配置会关闭不需要的模块,减少编译时间。
3.3 设置PATH和CMAKE_PREFIX_PATH
在CMD或PowerShell里先设置环境变量,让MinGW的编译器在PATH最前面:
set PATH=C:\Qt\Qt5.9.6\Tools\mingw530_32\bin;C:\Qt\Qt5.9.6\5.9.6\mingw53_32\bin;%PATH%这里把两个关键目录放到最前:一个是MinGW编译器,另一个是Qt库。这样CMake在查找编译器时会优先找到正确的g++,查找Qt时也能通过后续的CMAKE_PREFIX_PATH找准版本。不要只放编译器目录,Qt库目录也很重要,因为cmake的find_package需要在CMAKE_PREFIX_PATH里找Qt5Config.cmake。
设置一个专门的构建目录,我们不在源码目录里跑CMake,而是新建一个build-mingw-qt目录:
mkdir C:\opencv\build-mingw-qt cd C:\opencv\build-mingw-qt这样做的好处是源码目录保持干净,想重新配置时直接删掉build目录就行,算是一种后悔药。
3.4 CMake配置OpenCV:支持Qt的关键参数
现在正式跑CMake,我把常用参数写成一个完整的命令行:
cmake -G "MinGW Makefiles" \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_PREFIX_PATH="C:/Qt/Qt5.9.6/5.9.6/mingw53_32" \ -DWITH_QT=ON \ -DWITH_OPENGL=ON \ -DWITH_IPP=OFF \ -DWITH_TBB=OFF \ -DWITH_OPENCL=OFF \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_opencv_java=OFF \ -DBUILD_opencv_python=OFF \ -DBUILD_opencv_ts=OFF \ -DCMAKE_INSTALL_PREFIX="C:/opencv/install-mingw-qt" \ C:/opencv/source一行行拆开解释:
-G "MinGW Makefiles":生成Makefile,而不是Visual Studio工程。这里不能写"Unix Makefiles",否则Windows下会报错。-DCMAKE_BUILD_TYPE=Release:编译Release版本,速度最快,链接的运行时库也更干净。OpenCV 3.2.0对Debug版本的支持有些小坑,非要用Debug的话后面会遇到opencv_world320d.dll缺失的问题,建议先Release跑通。-DCMAKE_PREFIX_PATH:让CMake能定位到Qt 5.9.6的安装目录。这个路径必须指向mingw53_32,因为里面才有lib\cmake\Qt5Config.cmake。如果你只填C:/Qt/Qt5.9.6/5.9.6,CMake会去找默认编译类型(通常是MSVC)的Qt,导致找不到目标。-DWITH_QT=ON:打开Qt后端,这是让highgui用Qt渲染的核心开关。-DWITH_OPENGL=ON:Qt窗口渲染需要OpenGL支持,OpenCV的imshow在某些模式下会用到。-DWITH_IPP=OFF -DWITH_TBB=OFF -DWITH_OPENCL=OFF:这些加速库各自有编译器匹配问题。IPP库是Intel预编译的,MinGW下容易产生假链接错误;TBB需要额外下载,且版本冲突很常见;OpenCL在Qt窗口里没什么收益。关掉它们是最稳的组合。-DBUILD_SHARED_LIBS=ON:生成DLL动态库。虽然静态库能减少部署麻烦,但MinGW静态编译OpenCV时,Qt库也要是静态的,否则还是会依赖Qt的DLL,反而把问题搞复杂。-DBUILD_opencv_java=OFF -DBUILD_opencv_python=OFF -DBUILD_opencv_ts=OFF:这些都是不常用的模块,编译它们会拖慢时间,还有可能在MinGW下报一些奇怪的编译错误。做桌面应用,只需要opencv_core、opencv_imgproc、opencv_highgui、opencv_imgcodecs这几个核心模块。-DCMAKE_INSTALL_PREFIX:指定编译完成后安装的目标目录,后续给应用工程引用时会用到。
跑完CMake,屏幕上会出现一堆配置输出。最重要的信息在最后几行,你需要检查有没有Qt: YES。如果是Qt: NO,说明WITH_QT没有生效,回去看CMAKE_PREFIX_PATH是不是写错了。另外看下OpenCV modules列表里是否只列出了你要的模块,如果Java和Python还在,说明对应的BUILD_*开关没有生效,这通常是因为CMake缓存了上一次的配置,删掉build目录重跑一次就好。
4. 编译安装与验证:用CMake最小工程跑通Qt窗口
4.1 mingw32-make多线程编译与安装
CMake配置成功之后,在当前目录会生成Makefile和一堆中间文件。使用MinGW工具链时,编译命令不是make,而是mingw32-make。按-j参数指定并行任务数,我一般用4,因为MinGW的g++很吃内存,8个并行任务在8GB内存的机器上可能直接把系统卡死:
mingw32-make -j4首次编译OpenCV 3.2.0大概需要20到40分钟,取决于机器配置。如果中途报错,先别急着重跑,把错误信息里第一个文件路径和行号记下来,多半是某个模块的源码问题。最常见的报错是longlong类型重定义或SSE指令集不兼容,这时把对应模块关掉再重新CMake即可。
编译完成后执行安装,把OpenCV的头文件、库文件和DLL统一放到CMAKE_INSTALL_PREFIX指定目录:
mingw32-make install安装结束后,C:\opencv\install-mingw-qt下会有include、bin、lib三个目录。bin\opencv_world320.dll就是合并后的核心库,lib\libopencv_world320.dll.a是导入库。注意OpenCV 3.2.0默认把模块合并成了world单库,这对MinGW用户反而省心,因为不用一个个去联opencv_core320.dll、opencv_highgui320.dll这些分散的动态库。
4.2 安装结果与DLL组织
打开install-mingw-qt\bin目录,你会看到类似这样的文件:
| 文件 | 说明 |
|---|---|
| opencv_world320.dll | 核心动态库 |
| opencv_ffmpeg320.dll | 视频读写用的FFmpeg辅助库 |
| libopencv_world320.dll.a | MinGW链接用的导入库 |
注意opencv_ffmpeg320.dll不是world的一部分,它是运行时动态加载的。如果你的程序要读视频,这个DLL必须一起部署。另外Qt的DLL并不在这个目录里,它们在C:\Qt\Qt5.9.6\5.9.6\mingw53_32\bin,后面运行程序时需要把Qt的DLL也带上。
记住bin目录是运行时目录,lib目录是链接时目录。CMake配置应用时,find_package(OpenCV)会从install-mingw-qt\lib\cmake\opencv2读取配置。
4.3 最小示例验证Qt后端
现在创建一个极小的控制台工程来验证OpenCV是否真的用了Qt窗口。新建一个目录,里面放一个main.cpp和CMakeLists.txt。
main.cpp:
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> int main(int argc, char** argv) { // 构造一张320x240的黑色图像 cv::Mat img(320, 240, CV_8UC3, cv::Scalar(0, 0, 255)); if (img.empty()) { return -1; } // imshow会优先使用Qt窗口,如果编译时启用了Qt后端 cv::imshow("Qt Window Test", img); cv::waitKey(0); return 0; }CMakeLists.txt:
cmake_minimum_required(VERSION 3.5) project(OpenCVQtTest) set(CMAKE_PREFIX_PATH "C:/opencv/install-mingw-qt" "C:/Qt/Qt5.9.6/5.9.6/mingw53_32") find_package(OpenCV REQUIRED) find_package(Qt5 REQUIRED COMPONENTS Widgets) add_executable(OpenCVQtTest main.cpp) target_link_libraries(OpenCVQtTest ${OpenCV_LIBS} Qt5::Widgets)这里在CMAKE_PREFIX_PATH里同时写了OpenCV安装目录和Qt目录,这样两个find_package都能找到各自的配置。链接Qt5::Widgets是为了让程序在链接时带上Qt的初始化代码,否则运行时可能报QWidget: Cannot create a QWidget without QApplication。虽然OpenCV的highgui内部会创建QApplication,但显式链接上更稳妥。
编译验证工程:
set PATH=C:\Qt\Qt5.9.6\Tools\mingw530_32\bin;C:\Qt\Qt5.9.6\5.9.6\mingw53_32\bin;C:\opencv\install-mingw-qt\bin;%PATH% cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release . mingw32-make -j2 OpenCVQtTest.exe运行时能看到窗口标题是“Qt Window Test”,并且窗口风格是Qt的,说明OpenCV的imshow确实走的Qt后端。如果弹出来的窗口没有任何关闭按钮以外的控件,甚至启动时崩溃,那基本就是WITH_QT没生效。
5. 避坑:MinGW+OpenCV+Qt常见问题的排查与解决
5.1 链接报错:未定义引用_imp____Z...
现象:用find_package(OpenCV)链接后,出现一长串undefined reference to 'imp___ZN2cv6imshowERKNSt7__cxx1112basic_string...'之类的内容,符号名里带imp_。
原因:你链接的OpenCV库是MSVC编译的DLL导入库,或者MinGW版本与OpenCV库的编译版本不一致。imp_前缀是MinGW对动态库导入符号的修饰方式,但MSVC的导入库不产生这种符号,MinGW只能从DLL自身导出表中查找,找不到就报错。
解决:确认你的CMake工程里OpenCV_DIR指向的是我们自己编译的install-mingw-qt\lib\cmake\opencv2。在CMake缓存里查看OpenCV_LIBS,如果是opencv_world320,那就需要确认这个库是用哪个编译器生成的。最简单的验证方式:用strings命令查看opencv_world320.dll里是否含QtWidgets字符串,有就说明确实是Qt版,没有则说明是纯Win32版。
5.2 CMake找不到Qt5Config.cmake
现象:运行CMake时提示Could not find a package configuration file provided by "Qt5",或者Qt5::Core找不到。
原因:CMAKE_PREFIX_PATH没有指向Qt的MinGW版本目录,或者Qt安装时只装了MSVC版组件。很多人在安装Qt时选了5.9.6,但没注意到安装包里有两个5.9.6目录:msvc2015和mingw53_32,如果CMake找到的是前者,会因为它声明的编译器是MSVC而拒绝使用。
解决:把CMAKE_PREFIX_PATH明确写成C:/Qt/Qt5.9.6/5.9.6/mingw53_32,不要只写到5.9.6根目录。如果还是找不到,手动检查C:/Qt/Qt5.9.6/5.9.6/mingw53_32/lib/cmake/Qt5/Qt5Config.cmake是否存在。不存在的话,需要重新运行Qt安装程序,勾选“MinGW 5.3.0”组件。
5.3 编译中断:内存不足与命令过长
现象:mingw32-make -j4跑到一半,控制台输出g++: fatal error: Killed,或者Error: spawn failed,系统内存占用接近100%。
原因:OpenCV 3.2.0的opencv_contrib模块和一些大型模板文件会让单个编译单元占用1.5GB以上内存。MinGW的g++在Windows上又比较吃地址空间,32位编译还好,但多线程并行时会同时吃内存。
解决:把并行度降到-j2,同时关闭不必要的模块。我在CMake配置时就已经把BUILD_EXAMPLES、BUILD_TESTS、BUILD_PERF_TESTS都设成OFF,这几个会额外产生大量编译任务。如果内存还是不够,考虑把编译机的虚拟内存(页面文件)调大,或者改用64位MinGW工具链(但Qt 5.9.6自带的是32位,需要额外下载64位MinGW,且要自己编译匹配的Qt,工作量会变大)。
5.4 混合使用MSVC和MinGW产生的重定义
现象:链接时报一堆duplicate symbol或multiple definition of ...错误。
原因:项目的其他库是MSVC编译的,而OpenCV是MinGW编译的。两个不同编译器生成的静态库(.lib和.a)在符号命名上的规则冲突,导致同一个cv::Mat方法在多个库中存在不同版本或多个定义。
解决:必须保证整个依赖链都使用同一编译器。检查项目里是否还有其他第三方库是用MSVC编译的,如果无法重编这些库,那就把Qt、OpenCV和应用全部切到MSVC编译。反过来,如果坚持用MinGW,就要把其他库也拿到MinGW下重新编译。没有第三条路。
5.5 Windows下路径带空格导致的诡异失败
现象:CMake配置通过,但编译时出现No rule to make target 'C:/Program'的错误,或者生成的OpenCVQtTest.exe双击后立刻闪退,事件查看器里显示找不到opencv_world320.dll。
原因:C:\Program Files这类含空格的路径,在Cmake生成的Makefile中会拆成两个参数。MinGW的make对路径解析比MSVC更脆弱,尤其是CMAKE_INSTALL_PREFIX和源码路径。第二个原因,运行时DLL搜索路径不包含OpenCV的bin目录,程序启动时找不到DLL。
解决:所有与编译相关的路径,包括源码目录、构建目录、安装目录,全部放到像C:\opencv、C:\Qt这种无空格路径下。运行程序时把opencv_world320.dll和Qt的DLL复制到程序同目录,或者设置PATH环境变量包含这些bin目录。我习惯在调试时写一个run.bat,里面用set PATH=...临时注入依赖目录,这样不污染系统环境。
6. 进阶:用windeployqt整理运行时依赖,让程序在别的Win10上直接跑
自己编译OpenCV只是第一步,真正麻烦的是把程序部署到没有开发环境的机器上。MinGW编译的程序运行时会依赖libgcc_s_dw2-1.dll、libstdc++-6.dll、libwinpthread-1.dll,加上Qt的DLL和OpenCV的DLL,手动一个个复制很容易漏。Qt提供了windeployqt工具,可以自动扫描exe依赖的Qt模块并复制对应DLL。
在编译完OpenCVQtTest.exe后,进入exe所在目录执行:
C:\Qt\Qt5.9.6\5.9.6\mingw53_32\bin\windeployqt.exe OpenCVQtTest.exe运行后,exe所在目录会多出一堆Qt5Core.dll、Qt5Gui.dll、Qt5Widgets.dll以及platforms目录下的qwindows.dll。platforms这个目录特别重要,缺少它,Qt程序启动时会报qt.qpa.plugin: Could not find the Qt platform plugin "windows"。
然后还需要手动补上MinGW运行时和OpenCV的DLL:
copy C:\Qt\Qt5.9.6\Tools\mingw530_32\bin\libgcc_s_dw2-1.dll . copy C:\Qt\Qt5.9.6\Tools\mingw530_32\bin\libstdc++-6.dll . copy C:\Qt\Qt5.9.6\Tools\mingw530_32\bin\libwinpthread-1.dll . copy C:\opencv\install-mingw-qt\bin\opencv_world320.dll .这里有个血泪教训:opencv_ffmpeg320.dll必须在运行目录或系统PATH里,但windeployqt不会复制它。如果你的程序用到了VideoCapture,没这个DLL时不会报错,而是打开摄像头或视频文件时直接静默失败。我先前排查了一个下午,最后用Dependency Walker才看到加载失败的opencv_ffmpeg320.dll。
验证部署结果,可以用Qt自带的windeployqt --list查看它认为的依赖清单,再用dumpbin或MinGW的objdump -p检查exe的导入表:
objdump -p OpenCVQtTest.exe | grep "DLL Name"输出的每一行就是程序依赖的DLL。对比一下运行目录里的文件,缺失的补齐就完事。这一步做一遍,以后每次编译只要跑一个批处理文件就解决了。
最后说一点我的习惯:我把这套OpenCV编译环境固定成了一套脚本,放在C:\opencv\build-mingw-qt里作为基线。遇到新机器或新项目时,不重新折腾CMake参数,直接拿来用。遇到编译器版本升级时,我会先小范围编译opencv_core和opencv_highgui,跑通Qt窗口再上全量编译,这样能省掉大量等待时间。希望帮到你。
本文还有配套的精品资源,点击获取