简介:OpenCV 2.4.12 的 MinGW 编译包,面向 Windows 平台上使用 GCC 进行 C/C++ 计算机视觉开发的工程师与学习者,省去自行编译 OpenCV 的繁琐流程,可直接将预编译库集成到现有项目。压缩包共 240 个文件,大小 10.15MB,包含 112 个 hpp 和 49 个 h 头文件,用于声明各类 API;30 个 xml 为级联分类器与配置文件;19 个 dll 运行库与 19 个 a 静态库支撑实际链接和运行;另有 5 个 cmake 配置、5 个 exe 工具及 license 许可文件。借助其中的 OpenCVConfig.cmake,CMake 可自动匹配头文件与库路径,x86 目录下已备好 32 位动态/静态链接库,编写 CMakeLists.txt 后即可直接调用图像处理、特征检测、视频分析等常用函数。目前已有 129 人学习下载,适合需要稳定旧版本环境、迁移老项目或研究 OpenCV 2.x 源码结构的开发者。尽管该版本相对陈旧,但对于依赖旧接口的代码兼容性更优,仍可作为特定场景下的可靠选择。
1. 不要只下载预编译包:OpenCV 2.4.12 为什么必须用 MinGW 重新构建
从官网拉一个 OpenCV 2.4.12 的 Windows 安装包,解压后丢给 MinGW 链接,大概率收获一屏的undefined reference to cv::_InputArray::_InputArray()。这不是代码写错了,而是预编译包用的是 MSVC 编译出的二进制,和 MinGW 所属的 GNU 工具链在 C++ ABI 上根本不通用。这个标题的核心动作“opencv2.4.12 build mingw”,就是在 Windows 上拿 MinGW 从 OpenCV 2.4.12 源码重新编译出一套库文件,让链接器和运行库都落在同一个 ABI 里。适合处理老项目维护、Qt/CodeBlocks 等使用 MinGW 工具链的工程,也适合想在 Windows 上学习 OpenCV 编译流程的工程师。
2. 构建前先看清工具链:MinGW 与 MSVC 的差异、源码包和模块裁剪
2.1 MinGW 和 MSVC 的区别:为什么直接链接会爆undefined reference
MSVC 和 MinGW 的区别不是换个编译命令那么简单。C++ 编译产物不兼容的第一层是名称修饰(name mangling)规则不同,同一行cv::Mat::at<float>(int,int)在 MSVC 和 GCC 之下生成的符号表条目完全不同,链接器找不到符号,于是报一堆undefined reference。
第二层是运行库。MSVC 程序链msvcp140.dll、vcruntime140.dll,MinGW 程序链libstdc++-6.dll和libgcc_s_seh-1.dll。两者对new/delete、异常处理和std::string的内存布局都有差异,即使强行从符号层面衔接上,运行阶段也会在std::string传递或跨模块throw时崩溃。
第三层是导入库格式。MSVC 使用.lib文件描述 DLL 的导出函数,MinGW 使用.dll.a,两家格式不互通。OpenCV 官方 Windows 包里的x86/mingw或x64/vc14目录分别对应不同工具链,拿到vc14的.lib给 MinGW 用,CMake 会直接拒绝。所以需要从源码开始,让 CMake 触发一次“针对 GNU 工具链的完整编译”,得到.dll.a和.a文件。
2.2 去 mingw 官网下载前先确认三件事:GCC 版本、位数和 PATH
构建 OpenCV 2.4.12 时,工具链版本选择比源码本身更影响成败。这个版本诞生时 GCC 还在 4.8/4.9 时代,用新版 GCC 12/13 编译会撞上 C++11 默认值变更和-fpermissive报错,虽然多数能改开关绕过去,但对第一次操作的人不友好。我一般优先选 GCC 4.9.x 到 7.x 之间的 MinGW-w64,或者直接用 CodeBlocks 17.12 自带的 MinGW(GCC 5.1.0),Qt Creator 配的 5.9.9 携带的同版本工具链也行。
位数必须和最终目标 EXE 一致。用 32 位工具链编出的 OpenCV 库,不能给 64 位程序用;反之在 64 位程序里调 32 位 DLL 会在进程启动阶段直接报“不是有效的 Win32 应用程序”。下载时确认 MinGW-w64 的 prefix 是i686-w64-mingw32还是x86_64-w64-mingw32,二者只能留一个在 PATH 前面,混着放会导致 CMake 探测到错误编译器。
源码包选择也有讲究。OpenCV 2.4.12 官方提供了Win pack和Source两个渠道,构建场景必须下载 Source 版本,而且是 zip 格式,不是自解压 exe。解压的路径避免出现空格和中文,C:\build\opencv-2.4.12这个写法在后续 CMake 配置阶段能省掉很多路径解析问题。
工具链和目录规划参考下面这张表:
| 项目 | 建议取值 | 原因 |
|---|---|---|
| GCC 版本 | 4.9.x ~ 7.x | 与 2.4.12 的源码兼容性最好,新版本多出 C++11 默认值问题 |
| 编译器位数 | 与目标 EXE 一致 | 混用会导致链接失败或运行时 DLL 加载失败 |
| 源码路径 | 不含空格和中文 | 避免 CMake 和 MinGW Makefiles 对路径的解析问题 |
| CMake 版本 | 3.5 ~ 3.10 或 3.16 以下 | 新版 CMake 对老项目的策略有时会改变输出结构 |
| 生成器 | MinGW Makefiles | 直接产出 32 位 GNU 工具的 Makefile,不需要 Msys 环境 |
2.3 模块裁剪:2.4.12 不是每个模块都要编
OpenCV 2.4.12 的源码目录里有两个modules目录,根目录modules里包含core、imgproc、highgui、ml、video、objdetect、features2d、calib3d、flann、photo、stitching、nonfree等模块。默认全编不是不行,但会拖长构建时间,而且nonfree、stitching这种依赖第三方库的模块,在 Windows 上经常因为缺少Eigen或TBB导致配置异常。构建前打开 CMake 配置界面,直接勾选掉当前项目用不到的模块。
我这边的裁剪策略是保留core、imgproc、highgui、video、objdetect、calib3d、features2d,其他全部关闭。这样能保证视频读取、图像处理、相机调用和基本的特征匹配能力都在,又不会滑入第三方依赖的深坑。模块对应的 CMake 开关如下:
| 模块 | CMake 开关 | 编译产物 | 主要功能 |
|---|---|---|---|
| 核心库 | BUILD_opencv_core | libopencv_core | 矩阵、图像容器、基础数据结构 |
| 图像处理 | BUILD_opencv_imgproc | libopencv_imgproc | 滤波、几何变换、直方图、边缘检测 |
| 高层 GUI | BUILD_opencv_highgui | libopencv_highgui | 窗口显示、图像读写、摄像头读取 |
| 视频模块 | BUILD_opencv_video | libopencv_video | 光流、背景建模、跟踪 |
| 目标检测 | BUILD_opencv_objdetect | libopencv_objdetect | 人脸检测、HOG 特征 |
| 特征模块 | BUILD_opencv_features2d | libopencv_features2d | SIFT、SURF 封装、描述子匹配 |
| 相机标定 | BUILD_opencv_calib3d | libopencv_calib3d | 双目标定、立体匹配 |
关闭模块时有一句要注意:不要动BUILD_opencv_flann和BUILD_opencv_core。features2d和calib3d都依赖flann,这个是硬依赖,关掉之后 CMake 配置阶段会提示OPENCV_DEPENDENCIES缺失;core是所有模块的地基,任何情况都不要关。
3. 用 CMake 生成 MinGW Makefiles:目录规划、配置命令与关键开关
3.1 为什么源码目录和构建目录必须分开
OpenCV 2.4.12 的 CMake 体系支持源码内构建,即直接在opencv-2.4.12目录里执行 cmake,然后生成一堆中间文件和 Makefile。这种做法的缺点是:一次构建失败想换工具链或换配置时,源码目录里残留的CMakeCache.txt会持续干扰下次配置。CMakeCache 里缓存了上次的编译器路径、生成器类型和开关值,经常出现“明明改了-DWITH_FFMPEG=OFF,配置结果里还是 ON”的诡异情况。
所以构建目录要和源码目录同级分离。我一般按这个结构放:
C:\build\ opencv-2.4.12\ 源码解压目录,只读,不做任何构建 opencv-build\ 构建目录,CMake 缓存和中间文件都在这 opencv-install\ 安装目录,编完后 include / lib / dll 都装到这分离构建目录之后,换配置或换模块开关只需要删掉opencv-build里的CMakeCache.txt,源码保持干净。源码目录如果被弄脏了,最稳妥的方式是重新解压一份,不要手工清理临时文件。
3.2 可复现的配置命令:CMake 与 MinGW Makefiles 组合
进入构建目录后,用cmake指向源码路径,并显式指定生成器和工具链相关参数。下面是我在 Windows 命令提示符下执行的完整命令(在 PowerShell 里要额外注意引号转义):
cd C:\build\opencv-build cmake -G "MinGW Makefiles" \ -DCMAKE_BUILD_TYPE=Release \ -DBUILD_SHARED_LIBS=OFF \ -DCMAKE_INSTALL_PREFIX=C:/build/opencv-install \ -DCMAKE_MAKE_PROGRAM=C:/mingw/bin/mingw32-make.exe \ -DWITH_FFMPEG=OFF \ -DWITH_OPENMP=ON \ -DBUILD_opencv_stitching=OFF \ -DBUILD_opencv_nonfree=OFF \ -DCMAKE_CXX_FLAGS="-std=c++11" \ ..\opencv-2.4.12参数逐条解释:
-G "MinGW Makefiles"指定 CMake 生成 Makefile 的目标工具链是 MinGW,而不是 Visual Studio 的.sln工程。这个参数选错,后续mingw32-make命令会找不到 Makefile。-DCMAKE_BUILD_TYPE=Release控制编译优化级别,Release 对应-O3,Debug 对应-g -O0且生成大量.pdb无关文件。OpenCV 调试还是建议在最终应用里加日志,库本身用 Release 编译速度和运行效率都更好。-DBUILD_SHARED_LIBS=OFF让 OpenCV 编译为静态库。这一步要权衡:OFF 之后产出一堆.a文件,最终 EXE 体积变大但部署时不用带一堆 DLL;如果设置成 ON,后续要把bin目录里的 DLL 全部拷到 EXE 旁边。-DCMAKE_MAKE_PROGRAM指向mingw32-make.exe的绝对路径。不设置的话,CMake 会按 PATH 里的make.exe找,如果是 MSYS 或 MSYS2 的make.exe,格式和 MinGW 的 Makefiles 不匹配,会出现mingw32-make: Interrupt/Exception caught之类的错。-DWITH_FFMPEG=OFF关闭视频文件读取的 FFmpeg 依赖,摄像头读取不受影响。旧版 OpenCV 的高清视频编解码依赖外部opencv_ffmpeg.dll,这个 DLL 在官网 Win pack 里才有,源码构建默认不生成。-DCMAKE_CXX_FLAGS="-std=c++11"在 GCC 5.1 以上的工具链中可选,旧版 GCC 4.8 不需要;加上之后能从源码层面解决一部分跟std::shared_ptr和 C++11 特性相关的问题。
3.3 配置完成后必须检查的三项输出
CMake 配置结束前会打印一份配置摘要,这段输出里藏着后续构建能不能成功的关键信息。第一次配置完成后,不要立刻编译,先看三个地方。
第一,检查摘要里的Compiler那行:
-- Compiler: C:/mingw/bin/gcc.exe -- Compiler version: 5.1.0如果这里显示的不是 GNU 编译器,或者路径指向了系统里的 MSVC 残留,立刻回去检查PATH环境变量,把 MinGW 的bin目录挪到最前面。
第二,检查Video I/O和Camera的配置结果:
-- Video I/O: -- Video for Windows: YES -- DirectShow: YES -- FFMPEG: NO在 Windows 上,摄像头调用由 highgui 模块完成,底层依赖 DirectShow 或 Video for Windows。FFMPEG: NO不影响相机,但如果要读取 mp4 文件,则要保持WITH_FFMPEG=ON并且准备好opencv_ffmpeg*.dll。
第三,检查Modules to be built列表,确认opencv_ml、opencv_video等开关是否符合预期。列表里如果出现了To be built: opencv_world,说明某个组件强行拉起了 world 类型链接,这种配置下最后会合成一个大库,此时BUILD_SHARED_LIBS=OFF会变成一个巨大的.a文件,链接速度会非常慢。
配置阶段常见的另一个坑是CMAKE_INSTALL_PREFIX写成C:\build\opencv-install导致转义问题。CMake 里反斜杠会被当成转义字符处理,所以统一用正斜杠C:/build/opencv-install,Windows 下 CMake 完全认这个格式。
4. 用 mingw32-make 跑通编译:进度、失败定位和 DLL 部署
4.1 编译命令与 jobs 参数
配置完成后,CMake 会在构建目录里生成顶层 Makefile。编译动作由mingw32-make执行,命令和进度如下:
cd C:\build\opencv-build mingw32-make -j4-j4表示四路并行编译。这里的数量不是越大越好,MinGW 的 Makefiles 在处理 OpenCV 这种大规模工程时,并行任务数高于 8 会出现随机段错误或文件写入冲突,失败点在每次编译都不一样。我一般用-j4,CPU 是四核或六核都保持在物理核心数的 50% 到 70%,稳定最优先。
编译完成后执行安装:
mingw32-make installinstall 动作把include、lib、bin三部分复制到第 3 节设置的C:/build/opencv-install目录。静态库模式下,dll不会出现在安装目录里;动态库模式下,C:/build/opencv-install/bin里会出现一连串libopencv_core240.dll之类的文件。
4.2 三个典型构建失败:原因和定位方法
失败一:无法打开包含文件: "stdint.h"。
C:\build\opencv-2.4.12\modules\core\include\opencv2\core\types_c.h:59:21: fatal error: stdint.h: No such file or directorystdint.h是 C 标准头文件,MinGW 的 bin 目录里一定有。出现这个错误说明当前编译调用链用的不是 MinGW 编译器,而是莫名其妙切换到了 MSVC 的 cl.exe,或者 PATH 前面混入了某个不带标准头的嵌入式工具链。检查mingw32-make -v输出的 GCC 版本路径,确认 CMakeCache 里的编译器路径和实际gcc.exe所在目录一致;如果 CMakeCache 里存的是C:/Program Files/...这种带空格的路径,重新清理构建目录再配置一次。
失败二:undefined reference to __gxx_personality_v0和大量 C++ 标准库符号缺失。
这个错误发生在编译 OpenCV 自身的.cpp文件时,通常是因为gcc与g++混用,或者 Makefile 里的 CXX 编译器被切成了纯 C 编译器。CMake 拿 GCC 的gcc.exe和g++.exe分别编译 C 和 C++ 文件是正常的,但如果g++.exe不在 PATH 里,CMake 会回退到gcc.exe编译 C++ 文件,异常处理库从不加载,链接时就满屏__gxx_personality_v0。
定位方式是在构建目录里找CMakeFiles\CMakeError.log,文件最后几十行记录了探测阶段的错误详情。这个文件是 CMake 自己写的编译器测试报告,出现The C++ compiler ... is not able to compile a simple test program时,问题基本锁定在工具链环境。
失败三:application cannot find libopencv_core240.dll或opencv_ffmpeg.dll。
这个不是编译失败,而是运行阶段的错误。动态库模式下,程序启动时扫描 DLL 的路径只有三个:EXE 所在目录、系统目录和 PATH。把构建目录里零散的 DLL 拷到 EXE 旁边是最直接的方案,不要试图用改 PATH 的方式全局注册,这会污染其他项目。
另外 2.4 时代的 OpenCV 对视频文件支持依赖单独的opencv_ffmpeg.dll或opencv_ffmpeg_64.dll,这个文件在 Source zip 里没有,它是预编译组件。我在构建时选择直接-DWITH_FFMPEG=OFF,把视频文件读写交给应用层自行处理,省掉这个隐含依赖。如果必须支持 mp4 读取,就去 Win pack 里找到对应位数的 dll,把它放到 EXE 旁边,且文件名必须与highgui模块加载时检查的名称完全一致。
4.3 安装目录的布局和给谁用
安装完成后的目录结构是:
| 目录 | 内容 | 用途 |
|---|---|---|
include\opencv2 | 全部头文件 | 应用项目里的 include 路径 |
lib | libopencv_*.a及libopencv_*.dll.a | 链接器读取的导入/静态库,对应 CMake 的 link 目录 |
bin | *.dll(动态构建时才有) | 运行期依赖,需要拷到 EXE 目录 |
静态库模式下没有bin目录,所有.a文件都在lib下,命名如libopencv_core.a、libopencv_imgproc.a,注意最后的.a前面不带240版本号,这与 OpenCV 3.x 的命名规则不同。CMake 的OpenCVConfig.cmake在安装目录的根下,应用项目通过find_package(OpenCV)找到的正是这个配置文件。
5. 把自编译的 OpenCV 接进 Qt/CB 工程:链接清单和一个省事技巧
5.1 CMake 侧的最小链接配置
MinGW 自编译的 OpenCV 2.4.12 接进工程的方式,推荐用 CMake 的find_package。以下是能直接放进项目里的CMakeLists.txt:
cmake_minimum_required(VERSION 3.5) project(opencv_min_demo) set(CMAKE_PREFIX_PATH "C:/build/opencv-install") find_package(OpenCV REQUIRED) include_directories(${OpenCV_INCLUDE_DIRS}) add_executable(demo_demo main.cpp) target_link_libraries(demo_demo ${OpenCV_LIBS})set(CMAKE_PREFIX_PATH)用来告诉 CMake 去找哪个路径下的OpenCVConfig.cmake,不设置会默认搜索系统路径,大概率找不到。${OpenCV_LIBS}在 2.4.12 里是一串完整路径的.a文件列表,不需要手动逐个添加。这里有一个细节:2.4 版本的OpenCVConfig.cmake会强制引入d端 Debug 库,如果 CMake 构建类型是Debug,它会在库名后面拼d后缀,而 2.4 默认安装目录里并没有生成带d后缀的库。遇到cannot find -lopencv_cored时,把 CMake 的CMAKE_BUILD_TYPE改成Release重新配置一次即可。
5.2 不依赖 opencv_world 时的链接顺序
关闭 world 合成之后,静态库模式下链接顺序不合法会直接报一堆 pugixml、tbb 相关的未定义符号。静态链接按依赖反序排列,OpenCV 2.4.12 的常见顺序是:
| 顺序 | 库 | 说明 |
|---|---|---|
| 1 | opencv_calib3d | 依赖 features2d、flann、core |
| 2 | opencv_features2d | 依赖 flann、imgproc、core |
| 3 | opencv_video | 依赖 imgproc、core |
| 4 | opencv_objdetect | 依赖 imgproc、core |
| 5 | opencv_highgui | 依赖 imgproc、core,Windows 层还要链ole32、gdi32 |
| 6 | opencv_ml | 只依赖 core |
| 7 | opencv_imgproc | 依赖 core |
| 8 | opencv_flann | 依赖 core |
| 9 | opencv_core | 无内部依赖 |
CMake 的${OpenCV_LIBS}已经处理过这个顺序,手工写target_link_libraries时不要乱排。Qt Creator 在手动添加.a时会弹出链接顺序提示,验收标准只有一条:编译通过并且链接阶段没有undefined reference反弹。
5.3 一个省事技巧:合并库和验证摄像头通路
整个静态库体系里几十个.a文件让工程配置显得很啰嗦,2.4.12 的 CMake 选项里其实藏着BUILD_opencv_world,把它打开就能编出单个libopencv_world.a。合库的代价是每次增删模块都要重新编整个集合,但最终链接时只需要指定一个库文件,对 CodeBlocks 17.12 或 Qt 5.9.9 里的 MinGW Kit 非常友好。加上这个开关的条件是提前确认BUILD_SHARED_LIBS=OFF,否则合出来的是一个巨大的 DLL,再叠加opencv_ffmpeg.dll的部署问题,运行期会变成一场灾难。
库装好之后,验证通路可以直接写一段相机读取代码,配合opencv_highgui的namedWindow和imshow打开默认摄像头。2.4 时代的 Windows 相机读取依赖 DirectShow,底层原理是 crossbar 过滤器枚举摄像头设备,配置步骤里DirectShow: YES就是这段通路的地基。验证代码跑通后,把C:\build\opencv-install\bin下的所有 DLL 复制到 EXE 目录,然后按F9运行,窗口里出现一帧实时画面,这套 MinGW 构建就算真正落地。
本文还有配套的精品资源,点击获取