news 2026/10/24 4:58:12

Qt 7.0 + OpenCV 4.5.5 环境配置:MinGW与MSVC双路线实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
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.0(64位套件)+ 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. 最省事的路线:官方预编译包加MSVC

2.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对应的是VS2017,vc16对应的是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后缀的DLL,Release模式则是普通的那一个,混用的话程序会闪退或直接报内存相关的错误。

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 = ON

BUILD_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.lib,MinGW编译出来是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需要编译器支持C++11以上标准,如果你的MinGW太老,编译期报错会非常多,但我能怎么办,只能用新版本MinGW。同理,如果你换了一个新版本的Qt,它自带的MinGW版本往往也跟着更新了,这时候如果OpenCV还是你半年前编译好的老库,最好重新编译一次OpenCV,稳妥第一。

我认识一位同行,为图省事一直用官方预编译包配合MSVC,后来Qt升级后发现插件不兼容,整个编译环境乱了套,最后花了大半天才理顺。我的经验是,版本升级要整体升,不要只升其中一个,而且升级完OpenCV一定要重新跑一遍最简单的读图测试,确认所有环节还咬得住。

4.2 坑二:Debug和Release库的区分必须严肃对待

这个坑我反反复复掉进去过,值得单独讲一遍。OpenCV的编库规则是:Debug库文件名带后缀d,Release库文件名不带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。这个问题网上你能搜到各种各样的偏方,但其实最省心的方法就是:开发调试阶段,所有路径一律用纯英文不带空格。

这不光是为了OpenCV,Windows下很多库对中国开发者都不算友好,带中文的路径总是或多或少出点幺蛾子。如果你的业务场景必须支持中文路径,那就得升级到用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获取方式,基本就不会出大差错。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/24 4:58:09

数字人本地部署实战:10分钟跑通离线口播视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/24 4:55:36

CARLA源码编译安装完全指南:环境配置与避坑实操

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/24 4:55:33

PCA9422与STM32L031C6超低功耗电源管理协同设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/24 4:55:33

深入理解 diff:从 LCS 算法原理到代码审查与配置管理实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/24 4:55:32

TVD格式详解:从原理到CFD与气象模拟的工程实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华