欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-01 12:41:46
...
#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)