透视变换和仿射变换(下)

其实说白了仿射变换是透视变换的特殊形式,只不过透视变换的角度扩展到了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函数中两个点的坐标可以超出图像的范围,只不过的画线的时候会被图的边框切掉!

效果如下:

透视变换和仿射变换(下)_第1张图片

你可能感兴趣的:(透视变换和仿射变换(下))