Win10+VS2015下OpenCV3.3.0扩展contrib编译完整指南 如果你最近在一个老项目里接手了OpenCV 3.3.0大概率也绕不开这个标题本身Win10 VS2015 OpenCV3.3.0下扩展OpenCV_contrib3.3.0。OpenCV 3.3.0官方只提供标准模块的预编译包SIFT、SURF、face、aruco这些扩展模块都放在contrib仓库里而官方二进制是不包含它们的。更麻烦的是这个版本太老网上教程大多已经转向OpenCV 4.x照着新版流程做第一轮CMake配置就对不上。这篇文章就把我自己完整走通过一遍的流程记录下来从版本选择、环境准备到CMake配置、VS2015编译、安装再到用SIFT验证contrib是否真正生效。适合正在搭建VS2015环境下OpenCV 3.3.0源码编译环境的人也适合买了带旧SDK的工控机、只能锁死在VC14工具集里做视觉开发的人。1. 为什么一个2017年的老组件到现在还有人折腾1.1 contrib扩展包到底补了什么OpenCV的主仓库在3.x时代就已经把标准模块拆得很细核心、图像处理、视频、DNN等都在里面但历史遗留的xfeatures2d、face、aruco、text、optflow这些实验性或专利敏感模块一直放在独立仓库里。典型的就是SIFT和SURF。OpenCV 3.3.0里你去主仓库的opencv2/features2d.hpp里找SIFT是找不到的它被挪到了opencv2/xfeatures2d.hpp而这个头文件只存在于contrib扩展仓库的模块里。所以“扩展contrib”不是一个可选项而是必须做的编译步骤。很多人下载了官方提供的opencv-3.3.0-vc14解压包然后发现代码里写#include opencv2/xfeatures2d.hpp时报文件找不到或者SIFT函数链接时报未定义符号本质原因就是官方预编译包里没有编译contrib模块。更关键的是你不能指望把contrib的源码文件夹塞进已有官方包里碰运气。OpenCV的构建系统在主仓库源码里通过CMake组织contrib是构建时参与进来的扩展模块集合最终会被一起编进opencv_world330.dll或者拆分的多个lib中。想用SIFT就必须从源码重新编译主仓库加contrib没有捷径。1.2 版本三方咬合错一步满盘皆输这个标题里的三个版本号其实咬得很死。Windows 10对VS2015本身没有兼容问题但VS2015必须打到Update 3否则OpenCV 3.3.0的C11代码在编译中会遇到一些编译器内部错误。OpenCV 3.3.0主仓库的构建脚本对CMake版本有隐形的最低要求CMake太老无法识别VS2015的x64生成器CMake太新又可能因为策略变更产生一堆莫名其妙的问题。contrib仓库必须和主仓库选择同一个tag。主仓库下载的是3.3.0contrib也要下载3.3.0。如果一不留神拉了master分支OpenCV主仓库3.3.0的某些内部API签名和contrib最新代码对不上后期编译报错会成片出现且错误信息根本不像版本冲突。我见过不少配置失败案例最后查下来都是contrib版本拉错。遇到过拉成3.4.x分支然后去配3.3.0主仓库的编译xfeatures2d模块时几十个头文件找不到。这属于白花一小时换回匹配版本后立刻通过。2. 环境准备里最容易翻车的三个点2.1 VS2015 Update 3不是可选项如果你是第一次在这台机器上安装VS2015安装器里务必把“Visual C”工具集勾上同时勾选“Windows 10 SDK”。许多人只装了.NET相关组件等到CMake一跑发现找不到C编译器那叫一个摸不着头脑。安装完以后打开Visual Studio的“帮助–关于”确认版本号是14.0.25420.00以上。像这样的版本号对应VS2015 Update 3。Update 3修复了不少对Windows 10 SDK的识别问题也补了C标准库实现的一大堆bug。OpenCV 3.3.0源码里大量使用C11特性所以在VS2015上至少要这个Update。还有一个坑VS2015的内部版本号是14.0所以CMake生成器名称叫Visual Studio 14 2015 Win64不要以为是选错了。2.2 CMake版本不要盲目追新很多人习惯去CMake官网下载一个“最新稳定版”然后就开始configure。OpenCV 3.3.0是2017年发布的它的CMake脚本默认不认太新的策略规则。我常用的稳定组合是CMake 3.8.2这套组合在Win10 VS2015 OpenCV 3.3.0上跑了很多次CMake GUI没有红色告警生成OpenCV.sln也干净。如果你电脑里已经装了新版本CMake也没必要卸载重来。配置时看到一串关于CMP0025、CMP0075的策略警告时就要有心理准备新CMake可能在后续步骤里因为不同策略给OpenCV生成不同的项目结构。我实测过用CMake 3.28去配置OpenCV 3.3.0能生成工程但部分contrib模块的下载路径处理方式变了导致xfeatures2d的依赖文件下载位置异常最后编译阶段报文件找不到。老老实实换回3.8.2一次通过。2.3 源码目录结构与下载方式下载OpenCV源码时我建议在GitHub上按tag下载zip不要用master分支。主仓库选择3.3.0这个tag文件解压后目录名一般是opencv-3.3.0。contrib仓库同样选择3.3.0解压后目录名一般是opencv_contrib-3.3.0。目录结构我习惯这样摆D:\ ├── opencv-3.3.0 ├── opencv_contrib-3.3.0 └── opencv-3.3.0-buildopencv-3.3.0-build是CMake的build目录也就是最终生成VS工程文件的地方。三个路径不要出现中文、空格或者圆括号。别看这条像废话曾经有人放在C:\Users\张三\下载\里CMake的下载缓存路径处理中文有问题configure阶段一直报路径找不到。3. CMake配置过程逐项拆解3.1 第一次Configure与生成器选择打开CMake GUIWhere is the source code填D:/opencv-3.3.0Where to build the binaries填D:/opencv-3.3.0-build。然后点Configure。弹出选择框后下拉列表里选Visual Studio 14 2015 Win64注意一定要带Win64这是关键。如果你选成不含Win64的Visual Studio 14 2015生成的是32位工程的solution后面链接x64的OpenCV库全部失败。平台选完以后下面的编译器默认值不要动直接Finish。第一次Configure结束以后红色高亮条目会很多这是正常的。因为很多依赖还没有解析完成你接下来要做的就是在搜索框里逐个设置关键变量然后再次Configure。3.2 OPENCV_EXTRA_MODULES_PATH设置错误是最普遍原因在CMake GUI搜索OPENCV_EXTRA_MODULES_PATH把这个变量指向contrib仓库里的modules目录。正确写法D:/opencv_contrib-3.3.0/modules千万别写成D:/opencv_contrib-3.3.0。OpenCV构建系统会在这个路径下直接扫描modules子目录里各个模块的CMakeLists.txt。如果你填的是contrib的根目录虽然也能配置通过但最后生成的模块列表里只有主仓库的标准模块contrib根本没有参与构建。如果你想判断contrib是否真正被识别不用急着Generate。在CMake的输出窗口里找到OpenCV modules那一节正常情况下应该能看到xfeatures2d face aruco text ...看到这些模块才说明扩展路径生效了。3.3 必勾与可不勾的选项清单第二次Configure以后红色大部分会消失。这时候在搜索框里继续处理几个关键开关。必勾的变量名推荐值原因BUILD_opencv_worldON把所有OpenCV模块统一编译成一个opencv_world330库测试程序链接时只需要一个库文件OPENCV_ENABLE_NONFREEON启用SIFT、SURF等受专利保护的算法不勾的话即使编译成功运行时也会提示算法被禁用可以不勾的变量名推荐值原因BUILD_EXAMPLESOFF示例代码不是必需品关掉能省不少编译时间BUILD_TESTSOFF官方测试模块很大只做二次开发没必要编译BUILD_PERF_TESTSOFF同理BUILD_opencv_python2/BUILD_opencv_python3按需如果不用Python调用OpenCV可以关掉少编两个大模块BUILD_opencv_javaOFF用不到就关掉如果你只做C图像处理和特征提取关掉测试、示例和Python编译时间能少三分之一以上。四核八线程的机器实测半小时左右能把Release版本编完。这里有个容易被忽略的点BUILD_opencv_world开启以后contrib里的xfeatures2d等模块也会被编进world库不冲突。所以后面链接时只写opencv_world330.lib就够用。3.4 网络下载项IPP与FFmpeg的处理思路CMake一旦开始Configure会尝试从远程服务器下载一些第三方依赖。OpenCV 3.3.0主要涉及两个东西IPP加速库和FFmpeg预编译包。IPP本身是对图像计算的硬件加速优化默认情况下OpenCV会下载一份编进库中。如果网络比较波configure会卡在这里提示超时或CRC校验错误。解决办法很简单图像特征提取这类应用场景IPP关掉不影响功能只会让某些像素级操作慢一点。在搜索框里找WITH_IPP把它取消勾选。同理如果不用视频读写功能可以连WITH_FFMPEG一起关掉。配置完以后再次Configure这一步能绕开大部分下载问题。如果你确实需要用OpenCV读取视频FFmpeg预编译包又是必须的话那就在configure时保持WITH_FFMPEG打开多试几次或者找一个网络空闲的时间段继续。不要无限重试下载文件会缓存在C:/Users/用户名/.cache/opencv3/ffmpeg下某一次成功后文件会留在那里后续重新configure就不用再下载了。3.5 第三次Configure与Generate所有选项调整完后再点Configure。观察输出窗口如果已经没有红色高亮而且OpenCV modules列表里出现了contrib模块就可以点Generate了。Generate速度很快基本一两秒结束生成完会在build目录下产生一个OpenCV.sln。到了这一步CMake环节才算真正通过。很多教程在这里就默认成功了其实不算。我见过不少人在Generate时弹出CMake Error: The following variables are used in this project, but they are set to NOTFOUND之类的提示大意是某些依赖没找到。如果你的界面里也出现这个先不要Generate逐条看哪个变量是NOTFOUND常见的是PYTHON_EXECUTABLE或JAVA_JVM_LIBRARY。既然用不到Python和Java就把对应的BUILD_opencv_python*和BUILD_opencv_java关闭再Configure。4. VS2015编译与INSTALL安装4.1 用Release x64生成ALL_BUILD双击OpenCV.slnVisual Studio打开以后先把解决方案配置切到Release把解决方案平台确认在x64。这时候你会看到一个庞大的项目列表项目数量几十到上百不等取决于你的模块开关。在CMakeTargets目录下找到ALL_BUILD右键选择“生成”。注意第一次编译不要只单独生成INSTALL因为INSTALL依赖所有模块的lib单独生成会报错“无法打开opencv_core330.lib”之类。编译过程耗时很长。在这期间不要随便点掉正在运行的其他编译任务。如果某个模块失败VS的“错误列表”会直接定位到具体项目。这时候不要慌先看错误是属于编译类还是链接类。编译类错误通常和源码版本不匹配有关链接类错误通常是项目依赖没生成完整重新生成ALL_BUILD一般能解决。4.2 几个低概率但高破坏性的编译错误编译过程中我实际遇到过两个比较典型的坑。第一个是xfeatures2d模块编译时需要下载boostdesc_bgm.i、vgg_generated_48.i这类训练数据文件。这个下载动作发生在VS编译阶段如果网络不行VS会报error MSB3073或者提示找不到指定文件。解决办法是在错误信息里找到下载URL单独用浏览器把文件下载下来放到错误信息提示的缓存目录再重新生成该模块。第二个坑是编译器报fatal error C1083: Cannot open include file: opencv2/ximgproc.hpp。这种多半不是文件真的缺失而是你在CMake配置时把某个可选模块关了但xfeatures2d代码实际上依赖它。解决办法不是去改代码而是回到CMake GUI里把被关闭的相关模块重新打开重新Configure和Generate然后重新编译。还有一个不算错误但很影响效率的事情默认ALL_BUILD是顺序编译还是并行编译取决于VS设置。在VS菜单里“工具–选项–项目和解决方案–VC项目设置”中把“最大并行项目生成数”调到4或更高编译速度会明显提升。如果内存只有8G建议保持默认防止多个编译进程同时打爆内存。4.3 INSTALL项目与产物目录ALL_BUILD编译成功后找到INSTALL项目右键生成。这个项目不会产出新的功能库而是把编译结果统一复制到CMake里设置的安装目录。默认安装路径是D:/opencv-3.3.0-build/install。生成完成后目录结构应该是install ├── include │ └── opencv2 └── x64 └── vc14 ├── bin │ ├── opencv_world330.dll │ └── opencv_world330d.dll └── lib ├── opencv_world330.lib └── opencv_world330d.libvc14这个目录名很关键它代表Visual Studio 2015的VC工具集版本。如果你后面用VS2015建立测试工程库目录要指到这里。另外验证一下bin下有没有opencv_version.exe有的话直接命令行执行opencv_version.exe输出3.3.0就说明库本身没问题。接下来才有资格谈验证contrib扩展。5. 用SIFT在VS2015里验证contrib是否真的生效5.1 新建工程和目录配置打开VS2015新建一个C控制台工程。刚创建的时候默认可能是Win32平台这一步必须改。点菜单“生成–配置管理器”在“活动解决方案平台”里选择x64如果没有就先新建一个x64平台。否则后面链接时会报“这是无效的Win32应用程序”或“无法加载DLL”的错。然后设置工程属性配置项填写内容C/C – 常规 – 附加包含目录D:/opencv-3.3.0-build/install/include链接器 – 常规 – 附加库目录D:/opencv-3.3.0-build/install/x64/vc14/lib链接器 – 输入 – 附加依赖项Release下填opencv_world330.libDebug下填opencv_world330d.libDebug和Release的库要匹配使用。如果把Debug工程链接Release版的opencv_world330.lib多数情况能跑但调试时变量监视可能不正常如果Release工程链接了d版本库运行时会因为找不到调试版DLL失败。所以最简单的方法是OpenCV编译时把两者都编出来VS里切一次Debug生成ALL_BUILD和INSTALL再切一次Release生成这样lib目录下两个文件都在。5.2 测试代码与NONFREE双保险在工程里添加一个main.cpp内容如下#define OPENCV_ENABLE_NONFREE #include opencv2/opencv.hpp #include opencv2/xfeatures2d.hpp #include iostream int main() { cv::Mat gray cv::imread(D:/test.jpg, cv::IMREAD_GRAYSCALE); if (gray.empty()) { std::cout image not found std::endl; return -1; } auto sift cv::xfeatures2d::SIFT::create(); std::vectorcv::KeyPoint keypoints; cv::Mat descriptors; sift-detectAndCompute(gray, cv::noArray(), keypoints, descriptors); std::cout keypoint count: keypoints.size() std::endl; std::cout descriptor size: descriptors.rows x descriptors.cols std::endl; return 0; }注意第一行#define OPENCV_ENABLE_NONFREE必须出现在所有OpenCV头文件之前。虽然真正的“启不启用”在CMake阶段就已经决定但这个宏会在头文件层面强制展开非自由算法的声明相当于双保险。如果你在CMake阶段没有勾选OPENCV_ENABLE_NONFREE运行时SIFT会直接报“该算法受专利保护当前构建已禁用”程序返回空特征点。出现这种情况不要改宏回到CMake GUI勾上选项重新编译OpenCV才是正解。5.3 运行结果与常见报错排查编译通过以后运行程序前要确保opencv_world330.dll能被找到。最简单的办法是把install/x64/vc14/bin加进系统环境变量Path然后重启VS。不想改全局环境变量的话也可以把DLL直接复制到exe所在目录。如果程序输出keypoint count: 几千这样的信息说明contrib扩展真的生效了。哪怕只有几十个特征点只要数量不是0都说明SIFT模块已被正确编译进OpenCV库。常见报错我再列一张表现象原因处理编译时报找不到xfeatures2d.hpp工程包含目录没配或者CMake阶段contrib没参与构建检查包含目录和CMake模块列表链接时报LNK2019 unresolved external symbolworld库没链接上或者链接的是非world库但没把contrib模块的lib逐个写上回到属性页确认附加依赖项只有opencv_world330.lib运行时提示“算法已禁用”CMake阶段没勾选OPENCV_ENABLE_NONFREE重新CMake并编译OpenCV运行时提示DLL缺失bin目录不在Path中或dll版本是Debug/Release不匹配添加bin到Path或拷贝DLL到exe目录6. 让配置环境可复用的一些习惯6.1 环境变量建议只加局部很多教程让你一上来就把install/x64/vc14/bin塞进系统Path我建议换个思路。如果你的电脑上同时装了OpenCV 3.x和OpenCV 4.x或者同时有VS2015和VS2019编译的库全局Path一加测试程序运行时就会加载错DLL表现是程序启动后马上崩溃或者明明调用了最新库却报找不到新函数。我自己的习惯是在VS工程属性里设置“调试–环境”或者写一个setenv.bat脚本在编译运行前临时把bin加进Path。这样不同项目可以用不同OpenCV版本互不干扰。发布程序时再手动把需要的DLL放进exe同目录。6.2 保留install目录比重新编译更省事OpenCV源码编译这件事难点全在configure阶段和第三方依赖下载一旦成功install目录就是一套完整可用的SDK。重装系统以后只要你的VS2015还在直接把install目录拷到新机器然后在工程属性里指过去就行不需要重新走一遍CMake和编译。如果用Docker类隔离环境或者项目迁移建议把opencv-3.3.0、opencv_contrib-3.3.0和opencv-3.3.0-build三个目录整体打包存档。以后任何人想复现这个环境打开CMake GUI时只需要重新填路径其余配置全部能从build目录的CMakeCache里恢复比对着文档手点快得多。最后再多说一句如果你也被卡在某个奇怪的编译错误上不要急着改代码先把CMake输出窗口或者VS错误列表里第一条红色信息完整看一遍。老版本OpenCV的坑多数不是算法代码的问题而是路径、版本、网络下载这三件事。把这三件事理顺这篇配置流程基本就能一遍过。