透視變換和仿射變換(下)
阿新 • • 發佈:2019-02-15
其實說白了仿射變換是透視變換的特殊形式,只不過透視變換的角度擴充套件到了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函式中兩個點的座標可以超出影象的範圍,只不過的畫線的時候會被圖的邊框切掉!
效果如下: