简介:本资源为OpenCV 4.8.0在Windows平台下使用MinGW编译的完整源码包,面向需要在Windows环境中构建计算机视觉与机器学习应用的开发者,尤其适合希望摆脱Visual Studio依赖、使用MinGW工具链进行编译的中高级C++程序员。压缩包共约2000个文件,涵盖750个cpp源文件、317个hpp头文件、222个Python脚本、157个Java文件及135个C头文件,另含HTML文档、XML配置、Markdown说明与JSON数据等,整体约282.62MB,结构完整,便于按模块查阅源码与构建脚本。资源涉及DNN模块、视频编解码、图像处理等核心功能,并包含ffmpeg、tbb等依赖库的编译配置参考。已有330人学习下载。通过阅读源码与CMake配置,读者可掌握OpenCV在MinGW下的编译流程、模块裁剪与性能优化思路,为后续图像处理与模式识别项目开发打下基础。
1. OpenCV 4.8.0 + MinGW 编译:为什么你搜到的教程都跑不通
如果你在 Windows 上写 C++,又不想装几个 G 的 Visual Studio,MinGW-w64 几乎是唯一顺手的工具链。但当你兴冲冲去下 OpenCV 官方 Windows 包,解压一看,build/x64/vc16目录里全是.lib和.dll——那是给 MSVC 用的,MinGW 的g++根本链接不上。于是你开始搜「OpenCV MinGW 编译」,照着某篇教程敲 CMake,结果不是卡在下载ffmpeg的 7z 包,就是编译到一半报undefined reference to std::filesystem,再不然就是编完了pkg-config找不到路径。这篇笔记就是把我自己踩过的这条链路完整拆开:从工具链选型、CMake 参数怎么配、哪些模块该关、到编完怎么验证、怎么在 CMake 项目里引用。适合已经会写 C++、但被 OpenCV 官方包卡住的 Windows 开发者,也适合想把 OpenCV 塞进 CI 流水线的人。核心结论先放这:MinGW 编译 OpenCV 的成败,八成取决于工具链版本和 CMake 参数是否对齐,跟你的 CPU 快慢关系不大。
2. 工具链选型:MinGW-w64 的版本和线程模型怎么定
2.1 为什么不是随便一个 MinGW 都能编
OpenCV 4.8.0 的源码里大量使用了 C++17 特性,尤其是std::filesystem、std::optional和结构化绑定。如果你手里的 MinGW 是那种老旧的 MinGW.org 版本(gcc 8 以下),编译到modules/core/src/utils/filesystem.cpp就会直接报错。更隐蔽的坑是线程模型:MinGW-w64 有win32和posix两种线程实现,OpenCV 的parallel_for和std::thread依赖 posix 线程模型,如果你装的是x86_64-w64-mingw32-gcc默认 win32 线程,链接阶段会缺pthread相关符号。
我一般推荐用MSYS2 提供的 MinGW-w64 工具链,因为它的包管理能保证 gcc、cmake、ninja 版本互相兼容,省去手动配 PATH 的麻烦。具体来说,在 MSYS2 的 UCRT64 环境里,gcc 版本至少 13.2,cmake 至少 3.27,ninja 至少 1.11。UCRT64 比 MINGW64 更贴近 Windows 原生运行时,编出来的二进制依赖ucrtbase.dll,在 Win10 以上系统不需要额外分发运行时。
2.2 安装工具链和依赖的完整命令
打开 MSYS2 UCRT64 终端,逐条执行。注意包名里的ucrt-x86_64前缀,装错了环境后面 CMake 会找不到编译器。
# 更新包数据库和基础包,遇到提示选 y pacman -Syu # 安装 UCRT64 工具链:gcc、cmake、ninja、pkg-config pacman -S --needed \ mingw-w64-ucrt-x86_64-gcc \ mingw-w64-ucrt-x86_64-cmake \ mingw-w64-ucrt-x86_64-ninja \ mingw-w64-ucrt-x86_64-pkgconf # 安装 OpenCV 的可选依赖:图像编解码、视频 IO、GUI pacman -S --needed \ mingw-w64-ucrt-x86_64-libjpeg-turbo \ mingw-w64-ucrt-x86_64-libpng \ mingw-w64-ucrt-x86_64-libtiff \ mingw-w64-ucrt-x86_64-openjpeg2 \ mingw-w64-ucrt-x86_64-libwebp \ mingw-w64-ucrt-x86_64-ffmpeg \ mingw-w64-ucrt-x86_64-qt5-base \ mingw-w64-ucrt-x86_64-eigen3 # 验证版本,gcc 必须 >= 13,cmake 必须 >= 3.27 gcc --version cmake --version ninja --version这几条命令的逻辑是:先保证编译器支持 C++17,再保证构建工具能正确生成 Ninja 构建文件,最后把 OpenCV 会用到的图像格式库和视频库提前装好。关键参数说明:--needed避免重复安装;pkgconf是pkg-config在 MSYS2 里的包名,OpenCV 的 CMake 脚本会用它探测第三方库。如果你不装ffmpeg,后面 CMake 会尝试从网络下载预编译的opencv_videoio_ffmpeg.dll,那个下载链接在国内经常超时,所以强烈建议用 pacman 装好。
2.3 源码目录和构建目录的隔离
下载 OpenCV 4.8.0 源码和对应的opencv_contrib(如果你需要aruco、xfeatures2d这些扩展模块)。解压到一个没有空格、没有中文的路径,比如D:/dev/opencv-4.8.0和D:/dev/opencv_contrib-4.8.0。然后在旁边建一个build目录,所有编译产物都扔进去,保持源码目录干净。这是基本纪律,因为 CMake 的 in-source build 会污染源码树,后面想重新配参数都麻烦。
3. CMake 配置:把 30 多个开关一次配对
3.1 最小可用配置命令
下面这条命令是我反复验证过的基线配置,能编出一个带 GUI、带视频 IO、不带 Python 绑定的 OpenCV 静态库加动态库混合版本。把它保存成build.sh放在 build 目录里执行。
#!/usr/bin/env bash # 在 MSYS2 UCRT64 终端里,cd 到 build 目录后执行 cmake -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=D:/dev/opencv-install \ -DCMAKE_C_COMPILER=gcc \ -DCMAKE_CXX_COMPILER=g++ \ -DBUILD_SHARED_LIBS=ON \ -DBUILD_opencv_world=OFF \ -DWITH_OPENCL=OFF \ -DWITH_IPP=OFF \ -DWITH_MSMF=OFF \ -DWITH_DSHOW=ON \ -DWITH_FFMPEG=ON \ -DWITH_QT=ON \ -DWITH_VTK=OFF \ -DBUILD_opencv_python3=OFF \ -DBUILD_TESTS=OFF \ -DBUILD_PERF_TESTS=OFF \ -DBUILD_EXAMPLES=OFF \ -DOPENCV_EXTRA_MODULES_PATH=D:/dev/opencv_contrib-4.8.0/modules \ ../opencv-4.8.0逻辑说明:-G Ninja指定用 Ninja 而不是 Makefile,Ninja 在 Windows 上并行编译效率更高,且对路径长度不敏感。CMAKE_INSTALL_PREFIX是make install后的安装位置,后面写项目时find_package就找这个目录。BUILD_SHARED_LIBS=ON生成.dll加.dll.a导入库,方便多个项目共享;如果你要做单文件分发,改成OFF生成静态库,但静态链接 FFmpeg 和 Qt 会比较折腾。
参数取舍:WITH_OPENCL=OFF和WITH_IPP=OFF是因为这两个在 MinGW 下要么没库、要么链接报错,关掉不影响核心功能。WITH_MSMF=OFF关掉 Windows Media Foundation,改用DSHOW和FFMPEG做视频采集,MSMF 在 MinGW 下头文件不完整。BUILD_opencv_world=OFF是不把所有模块塞进一个库,保持模块独立,链接时按需引入,减少体积。
3.2 配置阶段最常见的三个报错
第一个报错是CMake Error: Could not find FFMPEG。原因是你没装mingw-w64-ucrt-x86_64-ffmpeg,或者装了但PKG_CONFIG_PATH没设。解决方法是确认pkg-config --modversion libavcodec能输出版本号,如果不行,在 CMake 命令前加export PKG_CONFIG_PATH=/ucrt64/lib/pkgconfig。
第二个报错是The CXX compiler identification is unknown。这通常是因为你在 MSYS2 的 MINGW64 环境里装了 UCRT64 的包,或者 PATH 里混入了其他 MinGW。排查方法:which gcc应该输出/ucrt64/bin/gcc,如果不是,关掉终端重新从 UCRT64 快捷方式进入。
第三个报错是Could NOT find Qt5。Qt5 的 CMake 配置文件在/ucrt64/lib/cmake/Qt5,如果 CMake 找不到,手动加-DQt5_DIR=/ucrt64/lib/cmake/Qt5。注意 Qt5 和 Qt6 的 CMake 包名不同,OpenCV 4.8.0 对 Qt6 支持还不完整,建议用 Qt5。
3.3 编译和安装:并行度与内存的平衡
配置成功后,执行编译。Ninja 默认按 CPU 核心数并行,但 OpenCV 的某些模块(比如dnn)单个编译单元吃内存很凶,16G 内存的机器如果 16 核全开,容易触发 OOM 或者编译器内部错误。
# 先看 ninja 默认并行度,再决定是否限制 ninja -j 8 # 编译完成后安装到 CMAKE_INSTALL_PREFIX ninja install参数说明:-j 8表示最多 8 个并行任务。如果你的 CPU 是 8 核 16 线程,可以试-j 12,但如果看到cc1plus.exe内存占用飙升到 2G 以上,就降到-j 6。编译时间参考:8 核机器大约 15 到 25 分钟,取决于是否带 contrib 模块。ninja install会把头文件、.dll、.dll.a和 CMake 配置文件复制到D:/dev/opencv-install,这个目录就是最终产物。
4. 避坑记录:五个让编译前功尽弃的细节
4.1 现象:链接时报undefined reference to std::filesystem::...
原因:MinGW 的std::filesystem实现需要链接-lstdc++fs,但 OpenCV 的 CMake 导出文件里没有自动加上这个库。解决:在你自己的项目CMakeLists.txt里,target_link_libraries之后追加stdc++fs,或者升级到 gcc 13 以上,新版本已经把 filesystem 合并进 libstdc++。
4.2 现象:运行程序时弹窗缺libgcc_s_seh-1.dll
原因:MinGW 编译的动态链接程序依赖 GCC 运行时 DLL,这些 DLL 在/ucrt64/bin下,但不在系统 PATH 里。解决:把/ucrt64/bin加入系统环境变量 PATH,或者用windeployqt类似的思路,把libgcc_s_seh-1.dll、libstdc++-6.dll、libwinpthread-1.dll复制到 exe 同目录。
4.3 现象:imshow窗口一闪而过或者报The function is not implemented
原因:编译时WITH_QT=ON但运行时找不到 Qt 平台插件,或者WITH_WIN32UI被关掉了。解决:确认opencv-install/x64/ucrt64/bin下有opencv_highgui480.dll,并且 Qt 的plugins/platforms/qwindows.dll在可执行文件能找到的路径下。最省事的办法是设QT_QPA_PLATFORM_PLUGIN_PATH环境变量指向 Qt 插件目录。
4.4 现象:CMake 配置时卡在Downloading opencv_videoio_ffmpeg.dll
原因:WITH_FFMPEG=ON但 CMake 没找到系统 FFmpeg,于是触发下载逻辑。解决:确保pkg-config --exists libavcodec返回成功,或者显式指定-DFFMPEG_INCLUDE_DIRS和-DFFMPEG_LIBRARIES。更彻底的办法是直接关掉WITH_FFMPEG,视频 IO 用DSHOW兜底,但会失去部分编码格式支持。
4.5 现象:编译到opencv_contrib的xfeatures2d模块报boost相关错误
原因:xfeatures2d里有些算法依赖 Boost,但 MinGW 的 Boost 包版本和 OpenCV 期望的不一致。解决:在 CMake 里加-DWITH_BOOST=OFF,或者只编译你需要的 contrib 模块,用-DBUILD_opencv_xfeatures2d=OFF单独关掉它。我一般只开aruco和face,其他 contrib 模块按需开。
5. 验证与集成:从pkg-config到 CMake 项目
5.1 用pkg-config快速验证安装结果
安装完成后,opencv-install/lib/pkgconfig下会有opencv4.pc。在 MSYS2 终端里设好PKG_CONFIG_PATH,然后查版本和编译参数。
export PKG_CONFIG_PATH=D:/dev/opencv-install/lib/pkgconfig:$PKG_CONFIG_PATH # 查版本,应该输出 4.8.0 pkg-config --modversion opencv4 # 查编译和链接参数 pkg-config --cflags --libs opencv4如果--modversion输出 4.8.0,说明安装路径和 pc 文件都正确。--cflags会输出一堆-I头文件路径,--libs输出-L和-l链接参数。这个命令可以直接喂给 g++ 做单文件编译测试。
5.2 写一个最小 CMake 项目做端到端验证
建一个test_opencv目录,放两个文件:CMakeLists.txt和main.cpp。这个测试会读一张图片、转灰度、保存,覆盖core、imgcodecs、imgproc三个基础模块。
# CMakeLists.txt cmake_minimum_required(VERSION 3.27) project(test_opencv CXX) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指向 OpenCV 安装目录的 CMake 配置 set(OpenCV_DIR "D:/dev/opencv-install/lib/cmake/opencv4") find_package(OpenCV REQUIRED) add_executable(test_opencv main.cpp) target_link_libraries(test_opencv PRIVATE ${OpenCV_LIBS}) target_include_directories(test_opencv PRIVATE ${OpenCV_INCLUDE_DIRS})// main.cpp #include <opencv2/core.hpp> #include <opencv2/imgcodecs.hpp> #include <opencv2/imgproc.hpp> #include <iostream> int main() { // 读入一张测试图片,路径按实际改 cv::Mat img = cv::imread("test.jpg", cv::IMREAD_COLOR); if (img.empty()) { std::cerr << "无法读取图片,检查路径" << std::endl; return -1; } cv::Mat gray; cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); cv::imwrite("test_gray.jpg", gray); std::cout << "OpenCV 版本: " << CV_VERSION << std::endl; std::cout << "灰度图尺寸: " << gray.cols << "x" << gray.rows << std::endl; return 0; }逻辑说明:find_package(OpenCV REQUIRED)会读取OpenCV_DIR下的OpenCVConfig.cmake,这个文件是ninja install生成的,里面记录了所有模块的库路径和依赖关系。target_link_libraries用${OpenCV_LIBS}一次性链接所有启用的模块。编译时用cmake -G Ninja ..然后ninja,运行test_opencv.exe应该输出 OpenCV 版本和灰度图尺寸。如果报找不到opencv_core480.dll,把D:/dev/opencv-install/x64/ucrt64/bin加入 PATH。
5.3 在 CI 里复现这套编译流程
如果你要把这套流程放进 GitHub Actions 或者自建的 Windows 构建机,核心是把 MSYS2 的安装和 pacman 命令脚本化。关键点是:用msys2/setup-msys2这个 action 时,指定msystem: UCRT64,然后在install字段里写 pacman 包名。编译步骤用msys2 -c "cd build && cmake ... && ninja && ninja install"。缓存策略上,把build目录和opencv-install目录都缓存起来,但注意 CMake 缓存里存了绝对路径,换机器缓存会失效,所以更稳妥的是缓存 pacman 的包缓存和源码压缩包。
6. 进阶技巧:用opencv_world和静态链接做单文件分发
如果你编 OpenCV 是为了做一个能直接发给别人运行的小工具,动态链接一堆 DLL 很烦。这时候可以重新配置一次,开BUILD_opencv_world=ON和BUILD_SHARED_LIBS=OFF,把所有模块合并成一个静态库libopencv_world480.a。但静态链接有个代价:FFmpeg 和 Qt 如果也是动态库,最终 exe 还是得带它们的 DLL。所以更彻底的做法是连 FFmpeg 也用静态库,但 MSYS2 的 pacman 只提供动态库版本,要静态 FFmpeg 得自己编,这就进入另一个坑了。
我的习惯是:开发阶段用动态链接加opencv_world,分发阶段用静态链接加WITH_FFMPEG=OFF和WITH_QT=OFF,只保留imgcodecs和imgproc的核心功能。这样编出来的 exe 只有几 MB,不依赖任何 OpenCV DLL,适合做命令行图像处理工具。具体配置是在 CMake 命令里加:
-DBUILD_SHARED_LIBS=OFF \ -DBUILD_opencv_world=ON \ -DWITH_FFMPEG=OFF \ -DWITH_QT=OFF \ -DWITH_DSHOW=OFF \ -DBUILD_opencv_videoio=OFF \ -DBUILD_opencv_highgui=OFF这样只编core、imgproc、imgcodecs三个模块,静态链接后 exe 体积在 5MB 左右。验证方法是把 exe 复制到一个干净的 Windows 虚拟机里运行,如果不报缺 DLL,就说明静态链接成功。这个技巧在写小工具或者做嵌入式 Windows 设备上的图像预处理时特别有用。
最后说一个我自己的教训:不要一边改 CMake 参数一边编译,改完参数一定要删掉build/CMakeCache.txt重新配。我有一次在已有 build 目录里直接改BUILD_SHARED_LIBS,结果 CMake 缓存里还留着旧的库类型,编出来的东西一半静态一半动态,链接时报了几百个符号冲突,查了一下午才发现是缓存没清。现在我的习惯是每次重新配置前先rm -rf build/*,虽然多花几十秒,但省下的排错时间远不止这点。希望帮到你。
本文还有配套的精品资源,点击获取