1. 程式人生 > >SIFT特徵檢測與RANSAC過濾

SIFT特徵檢測與RANSAC過濾

/*
 *@function SiftDetect.cpp
 *@brief 對sift特徵檢測和匹配進行測試,並實現RANSAC演算法進行過濾錯配點
 *@author ltc
 *@date 11:20 Saturday,28 November,2015
 */
#include<iostream>
#include<opencv2\opencv.hpp>
#include<opencv2\nonfree\nonfree.hpp>
using namespace std;
using namespace cv;


//RANSAC演算法
vector<DMatch> ransac(vector<DMatch> matches,vector<KeyPoint> queryKeyPoint,vector<KeyPoint> trainKeyPoint);

int main(int argc,char* argv[])
{
	//影象讀取
	Mat img1,img2;
	img1=imread("1 (2).jpg",CV_WINDOW_AUTOSIZE);
	img2=imread("2 (2).jpg",CV_WINDOW_AUTOSIZE);

	if(img1.empty()||img2.empty())
	{
		return -1;
	}

	//sift特徵提取
	SiftFeatureDetector detector;	
	vector<KeyPoint> keyPoint1,keyPoint2;
	detector.detect(img1,keyPoint1);
	detector.detect(img2,keyPoint2);
	//cout<<"Number of KeyPoint1:"<<keyPoint1.size()<<endl;
	//cout<<"Number of KeyPoint2:"<<keyPoint2.size()<<endl;

	//sift特徵描述子計算
	SiftDescriptorExtractor desExtractor;
	Mat des1,des2;
	desExtractor.compute(img1,keyPoint1,des1);
	desExtractor.compute(img2,keyPoint2,des2);

	//sift特徵點(描述子)匹配
	Mat res1,res2;
//	drawKeypoints(img1,keyPoint1,res1,Scalar::all(-1),/*DrawMatchesFlags::DRAW_RICH_KEYPOINTS*/DrawMatchesFlags::DEFAULT);
//	drawKeypoints(img2,keyPoint2,res2,Scalar::all(-1),/*DrawMatchesFlags::DRAW_RICH_KEYPOINTS*/DrawMatchesFlags::DEFAULT);
	BFMatcher matcher(NORM_L2);
	FlannBasedMatcher matcher_flann;
	vector<DMatch> matches;

	vector<vector<DMatch>> matches_knn;
	matcher.match(des1,des2,matches);
	matcher.knnMatch(des1,des2,matches_knn,2);

//	cout<<"matches_knn.size:"<<matches_knn.size()<<endl;

	//sift特徵最近距離與次近距離之比小於0.6視為正確匹配
	vector<DMatch> match_knn;
	for(int i=0;i<matches_knn.size();i++)
	{
		float ratio=matches_knn[i][0].distance/matches_knn[i][1].distance;
		if(ratio<0.6)
		{
			match_knn.push_back(matches_knn[i][0]);
		}
	}

//	matcher_flann.match(des1,des2,matches_flann);

	//for(int i=0;i<matches.size();i++)
	//{
	//	cout<<"第"<<i<<"對匹配:"<<endl;
	//	cout<<"queryIdx:"<<matches[i].queryIdx<<"\ttrainIdx:"<<matches[i].trainIdx<<endl;
	//	cout<<"imgIdx:"<<matches[i].imgIdx<<"\tdistance:"<<matches[i].distance<<endl;
	//}

	//cout<<"Number of matches:"<<matches.size()<<endl;
	//cout<<"Number of matches_flann:"<<matches_flann.size()<<endl;
	
	vector<DMatch> matches_ransac=ransac(matches,keyPoint1,keyPoint2);
	Mat img_match,img_match_flann;
	
	drawMatches(img1,keyPoint1,img2,keyPoint2,matches_ransac,img_match);
	drawMatches(img1,keyPoint1,img2,keyPoint2,match_knn,img_match_flann);

	imshow("img_match",img_match);
	imshow("img_match_flann",img_match_flann);
	
	//for(size_t i=0;i<keyPoint1.size();i++)
	//{
	//	//cout<<"x:"<<kp1.at(i).pt.x<<endl;
	//	circle(img1,Point((int)(keyPoint1.at(i).pt.x),(int)(keyPoint1.at(i).pt.y)),3,Scalar(255,0,0),2,8,0);
	//}

	//imshow("img1",img1);
	//imshow("img1_",res1);
//	imshow("img2",res2);
	ransac(matches,keyPoint1,keyPoint2);
	waitKey(0);

	return 0;
}
//RANSAC演算法實現
vector<DMatch> ransac(vector<DMatch> matches,vector<KeyPoint> queryKeyPoint,vector<KeyPoint> trainKeyPoint)
{
	//定義儲存匹配點對座標
	vector<Point2f> srcPoints(matches.size()),dstPoints(matches.size());
	//儲存從關鍵點中提取到的匹配點對的座標
	for(int i=0;i<matches.size();i++)
	{
		srcPoints[i]=queryKeyPoint[matches[i].queryIdx].pt;
		dstPoints[i]=trainKeyPoint[matches[i].trainIdx].pt;
	}
	//儲存計算的單應性矩陣
	Mat homography;
	//儲存點對是否保留的標誌
	vector<unsigned char> inliersMask(srcPoints.size()); 
	//匹配點對進行RANSAC過濾
	homography = findHomography(srcPoints,dstPoints,CV_RANSAC,5,inliersMask);
	//RANSAC過濾後的點對匹配資訊
	vector<DMatch> matches_ransac;
	//手動的保留RANSAC過濾後的匹配點對
	for(int i=0;i<inliersMask.size();i++)
	{
		//cout<<inliersMask[i]<<endl;
		cout<<(int)(inliersMask[i])<<endl;
		if(inliersMask[i])
		{
			matches_ransac.push_back(matches[i]);
			//cout<<"第"<<i<<"對匹配:"<<endl;
			//cout<<"queryIdx:"<<matches[i].queryIdx<<"\ttrainIdx:"<<matches[i].trainIdx<<endl;
			//cout<<"imgIdx:"<<matches[i].imgIdx<<"\tdistance:"<<matches[i].distance<<endl;
		}
	}
	//返回RANSAC過濾後的點對匹配資訊
	return matches_ransac;
}

匹配結果: