使用(ransac)随机采样一致算法进行图像匹配

#include<opencv2/opencv.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<iostream>
using namespace cv;
using namespace cv::xfeatures2d;
using namespace std;

//使用对称性测试以及RANSAC匹配特征点。
//1.这是进行图像匹配的第一步工作,寻找优质的特征点,
//要用这些特征点来计算基本矩阵,所以必须对我们得到的特征点进行精细的筛选工作。
int ratioTest(vector<vector<DMatch> >& matches);
void symmetry(const vector<vector<DMatch>>& matches1, const vector<vector<DMatch>>& matches2, vector<DMatch>& symmetry);
Mat ransac_test(vector<DMatch>& matches, vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2, vector<DMatch>& out_matches);

int main()
{
	Mat  image = imread("植物.jpg");
	Mat image1;
	resize(image, image, Size(400, 600));//缩放
	//灰度变换
	cvtColor(image, image1, CV_BGR2GRAY);

	Mat image0 = imread("植物2.jpg");
	resize(image0, image0, Size(400, 600));//缩放
	Mat image2;
	cvtColor(image0, image2, CV_BGR2GRAY);

	imshow("image1", image1);

	//1.第一步,我们先找到特征点,并且提取特征点的描述子,为下一步做准备。
	vector<KeyPoint> keyp1, keyp2;
	Ptr<SURF> xx = SURF::create(2000);//检测器。
	//hessian值,越大,那么检测到的点就越少,hessian值是一个阈值,或者说是一个淘汰值,小于则不会被选取。

	xx->detect(image1, keyp1);//在image中找出特征点。
	xx->detect(image2, keyp2);

	Mat des1, des2;
	xx->compute(image1, keyp1, des1);//描述子。
	xx->compute(image2, keyp2, des2);
	//1.
	Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create(1);//描述子匹配器。???????matcherType到底是什么意思???、
	vector<vector<DMatch>> matches1,matches2;//DMatch是中有两个元素,指向第一个向量的索引和指向第二个向量的索引。(两个匹配点的信息)
	//matches1.distance :less is better越小越好。 
	//每个图像的一个点,在另一个图像中找到两个匹配点,方便我们筛选,
	//如果这两个离的太近,那么说明会产生误差,我们舍弃,如果离的太远,那么说明有一个是可靠的。
	matcher->knnMatch(des1, des2, matches1,2);//将复合的匹配放入描述子中。//注意,des2和des1的顺序和结果也有关系。
	matcher->knnMatch(des2,des1,matches2,2);//注意knnMatch 的用法,是为一个点找到多个点。
	
	//然后我们需要从中筛选排在前列的匹配点。
	
	
	//2.

	Mat image_matches1, image_matches2;//我们来测试两幅图的匹配是否相同。
	


	//然后我们需要删除那些,两个匹配点非常靠近的点。怎么比较??
	//matches.ditance第一个比第二个小,所以,第二越大,说明,两个特征点离的越近,他们的比率就越接近于1.
	//所以我们要排除那些比率大于一定阈值的点,我们用一个函数,retioTest();
	int removed = ratioTest(matches1);
	removed = ratioTest(matches2);
	//转换keypoint为point2f//因为findFundamentalMat 只接受point2f格式。

	//以上两个语句,我们就移除了会产生歧义的匹配。
	//3.我们要看两幅图中对称的匹配点,不对称的我们不考虑。对称方法我们也单独设置一个函数symmetryTest()。
	vector<DMatch>sym;
	symmetry(matches1,matches2,sym);
	
	//drawMatches(image,keyp1,image0,keyp2,sym,image_matches1);
	//imshow("结果",image_matches1);
	
	//求基础矩阵。
	Mat fundemental;
	vector<DMatch> newone;
	fundemental = ransac_test(sym,keyp1,keyp2,newone);
	drawMatches(image, keyp1, image0, keyp2, newone, image_matches1);
	imshow("结果",image_matches1);



	waitKey(0);
	return 0;
}



//删除那些离的太过于相近的特征点。
int ratioTest(vector<vector<DMatch> >& matches) //matches存储着最优点和次优点。
{
	int removed = 0;//删除的点计数。
	for (vector<vector<DMatch>>::iterator matche_iterator = matches.begin(); matche_iterator != matches.end(); matche_iterator++)
	{
		if (matche_iterator->size() > 1)//如果存入的两个特征点,才进行处理。
		{
			if ((*matche_iterator)[0].distance / (*matche_iterator)[1].distance > 0.79)//我们将阈值设置为,说明:这个阈值设置的越大,跃接近于1,说明删除的越少。当阈值等于0时,
				//就等于是删除了所有的匹配点。
			{
				matche_iterator->clear();//移除匹配。
				removed++;
			}
		}
		else//将不能达到两个匹配的点,也进行移除。
		{
			matche_iterator->clear();
			removed++;

		}

	}

	return removed;
}



//检验是否对称匹配。
void symmetry(const vector<vector<DMatch>>& matches1, const vector<vector<DMatch>>& matches2, vector<DMatch>& symmetry)
{
	for (vector<vector<DMatch>>::const_iterator matche_iterator1 = matches1.begin(); matche_iterator1 != matches1.end(); ++matche_iterator1)
	{
		if (matche_iterator1->size() < 2) continue;//是之前检验阈值时被删除的点。


		for (vector<vector<DMatch>>::const_iterator matche_iterator2 = matches2.begin(); matche_iterator2 != matches2.end(); ++matche_iterator2)
		{

			if (matche_iterator2->size() < 2) continue;

			//开始对称性检测。
			if ((*matche_iterator1)[0].queryIdx == (*matche_iterator2)[0].trainIdx && (*matche_iterator2)[0].queryIdx == (*matche_iterator1)[0].trainIdx)
			{
				symmetry.push_back(DMatch((*matche_iterator1)[0].queryIdx, (*matche_iterator1)[0].trainIdx, (*matche_iterator1)[0].distance));
				break;//图一到图二中的下一个匹配,因为是双重循环,我们找的是图一中的最优解。
			}//注意,这个break一定要在括号里边。
		}
	}
}


//我们需要创建一个基于RANSAC方法来计算F矩阵的函数。
Mat ransac_test(vector<DMatch>& matches, vector<KeyPoint>& keypoints1, vector<KeyPoint>& keypoints2, vector<DMatch>& out_matches)
{
	//函数输入一个matches,keypoints1,keypoints2
	vector<Point2f> points1, points2;
	//因为ransac函数不能用keypoints类型,所以要先将keypoints转换为point类型。
	for (vector<DMatch>::const_iterator it = matches.begin(); it != matches.end(); ++it)
	{
		//先得到左图的特征点的point类型,也就是压入,points1
		float x = keypoints1[it->queryIdx].pt.x;
		float y = keypoints1[it->queryIdx].pt.y;
		points1.push_back(Point2f(x,y));

		//同理可以得到右边图像对应的点。
		 x = keypoints2[it->trainIdx].pt.x;
		 y = keypoints2[it->trainIdx].pt.y;
		points2.push_back(Point2f(x, y));
	}

	//然后开始计算F矩阵。
	vector<uchar>inliers(points1.size(),0);
	Mat fundemental = findFundamentalMat(Mat(points1),Mat(points2),inliers,CV_FM_RANSAC);
	//提取通过的匹配点。
	vector<uchar>::const_iterator itIn = inliers.begin();
	
	vector<DMatch>::const_iterator itM = matches.begin();
	for (; itIn != inliers.end(); ++itIn, ++itM)
	{
		if (*itIn)//不为空
		{
			out_matches.push_back(*itM);
		}


	}
	
	//改善F矩阵。也就是用out_matches再进行一遍随机抽样连续一致算法。
	points1.clear();
	points2.clear();
	for (vector<DMatch>::const_iterator it = out_matches.begin(); it != out_matches.end(); ++it)
	{
		//先得到左图的特征点的point类型,也就是压入,points1
		float x = keypoints1[it->queryIdx].pt.x;
		float y = keypoints1[it->queryIdx].pt.y;
		points1.push_back(Point2f(x, y));

		//同理可以得到右边图像对应的点。
		x = keypoints2[it->trainIdx].pt.x;
		y = keypoints2[it->trainIdx].pt.y;
		points2.push_back(Point2f(x, y));


	}

	fundemental = findFundamentalMat(Mat(points1),Mat(points2));


	return fundemental;





}


```![在这里插入图片描述](https://img-blog.csdnimg.cn/20191123183406498.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dhb2N1aTg4Mw==,size_16,color_FFFFFF,t_70)
![在这里插入图片描述](https://img-blog.csdnimg.cn/2019112318343061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2dhb2N1aTg4Mw==,size_16,color_FFFFFF,t_70)
这个错误通常是因为版本问题导致的。在 OpenCV 2.x 中,BFMatcher 类没有 knnMatch 方法,而在 OpenCV 3.x 中,BFMatcher 类已经添加了 knnMatch 方法。 如果你使用的是 OpenCV 2.x 版本,则应该改用 match 方法,而不是 knnMatch 方法。如果你使用的是 OpenCV 3.x 版本或更高版本,则应该使用 knnMatch 方法。 因此,你需要检查你的 OpenCV 版本并相应地更改你的代码。如果你使用的是 OpenCV 2.x 版本,则应该将代码中的 knnMatch 替换为 match。如果你使用的是 OpenCV 3.x 版本或更高版本,则应该保留 knnMatch 方法。 以下是 OpenCV 2.x 中使用 BFMatcher 的示例代码: ``` import cv2 img1 = cv2.imread('img1.png', 0) img2 = cv2.imread('img2.png', 0) # Initiate SIFT detector sift = cv2.SIFT() # find the keypoints and descriptors with SIFT kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None) # BFMatcher with default params bf = cv2.BFMatcher() matches = bf.match(des1,des2) # Draw first 10 matches. img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2) cv2.imshow("Matches", img3) cv2.waitKey(0) ``` 以下是 OpenCV 3.x 中使用 BFMatcher 的示例代码: ``` import cv2 img1 = cv2.imread('img1.png', 0) img2 = cv2.imread('img2.png', 0) # Initiate SIFT detector sift = cv2.SIFT_create() # find the keypoints and descriptors with SIFT kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None) # BFMatcher with default params bf = cv2.BFMatcher() matches = bf.knnMatch(des1,des2,k=2) # Apply ratio test good = [] for m,n in matches: if m.distance < 0.75*n.distance: good.append([m]) # Draw first 10 matches. img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good[:10],flags=2) cv2.imshow("Matches", img3) cv2.waitKey(0) ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值