1. 程式人生 > >透視變換和仿射變換(下)

透視變換和仿射變換(下)

其實說白了仿射變換是透視變換的特殊形式,只不過透視變換的角度擴充套件到了z座標,相當於從空間中另一個平面看這個圖,仿射變換在同一個平面不同角度看同一個圖,一下是透視變換的一個例子,通過一個原圖(一個原圖,一個做了相應變換的圖),來確定變換的方位,思想還是上節的思想:

1.通過原圖的幾個點和變換圖中對應的幾個點的關係,計算出變換矩陣(這裡對應點是利用surf演算法計算的)

2.然後利用原圖的四個點通過變換矩陣來計算變換後圖的四個點(就是圖的四個頂點啦)

3.把這四個點連線就是圖的方位了。

#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/features2d/features2d.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/calib3d/calib3d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
using namespace cv;
using namespace std;
int main()
{
	Mat srcImage1=imread("1.jpg",1);
	Mat srcImage2=imread("3.jpg",1);
	int minHessian=400;
	SurfFeatureDetector detector(minHessian); //surf特徵提取
	vector<KeyPoint>keyPoints_object,keyPoints_scene; //原圖的關鍵的和場景圖的關鍵點
	detector.detect(srcImage1,keyPoints_object); //提取關鍵點
	detector.detect(srcImage2,keyPoints_scene);  //提取場景的關鍵點
	SurfDescriptorExtractor extractor;
	Mat descriptors_object,descriptors_scene;  //定義連個描述子
	extractor.compute(srcImage1,keyPoints_object,descriptors_object); //計算描述子
	extractor.compute(srcImage2,keyPoints_scene,descriptors_scene);
	FlannBasedMatcher matcher;  //flann匹配
	vector<DMatch>matches;  //定義匹配結構
	matcher.match(descriptors_object,descriptors_scene,matches);   //計算匹配
	double max_dis=0;
	double min_dis=100;

	for(int i=0;i<descriptors_object.rows;i++) //在所有的匹配中找最大和最小的
	{
		double dist=matches[i].distance;
		if(dist<min_dis) min_dis=dist; //獲取最小的
		if(dist>max_dis) max_dis=dist;
	}

	vector<DMatch>good_matches;
	for(int i=0;i<descriptors_object.rows;i++)
	{
		if(matches[i].distance<3*min_dis)
		{
			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<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
	//繪製匹配點
	vector<Point2f>obj;
	vector<Point2f>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);
	}
	Mat H=findHomography(obj,scene,CV_RANSAC); //在兩個對應的點集總尋找變換矩陣
	vector<Point2f>obj_corner(4); //定義原來圖的四個點
	obj_corner[0]=cvPoint(0,0);  //左下角座標
	obj_corner[1]=cvPoint(srcImage1.cols,0);  //右下角座標
	obj_corner[2]=cvPoint(srcImage1.cols,srcImage1.rows); //右上角座標
	obj_corner[3]=cvPoint(0,srcImage1.rows); //左上角座標
	vector<Point2f>scene_corners(4);  //待求取圖的四個角座標
	perspectiveTransform(obj_corner,scene_corners,H);//利用變換矩陣來求這四個角的座標

	line(img_matches,scene_corners[0]+Point2f(static_cast<float>(srcImage1.cols),0),scene_corners[1]+Point2f(static_cast<float>(srcImage1.cols),0),Scalar(255,0,123),4);
	line(img_matches,scene_corners[1]+Point2f(static_cast<float>(srcImage1.cols),0),scene_corners[2]+Point2f(static_cast<float>(srcImage1.cols),0),Scalar(255,0,123),4);
	line(img_matches,scene_corners[2]+Point2f(static_cast<float>(srcImage1.cols),0),scene_corners[3]+Point2f(static_cast<float>(srcImage1.cols),0),Scalar(255,0,123),4);
	line(img_matches,scene_corners[3]+Point2f(static_cast<float>(srcImage1.cols),0),scene_corners[0]+Point2f(static_cast<float>(srcImage1.cols),0),Scalar(255,0,123),4);
	imshow("xiaoguo1",img_matches);

	line(srcImage2,scene_corners[0],scene_corners[1],Scalar(255,0,123),4);
	cout<<scene_corners[0]<<endl<<scene_corners[1]<<endl<<scene_corners[2]<<endl<<scene_corners[3];
	line(srcImage2,scene_corners[1],scene_corners[2],Scalar(255,0,123),4);
	line(srcImage2,scene_corners[2],scene_corners[3],Scalar(255,0,123),4);
	line(srcImage2,scene_corners[3],scene_corners[0],Scalar(255,0,123),4);
	imshow("xiaoguo2",srcImage2);

	waitKey(0);
	return 0;
}

注意:這個line函式中兩個點的座標可以超出影象的範圍,只不過的畫線的時候會被圖的邊框切掉!

效果如下: