Qt 7.0 + OpenCV 4.5.5 环境配置:MinGW与MSVC双路线实战指南 1. 写在前面的环境说明1.1 我最终敲定的版本组合最近把项目从老旧的Qt 5.12往新版本迁移需要在一个全新的Win10 64位环境里把OpenCV 4.5环境调通。网上关于Qt配置OpenCV的教程一抓一大把但我照着操作下来发现真正的问题是版本组合太多了每个教程用的编译器、Qt版本、OpenCV版本都不一样照着抄很容易翻车而且翻车的姿势千奇百怪。这里先把我的组合写清楚Qt 7.064位套件 OpenCV 4.5.5 CMake 3.20 编译器选了MinGW 64位。我特意测试了两条路线一条是配合MSVC编译器使用官方预编译包另一条是配合MinGW编译器从源码用CMake自己编译。两条路都跑通了但耗时和坑的数量完全不同。这篇内容会把两条路都写清楚你按自己的编译器情况选一条就行。先说一下为什么要纠结编译器。Qt 7.0安装的时候通常会让你勾选套件Kit最常见的就是MSVC和MinGW两种。OpenCV官方发布的预编译包说到底是为MSVC准备的库文件用的是MSVC的格式MinGW去链接这些库是行不通的。所以配置之前你得先想明白自己的Qt套件用的是哪个编译器再决定走哪条路。这个决策顺序搞反了后面都是白忙活。1.2 三条路线怎么选预编译包、源码编译还是在线安装配置OpenCV环境本质上就三条路。第一条直接用OpenCV官方预编译包加MSVC编译器。这个方案最省事OpenCV官网下载编译好的Windows版本里面已经包含了头文件、静态链接库、动态链接库你只需要在Qt工程文件里把include目录和lib目录指过去就行。但我提醒一句这个包里的库是按MSVC的ABI应用二进制接口编译的所以你的Qt套件必须选MSVC系列。我用的是MSVC 2019 64位的套件来对应的。第二条用MinGW编译器的话就得从源码用CMake自己编译OpenCV。因为OpenCV官方没有给MinGW提供预编译的库。这条路麻烦在要安装CMake、配置源码编译耗时看机器性能通常半个小时到一个小时。但好处是生成的库跟你的MinGW编译器是严格匹配的不会出现链接时ABI不兼容的问题而且你可以自己裁剪编译的模块比如只编译需要的模块可以省出不少空间和时间。第三条通过vcpkg或conda这类包管理器安装。这个我在某个X86模拟项目里临时用过确实方便一条命令就装好了但它把OpenCV都装进了包管理器自己的目录里你Qt工程引用起来反而不太直观。而且vcpkg默认集成的方式在Qt Creator里如果不用它的CMake预设工具链容易产生路径和编译选项不一致的问题。所以这篇的内容我主要讲前两种包管理器的方式就提一句你自己去尝试的时候有个心理预期就好。我个人经验是你的目标如果是尽量少折腾、赶紧把功能跑起来那就用MSVC加官方预编译包。如果是想要一个干净可控的环境、后面可能还要自己给OpenCV源码打补丁那就用MinGW加源码编译。这里没有绝对的好坏只有适合不适合。我项目里实际现在用的是MinGW编译出的库后面会详细说为什么。2. 最省事的路线官方预编译包加MSVC2.1 下载与安装注意把目录权限管好先说官方预编译包这条路的具体操作。去OpenCV官网的Releases页面找4.5.x系列下载winpack版本。这里我不放具体链接因为版本和站点结构会变你只要记着下载那个大概两三百兆的exe自解压文件就行。之前有朋友下载成源码包解压出来只有cmake文件和源码白白花了一段时间去排错——类似这种文件选错的问题我在圈里见过不止一次。下载后双击自解压它会把文件释放到你指定的目录。这里有个细节很多人不注意如果你释放到了比如C盘根目录而你的Windows用户名是中文名称或者当前用户对这个目录没有完全控制权限后面编译报错各种“无法打开文件opencv_world455.lib”的概率会大增。我一般习惯解压到一个纯英文路径下比如D:\Libs\opencv454把权限问题的风险直接规避掉。这种小习惯能省去很多无头绪的排查时间。解压完成后目录结构大概是这样的opencv/ build/ include/ x64/ vc15/lib/ vc15/bin/ vc16/lib/ vc16/bin/ sources/注意里面有个vc15和vc16的区分。vc15对应的是VS2017vc16对应的是VS2019。我用的是MSVC 2019套件所以后面链接库的时候选的是vc16目录下的库文件。如果你用MSVC 2017就去找vc15。这个细节搞错了链接阶段很容易报出一个版本不匹配的奇怪错误。2.2 在Qt的pro文件里把路径写对如果你是qmake工程就在.pro文件里加这样一段配置INCLUDEPATH D:/Libs/opencv454/build/include \ D:/Libs/opencv454/build/include/opencv2 LIBS D:/Libs/opencv454/build/x64/vc16/lib/opencv_world455.lib上面这些是release模式的配置。如果你还打算在debug模式下调试程序就得再补上debug版的库。OpenCV库文件通常会区分为带d和不带d的后缀opencv_world455.lib是release版本opencv_world455d.lib是debug版本。两个最好都加上用debug编译时加d版本release时加不带d。我见过有人图省事只加一个结果debug模式下运行程序直接在加载库的阶段崩溃还以为是代码写错了。那段配置加完之后最终的形式应该是类似这样INCLUDEPATH D:/Libs/opencv454/build/include CONFIG(debug, debug|release) { LIBS D:/Libs/opencv454/build/x64/vc16/lib/opencv_world455d.lib } else { LIBS D:/Libs/opencv454/build/x64/vc16/lib/opencv_world455.lib }写完之后qmake会重新解析一次如果你用的是MSVC套件这时候直接编译理论上就能过了。我第一次配置的时候编译一直报错后来发现是我在pro文件里忘了指定CONFIG两种库同时链接进去了导致重复符号冲突。2.3 运行时DLL问题把dll放到该放的位置链接通过只代表编译链接成功程序能不能跑起来还得看运行时能不能找到DLL。官方包里的DLL放在build\x64\vc16\bin目录下有opencv_world455.dll和opencv_world455d.dll两个。运行Qt程序默认会去可执行文件所在的目录找DLL找不到就报那个经典的“程序无法启动因为计算机中丢失opencv_world455.dll”的错误。解决办法有几种把bin目录配置到系统环境变量Path里面或者把需要的DLL直接复制到exe旁边。我建议在开发阶段直接把DLL复制到构建目录下这样最直观、最快。后期要发布软件时再统一处理DLL打包的问题。还有一点如果你Debug和Release两种模式都在用最好把两个DLL都复制过去免得切换模式时找不到对应的DLL。注意Debug模式的exe需要的是带d后缀的DLLRelease模式则是普通的那一个混用的话程序会闪退或直接报内存相关的错误。2.4 跑通第一个测试程序配置好之后不要犯我当年的错误上来就写复杂的图像处理代码。先写一个最简单的程序验证环境通不通#include opencv2/opencv.hpp #include QDebug using namespace cv; int main() { Mat img imread(D:/test.jpg); if (img.empty()) { qDebug() 图片加载失败; return -1; } qDebug() 图片加载成功, 尺寸: img.cols x img.rows; return 0; }这个程序能跑通说明头文件路径、库路径、DLL路径三个环节都打通了。在这里我遇到过一个问题imread返回空的Mat但图片明明就在那个路径。我排查半天最后发现是图片路径里带了中文OpenCV的imread在某些版本环境下对中文路径支持不好。解决办法是测试阶段把测试图片放到纯英文路径下比如D盘根目录。这个问题后面会单独说。3. 更通用的路线MinGW配合CMake自己编译3.1 为什么要自己编译官方库与MinGW不匹配如果你的Qt套件是MinGW而不用MSVC上面那些步骤就完全行不通了。原因其实很简单C/C编译器和链接器之间动态库和静态库的格式是需要匹配的。MSVC用的库格式和MinGW用的格式不一样硬链接会出现成片的未定义引用错误信息类似这样undefined reference to cv::imread(std::string const, int)这个错误非常具有迷惑性因为它看起来像头文件声明和库实现对不上但本质是编译器和你链接的库是两套体系互不相认。解决办法就是换库要么你换成MSVC的Qt套件要么你用MinGW从源码编译OpenCV。我因为项目的后续构建流程已经固定在MinGW体系里了所以选了后者。自己编译需要注意的软件有OpenCV源码包、CMake工具、MinGW编译环境。如果你的Qt安装时自带了MinGW编译器那就直接用那个如果没有去下载跟Qt版本匹配的MinGW版本。版本匹配这块Qt 7.0不同小版本对MinGW版本有对应关系尽量在Qt安装目录下找它自带的那个省得出兼容性问题。3.2 CMake配置步骤关键的几个开关先创建两个目录一个是存放OpenCV源码的目录解压后的sources另一个是编译输出目录比如D:\Libs\opencv-mingw-build。打开CMake GUI把源码目录和输出目录填进去。然后选择编译器点击Configure指定生成的工程要用MinGW Makefiles。这里最关键的一步是指定编译器时确保你指定的是64位的MinGW编译器gcc.exe和g.exe而不是32位版本。选错编译器是最隐蔽的坑因为它报错的时候完全不会提32位还是64位只会说一些奇怪的链接错误。Configure完成之后会有非常多的CMake选项。我建议这样设置关键的几个值CMAKE_BUILD_TYPE Release BUILD_opencv_world ON WITH_OPENCL OFF WITH_MSMF OFF ENABLE_CXX11 ONBUILD_opencv_world这个开关我强烈建议打开它会生成一个集中式的库后面在Qt里链接时只需要一个库文件不用面对一大堆模块库。OpenCV模块非常多默认情况下每个模块一个库链接配置就会非常冗长。WORLD模式能省掉这堆麻烦。然后还需要设置CMAKE_MAKE_PROGRAM指向mingw32-make.exe的完整路径。这一步如果不设置生成阶段会卡住或者它找不到make程序。CMake GUI和命令行版本我都试过GUI模式下指着比较方便生成后你还能看得到很多选项的最终值方便追踪。全部配置好之后点Generate生成MinGW的Makefile。一切顺利的话CMake窗口下方会显示“Generating done”。如果在这一步就报错了我建议先别急着往下走认真看错误信息多半是编译器路径不对或者CMake版本太老。3.3 编起来时长和常见小坑生成Makefile之后进入编译输出目录打开命令行执行mingw32-make -j8后面的数字是并行编译线程数一般建议设成你CPU核心数的差不多两倍。我第一次编译OpenCV的时候老老实实用单线程结果等到天荒地老后来改用-j8速度快了不是一点半点。这个编译过程我实测下来普通配置的电脑大概需要半小时左右。期间看到屏幕上飞速滚过的编译信息不用慌只要最终没有出现红色的error都是正常现象。等编译完成后再执行一次mingw32-make install这条命令会把你编译好的头文件和库文件统一安装到CMake里设置过的install前缀目录下一般默认是D:\Libs\opencv-mingw-build\install。以后Qt工程引用的就是install目录下的东西而不是编译中间目录里的东西。编译期间容易遇到的问题比较典型的就是C标准报错比如报“unrecognized command line option”之类的。这种情况基本都是MinGW编译器版本和OpenCV 4.5源码要求不一致导致的。还有就是把BUILD_opencv_world打开后最终生成的库文件会非常大这没关系属于正常现象别看到文件很大就以为编译出错了。3.4 编译完成后的工具链匹配检查编译完成之后你要重点看一眼install目录下有什么。正常情况下include下有opencv2目录lib下有libopencv_world455.a这样的静态库文件bin下有opencv_world455.dll和opencv_world455d.dll这些运行时库文件。注意这里生成的文件名和官方预编译包不一样官方那个是opencv_world455.libMinGW编译出来是libopencv_world455.a。带d和不带d的还是同样的思路区分debug和release。你在pro文件里写链接时是这样的INCLUDEPATH D:/Libs/opencv-mingw-build/install/include LIBS -LD:/Libs/opencv-mingw-build/install/lib \ -lopencv_world455这个写法是MinGW常用的链接方式-L指定库目录-l指定库名库名不需要带前缀lib和后缀.a。如果是Debug模式库名要换成-lopencv_world455d。如果你看到这里眼熟了说明你已经开始理解工具链的匹配逻辑了。我自己在这个环节上踩过不少次坑最深刻的一次是我费劲编译完了OpenCV结果在Qt里把套件选错了用的还是MSVC套件去链接MinGW编译的库结果报错报得比之前还狠。记住MinGW编译出来的库只能给MinGW套件的Qt项目用MSVC和MinGW绝对不能混用这个规律放之四海而皆准。还有一个我自己摸索出来的习惯编译完OpenCV之后我可以先单独写一个极小的纯C项目不依赖Qt直接用MinGW的命令行编译一下确认库本身没问题再把这个库接进Qt工程。如果这个最小的项目也报链接错误那问题就在OpenCV编译本身不在Qt配置这样排查范围立刻缩小一半。4. 实操现场帮你绕过去的几个坑4.1 坑一Opencv版本、Qt版本和编译器版本三者排列组合的相爱相杀OpenCV版本、Qt版本、编译器版本这三者的版本号就像三个互相咬合的齿轮一个版本换掉另外两个不一定还跟着咬合。我在实际操作里最头疼的不是某个软件装不上而是OpenCV新版本和旧编译器不兼容。比如OpenCV 4.5.x需要编译器支持C11以上标准如果你的MinGW太老编译期报错会非常多但我能怎么办只能用新版本MinGW。同理如果你换了一个新版本的Qt它自带的MinGW版本往往也跟着更新了这时候如果OpenCV还是你半年前编译好的老库最好重新编译一次OpenCV稳妥第一。我认识一位同行为图省事一直用官方预编译包配合MSVC后来Qt升级后发现插件不兼容整个编译环境乱了套最后花了大半天才理顺。我的经验是版本升级要整体升不要只升其中一个而且升级完OpenCV一定要重新跑一遍最简单的读图测试确认所有环节还咬得住。4.2 坑二Debug和Release库的区分必须严肃对待这个坑我反反复复掉进去过值得单独讲一遍。OpenCV的编库规则是Debug库文件名带后缀dRelease库文件名不带d。比如opencv_world455d.dll就是给Debug用的opencv_world455.dll是给Release用的。Qt Creator左下角有Debug和Release两个构建模式按钮很多人不注意切换。如果你在Debug模式下却链接了Release库程序会直接在启动时崩溃或者运行表现奇怪。我当时还傻乎乎地去查代码直到把构建模式切到Release模式一切正常才醒悟过来。为了防止再犯这个错误我现在总是在pro文件里用CONFIG来判断构建模式分别指定不同库名这样代码写死了后无论怎么切换模式都不会配错。这个经验特别重要尤其你刚配置好环境代码还没跑起来之前先确认自己当前是什么构建模式再去检查pro文件里链接的库是哪个版本。4.3 坑三CMake编译OpenCV时生成的Makefile需要手动指定make程序有次我帮一个朋友远程看问题他卡在CMake生成阶段死活过不去报一堆关于sh.exe的错。后来发现CMake在生成MinGW的Makefile时默认去系统环境里找make程序但系统里装了不止一个make工具它们配置方式又不一样互相干扰导致生成出来的Makefile用的编译命令是错的。解决办法其实很简单在CMake第一次Configure之后找到CMAKE_MAKE_PROGRAM这个选项手动指定到你Qt安装目录下MinGW的bin目录里的mingw32-make.exe然后再点Generate。指定完之后后续生成和编译就顺了。可能你也想到了本质就是让CMake明确知道使用哪个make工具不留给它猜的余地。4.4 坑四中文路径导致的图片读取失败这个我之前其实提过。我一开始写测试程序放了一张图在桌面文件名叫“测试图片.jpg”结果imread出来始终是空的。OpenCV的imread函数在处理中文路径时很多版本底层实现的编码转换都不支持导致路径解析失败返回空Mat。这个问题网上你能搜到各种各样的偏方但其实最省心的方法就是开发调试阶段所有路径一律用纯英文不带空格。这不光是为了OpenCVWindows下很多库对中国开发者都不算友好带中文的路径总是或多或少出点幺蛾子。如果你的业务场景必须支持中文路径那就得升级到用fstream这些标准库自己读取文件再转成Mat数据但那是另一个复杂话题了。现阶段测试阶段先保持路径简单别给自己添堵。4.5 坑五OpenCV头文件版本冲突还有一种情况是你的系统里曾经装过其他版本的OpenCV或者通过Python装过导致include搜索路径不小心指到了另外一个版本的opencv头文件然后编译报各种奇怪的定义错误。我经验里最坑的一次是我pro文件明明写的4.5.5的库但include路径配置的时候阴差阳错地指到了一个老项目的第三方目录下结果编译器找到的是那个老版本的opencv.hpp。它里面有API定义和4.5.5的库实现对不上编译时全是红色波浪线错误。排查思路就是确认你的编译器实际使用的头文件路径到底是哪个。可以在pro文件里临时加上一行message(include path: $$INCLUDEPATH)编译时在“编译输出”窗口看实际展开的include路径绝对能定位出问题所在。这个技巧我一直当成杀手锏使用当环境变量、系统目录、项目目录多个来源混杂时它能让问题变得极其清晰。5. 快速验证项目与收尾建议5.1 第一个Demo完整代码结构参考配置完成之后建议直接把下面这个示例项目完整跑一遍。先从最简单的图像读取和显示开始验证整个链路是通的。项目结构可以很简单一个main.cpp文件加一个.pro文件。main.cpp的代码#include opencv2/opencv.hpp #include QDebug using namespace cv; using namespace std; int main(int argc, char *argv[]) { string imgPath D:/test.png; Mat src imread(imgPath); if (src.empty()) { qDebug() 图片读取失败请检查路径; return -1; } Mat gray; cvtColor(src, gray, COLOR_BGR2GRAY); imwrite(D:/test_gray.png, gray); qDebug() 处理完成原图尺寸 src.cols src.rows; return 0; }这段代码做的事情很朴素读取一张彩色图转成灰度图保存到新文件。但就是这三行核心操作把OpenCV最基础的图像数据结构Mat、最常用的读图、颜色转换、写图接口全验证了一遍。如果这段程序能跑通说明你整个环境里最关键的环节已经没有问题了。5.2 再验证一个摄像头实时视频流图像读写没问题之后建议再跑一个摄像头视频流捕获的Demo因为摄像头涉及视频IO模块这个模块在你编译OpenCV时如果没启用或者系统缺少相应驱动会报一些很隐蔽的运行时错误。代码类似这样VideoCapture cap(0); if (!cap.isOpened()) { qDebug() 无法打开摄像头; return -1; } Mat frame; while (cap.read(frame)) { imshow(live, frame); if (waitKey(30) 0) break; } cap.release(); destroyAllWindows();这段代码里imshow和waitKey这两个函数还需要配合一个图形窗口环境在Qt的GUI程序里用通常没问题。你在验证时如果摄像头打不开先检查设备是否被占用再检查编译时WITH_MSMF等视频后端相关选项有没有开启。这个Demo通过之后摄像头相关的开发你心里就有底了。5.3 收尾的几个小建议配置环境这件事看似是一个操作活其实核心逻辑就一个确保编译器、库、路径三者严格匹配。这话听起来跟没说一样但你一旦在配置环境时把这条原则刻进脑子里就不会犯低级错误。具体说就是你得时刻清楚自己的Qt套件用的是哪个编译器是MSVC就配官方库是MinGW就自己编译别混搭路径里的每个头文件目录、库文件目录你都得能说出它的来源模糊的地方宁可多花时间确认也别侥幸跳过。Debug和Release库的区分中文路径的坑dll复制到exe旁边这些是三个高频问题基本覆盖我见过的九成配置报错场景。你如果能在这三个点上有意识地在工程文件里做好处理后面的开发会顺很多。对了还有一个小技巧分享给你无论配置什么环境我都有一个习惯就是新建一个专门用来验证环境的临时工程在这个工程里只写最简单的功能性代码。验证通过之后这个工程就被我标记为“环境配置检查清单”之后每次升级软件或者换电脑第一时间跑一遍能省去大量排错时间。这套组合我前后配置了好几遍从最开始的懵圈到后来的轻车熟路也就经历了上面说的这些坑。希望这篇内容能帮你少走一些弯路。如果你的环境组合跟我不完全一样梳理逻辑是一样的关键是先摸清你的编译器再决定你的OpenCV获取方式基本就不会出大差错。