目录
0.写作背景
1.安装visual studio
2.下载OpenCV相关的源码
下载OpenCV原始的源码
下载OpenCV contrib的源码
下载安装cmake
3.cmake编译OpenCV
初始编译
CmakeDownload的bug修复
OpenCV-crontrib编译:
Generate生成代码
VS生成代码:
报错修复
4.Visual Studio配置变量
5.Case测试:
初始测试
SIFT算子测试
SURF算子测试
6.总结
7.参考链接:
OpenCV可能是目前使用最广泛的开源图像处理工具了,尤其是在科研领域。
在读研期间进行图像拼接相关的科研工作时候,我遇到了和OpenCV相关很棘手的两个问题:
1.为什么的我的OpenCV安装不成功???
2.为什么我的OpenCV不能修改源码?
那个时候CSDN上的相关资料也不多,甚至现在关于OpenCV安装的很多问题,CSDN上说的也不算很清楚。与此同时那段时间也是自己比较艰难的一段时间,在OpenCV上花了很多时间和精力才终于解决了上述两个问题。我在此分享一下如何解决这两个问题。
本篇主要详细记录一下如何在Windows 操作系统下,搭建Visual Studio+OpenCV+OpenCV contrib的运行环境。
关于安装visual studio,最保险的方法首先去官网下载安装器:
下载 Visual Studio Tools - 免费安装 Windows、Mac、Linux
暂时使用Community版本就好,尤其是对学生or个人用户而言。
然后安装的时候,参考第一个"参考链接"(我自己安装的时候忘记截图了啦真的是很对不起了啦,谁要是质疑我就很机车了啦):
然后只要选择"使用C++的桌面开发"就好。
然后一路默认安装就好。
本地随便建一个新项目运行:
选择“控制台应用”:
项目建立之后,点击"本地Windows调试器":
然后就可以运行输出HelloWorld了:
既然要下载源码了,我们还是去OpenCV的官网,下载最新的release版本:
Releases - OpenCV
截止至2022年4月4号,最新的Release版本是OpenCV – 4.5.5。我们下载Sources(后面修改源码需要用到):
下载之后解压到特定文件夹,当前case之中我解压到了E:\Downloads\opencv-4.5.5
然后我们去下载OpenCV contrib,官网链接:
GitHub - opencv/opencv_contrib: Repository for OpenCV's extra modules
Q:为什么要下载OpenCV contrib呢?
A:因为自从OpenCV 3.0之后,很多经典的算法,比如sift和surf特征点检测算法,由于专利原因,已经不包含在OpenCV的源码当中了,需要下载OpenCV contrib包才能继续使用。
OpenCV contrib的版本记得要和OpenCV版本符合哦(例如上图我们选择的是4.X版本)。还是要下载源码哦。
下载完解压,本文的路径为:E:\Downloads\opencv_contrib-4.x
之后我们还需要去下载cmake 用于编译OpenCV。
这里别下载错了下载成source了。在安装OpenCV的过程之中,我们只需要使用Cmake的gui程序图像化运行就好,不需要去管cmake的源码。
下载完解压,本文的解压地址为:E:\Downloads\cmake-3.23.0-windows-x86_64。在bin目录下运行cmake-gui.exe即可。
前置工作结束就需要开始编译OpenCV了。
1.第一步先按下图操作:
2.弹窗出来的配置,按照自己的开发环境配置即可(本文的环境是VS 2022,平台是X64平台),然后点击"Finish"即可:
3.cmake的窗口开始打印信息:
打印出来的信息中如果出现python、matlab相关的报错,例如下图,直接pass。(Python……ptsd,想到python就ptsd……想起某人爱用python造轮子……)
这一步需要等到cmake初始编译完成。
这一步很多博客都没有写清楚如何排查,导致很多新手在之后VisualStudio阶段导包的时候出错。
上一步完成之后,大部分情况下会报错。
不出意外会看到如下的报错信息。
仔细阅读之后,我们应该查看一下CMakeDownloadLog.txt。
使用Notepad++或者其他软件打开CMakeDownloadLog.txt,
有时间的同学自己阅读和翻译。我直接说一下问题:Cmake去下载相关的包没有下载下来。
所以根据红框处的信息我们需要自行下载,方法:将链接输入到浏览器,然后就会自动下载。一些链接输入到浏览器之后,显示的是文本,那么就将文本拷贝到本地并重命名,如下图的cmake文件。
这种情况,就ctrl+s保存,注意命名。
此处我不把包上传到CSDN上,因为版本更新之后还是有可能遇到同样问题,希望后续OpenCV版本更新之后,大家能自行解决问题。
另外此处的链接可能会被屏蔽,大家自行找办法下载。
下载之后将这些包拷贝到.cache文件夹下,并且需要更改包的名字(cmake下载包之后将校验的hash码重命名到了包中),下图以ippcv包为例:
下载的包原名为:
ippicv_2020_win_intel64_20191018_general.zip
复制到CmakeDownloadLog.txt中的.cache文件夹下,并改名为:
879741a7946b814455eee6c6ffde2984-ippicv_2020_win_intel64_20191018_general.zip
其他的包同上。不赘述。
这些拷贝结束之后,我们重新configure:
然后我们在看CmakeDownLoadLog.txt,已经不报错了:
cmake也不标红和报错了:
在cmake的OPENCV_EXTRA_MODULES_PATH之中输入之前下载的OpenCV-contrib的路径(精确到modules:
再次configure,然后又看到一大堆报错:
查看CmakeDownLoadLog.txt,是的,又来了:
再次下载吧。(有一说一,多了好多微信二维码的内容,不愧是你,腾讯!不愧是你,化腾!)
下载完成,再次configure,并查看CmakeDownLoadLog.txt,好的不报错了。PS:如果过程中发现CmakeDownLoadLog.txt还是有报错,继续下载,继续复制。
另外在多次configure过程中,每次都会尝试从.cache文件中获取原始文件,再拷贝到build之后的文件夹下面,复制的过程也会打日志的。建议多点几次configure。
最后我们查看CmakeDownLoadLog.txt,我们会看到如下信息:
终于都是match了,开心!
注:史前大坑:OPENCV_ENABLE_NONFREE一定要勾选上啊!否则Nonfree没法用。
上述工作检查无误,到了这一步才可以点击Generate哦。
找到build之后的OpenCV.sln文件,用VS打开。
右键项目,并点击“重新生成解决方案”:
另外这里只是生成了debug版本,后面记得把Release版本也生成一下,Debug和Relea版本都生成之后,后续的代码才能在debug和release两个环境下运行。
这一步会等很久,等待时间从2小时到12个小时不等。
(注:这里有点错误,参考了其他一些链接,实际上只需要对CMakeTargets文件夹下的Install进行重新生成即可,如下图,但是全部重新生成应该也不影响)。
之前安装OpenCV 3.X版本没有遇到过这个错误,这次遇到了,就尝试修复一下吧。参考链接4。
vs2022重新编译opencv-python cuda加速时报错_Harry Xu的博客-CSDN博客
解决方法的核心就是找到出错的文件,然后保存为Unicode格式的文件即可。
个人猜测这个问题不修复也不会怎么影响OpenCV大部分功能的使用。
然后重新生成,可以看到没有报错了(无论是debug还是release版本)。
注:如果只重新生成INSTALL的话,之前的报错应该是不会出现的。
只重新生成INSTALL之后,可以看到170个项目都成功了。
我们首先创建一个空的"控制台应用"项目,就叫OpenCVtest。
然后先配置系统环境变量,Windows控制台搜索即可查询到。
然后重启电脑才会生效。
这里还是使用Release版本 x64的编译环境,debug的类似。
然后右键项目,更改属性:
然后编辑VC++目录下的包含目录(其实就是英文版本的include path):
然后把install之后的include文件夹路径添加上去(注意,是install之后的include路径,不要填错成了其他的include路径)
然后我们编辑库目录(其实就是英文版的lib path)
把install之后的lin目录输入进去(再次强调是install之后的lib目录)
链接器->附加依赖项->编辑,输入所有的xxxxx/install\x64\vc16\lib中 所有xxxd.lib文件名字:
这里建议使用windows命令行操作获取所有的XXX455.lib文件名(455是opencv版本名字,不同版本的opencv安装后,敲命令行使用不同的版本号哦)。
操作命令如下:
dir *.* /B | findstr 455.lib
复制进去:
然后我们开始测试。
为了验证我们安装OpenCV的效果,我们需要使用测试Case进行测试。
这里先测试OpenCV的基本功能,再使用SIFT算子和SURF算子进行测试。 由于SIFT算子和SURF算子都是OpenCV contrib里面才有的图像库,这两个算子能测试通过,说明OpenCV contrib安装完成(更正:opencv4.4之后sift又回到opencv普通库了……崩溃)。
在项目中输入下述代码:
// OpenCVTest.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//
#include
#include
int main()
{
cv::Mat src = cv::imread("E:\\images\\00000.jpg");//图片路径
if (src.empty())
{
std::cout << "pic is empty!\n";
return -1;
}
cv::imshow("show", src);
cv::waitKey(0);
std::cout << "Hello World!\n";
}
运行结果:
好了,说明能展示了。
参考上述文章:
代码如下:
#include
#include
#include //OpenCV 4.2.0 及之后版本
int main()
{
cv::Mat imageL = cv::imread("E:\\images\\3.jpg");
cv::Mat imageR = cv::imread("E:\\images\\4.jpg");
//提取特征点方法
//SIFT
//cv::Ptr sift = cv::xfeatures2d::SIFT::create();
cv::Ptr sift = cv::SIFT::create(); //OpenCV 4.4.0 及之后版本
//ORB
//cv::Ptr orb = cv::ORB::create();
//SURF
//cv::Ptr surf = cv::xfeatures2d::SURF::create();
//特征点
std::vector keyPointL, keyPointR;
//单独提取特征点
sift->detect(imageL, keyPointL);
sift->detect(imageR, keyPointR);
//画特征点
cv::Mat keyPointImageL;
cv::Mat keyPointImageR;
drawKeypoints(imageL, keyPointL, keyPointImageL, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
drawKeypoints(imageR, keyPointR, keyPointImageR, cv::Scalar::all(-1), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//显示窗口
cv::namedWindow("KeyPoints of imageL");
cv::namedWindow("KeyPoints of imageR");
//显示特征点
cv::imshow("KeyPoints of imageL", keyPointImageL);
cv::imshow("KeyPoints of imageR", keyPointImageR);
//特征点匹配
cv::Mat despL, despR;
//提取特征点并计算特征描述子
sift->detectAndCompute(imageL, cv::Mat(), keyPointL, despL);
sift->detectAndCompute(imageR, cv::Mat(), keyPointR, despR);
//Struct for DMatch: query descriptor index, train descriptor index, train image index and distance between descriptors.
//int queryIdx –>是测试图像的特征点描述符(descriptor)的下标,同时也是描述符对应特征点(keypoint)的下标。
//int trainIdx –> 是样本图像的特征点描述符的下标,同样也是相应的特征点的下标。
//int imgIdx –>当样本是多张图像的话有用。
//float distance –>代表这一对匹配的特征点描述符(本质是向量)的欧氏距离,数值越小也就说明两个特征点越相像。
std::vector matches;
//如果采用flannBased方法 那么 desp通过orb的到的类型不同需要先转换类型
if (despL.type() != CV_32F || despR.type() != CV_32F)
{
despL.convertTo(despL, CV_32F);
despR.convertTo(despR, CV_32F);
}
cv::Ptr matcher = cv::DescriptorMatcher::create("FlannBased");
matcher->match(despL, despR, matches);
//计算特征点距离的最大值
double maxDist = 0;
for (int i = 0; i < despL.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
maxDist = dist;
}
//挑选好的匹配点
std::vector< cv::DMatch > good_matches;
for (int i = 0; i < despL.rows; i++)
{
if (matches[i].distance < 0.5 * maxDist)
{
good_matches.push_back(matches[i]);
}
}
cv::Mat imageOutput;
cv::drawMatches(imageL, keyPointL, imageR, keyPointR, good_matches, imageOutput);
cv::namedWindow("picture of matching");
cv::imshow("picture of matching", imageOutput);
cv::waitKey(0);
return 0;
}
原始图像如下:
运行结果:
代码如下,参考了:
【OpenCV】OpenCV 4 下 SIFT、SURF的使用_魏Gordon的博客-CSDN博客_opencv4 surf
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/xfeatures2d/nonfree.hpp"
#include "opencv2/xfeatures2d.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/imgproc.hpp"
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main()
{
//【0】改变console字体颜色
system("color 1F");
//【1】载入原始图片
Mat srcImage1 = imread("E:/images/3.jpg", 1);
Mat srcImage2 = imread("E:/images/4.jpg", 1);
Mat copysrcImage1 = srcImage1.clone();
Mat copysrcImage2 = srcImage2.clone();
if (!srcImage1.data || !srcImage2.data)
{
printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false;
}
//【2】使用SURF算子检测关键点
int minHessian = 100;//SURF算法中的hessian阈值
Ptr detector = SURF::create(minHessian);//定义一个SurfFeatureDetector(SURF) 特征检测类对象
// Ptr detector = cv::xfeatures2d::SURF::create(400);
vector keypoints_object, keypoints_scene;//vector模板类,存放任意类型的动态数组
//【3】调用detect函数检测出SURF特征关键点,保存在vector容器中
detector->detect(srcImage1, keypoints_object);
detector->detect(srcImage2, keypoints_scene);
//【4】计算描述符(特征向量)
Ptr extractor = SURF::create();
Mat descriptors_object, descriptors_scene;
extractor->compute(srcImage1, keypoints_object, descriptors_object);
extractor->compute(srcImage2, keypoints_scene, descriptors_scene);
//【5】使用FLANN匹配算子进行匹配
FlannBasedMatcher matcher;
vector< DMatch > matches;
matcher.match(descriptors_object, descriptors_scene, matches);
double max_dist = 0; double min_dist = 100;//最小距离和最大距离
//【6】计算出关键点之间距离的最大值和最小值
for (int i = 0; i < descriptors_object.rows; i++)
{
double dist = matches[i].distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
printf(">Max dist 最大距离 : %f \n", max_dist);
printf(">Min dist 最小距离 : %f \n", min_dist);
//【7】存下匹配距离小于3*min_dist的点对
std::vector< DMatch > good_matches;
for (int i = 0; i < descriptors_object.rows; i++)
{
if (matches[i].distance < 3 * min_dist)
{
good_matches.push_back(matches[i]);
}
}
//绘制出匹配到的关键点
Mat img_matches;
drawMatches(srcImage1, keypoints_object, srcImage2, keypoints_scene,
good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
//定义两个局部变量
vector obj;
vector scene;
//从匹配成功的匹配对中获取关键点
for (unsigned int i = 0; i < good_matches.size(); i++)
{
obj.push_back(keypoints_object[good_matches[i].queryIdx].pt);
scene.push_back(keypoints_scene[good_matches[i].trainIdx].pt);
}
vector listpoints;
//Mat H = findHomography( obj, scene, CV_RANSAC );//计算透视变换
Mat H = findHomography(obj, scene, RANSAC, 3, listpoints);//计算透视变换
std::vector< DMatch > goodgood_matches;
for (int i = 0; i < listpoints.size(); i++)
{
if ((int)listpoints[i])
{
goodgood_matches.push_back(good_matches[i]);
cout << (int)listpoints[i] << endl;
}
}
cout << "listpoints大小:" << listpoints.size() << endl;
cout << "goodgood_matches大小:" << goodgood_matches.size() << endl;
cout << "good_matches大小:" << good_matches.size() << endl;
Mat Homgimg_matches;
drawMatches(copysrcImage1, keypoints_object, copysrcImage2, keypoints_scene,
goodgood_matches, Homgimg_matches, Scalar::all(-1), Scalar::all(-1),
vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("去除误匹配点后;", Homgimg_matches);
//从待测图片中获取角点
vector obj_corners(4);
obj_corners[0] = cvPoint(0, 0); obj_corners[1] = cvPoint(srcImage1.cols, 0);
obj_corners[2] = cvPoint(srcImage1.cols, srcImage1.rows); obj_corners[3] = cvPoint(0, srcImage1.rows);
vector scene_corners(4);
//进行透视变换
perspectiveTransform(obj_corners, scene_corners, H);
//绘制出角点之间的直线
line(img_matches, scene_corners[0] + Point2f(static_cast(srcImage1.cols), 0), scene_corners[1] + Point2f(static_cast(srcImage1.cols), 0), Scalar(255, 0, 123), 4);
line(img_matches, scene_corners[1] + Point2f(static_cast(srcImage1.cols), 0), scene_corners[2] + Point2f(static_cast(srcImage1.cols), 0), Scalar(255, 0, 123), 4);
line(img_matches, scene_corners[2] + Point2f(static_cast(srcImage1.cols), 0), scene_corners[3] + Point2f(static_cast(srcImage1.cols), 0), Scalar(255, 0, 123), 4);
line(img_matches, scene_corners[3] + Point2f(static_cast(srcImage1.cols), 0), scene_corners[0] + Point2f(static_cast(srcImage1.cols), 0), Scalar(255, 0, 123), 4);
//显示最终结果
imshow("效果图", img_matches);
waitKey(0);
return 0;
}
测试结果如下。
在OpenCV4.X版本中,SURF依然是OpenCV contrib中的代码。SURF代码测试成功,说明我们的安装已经成功了。
看到这里的都不容易,大家休息一下吧。
另外给公众号打一个广告,欢迎大家的关注。
公众号:潜艇上的技术小屋,和潜艇没有半毛钱关系的互联网技术公众号。
OpenCV的安装的确是一个非常复杂和麻烦的过程,即使我之前已经有了成功安装的经验,这一次安装(加写教程)还是花了我大约一天的时间。
在安装过程中,主要注意以下几点:
1.cmake阶段注意查看Cmake的报错信息,及时检查CMakeDownLog.txt文件;
2.根据日志文件自行下载相应的依赖;
3.最后的测试case能够跑通才算完成整个安装流程。
VS2019+OpenCV4.1.0安装及整合详细步骤 - 简书
OpenCV3.3+contrib+VS2017+CMake+Win10_码代马的博客-CSDN博客
OpenCV+opencv_contrib+VS2015+CMake+Win10编译过程_TechGreat的博客-CSDN博客_cmake opencv_contrib
vs2022重新编译opencv-python cuda加速时报错_Harry Xu的博客-CSDN博客win10 +visual studio 2019 +opencv4.5.0+opencv_contrib4.5.0源码编译安装_语符律的博客-CSDN博客_win10安装opencv4.5
OpenCV3.4.0+Visual Studio2017配置 - 上中下,高平宽 - 博客园
opencv::sift特征提取 - osbreak - 博客园
【VS2017】【OpenCV4.0.0】调用SIFT出错_啊吼!的博客-CSDN博客