其实说白了仿射变换是透视变换的特殊形式,只不过透视变换的角度扩展到了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; }
效果如下: