一,首先我們對函數先進行分析
findHomography:
計算多個二維點對之間的最優單映射變換矩陣 H(3行x3列) (就是對圖片的矯正),使用最小均方誤差或者RANSAC方法
函數功能:找到兩個平面之間的轉換矩陣。
這里涉及到映射變換的知識,
下面介紹下什么是映射變換:
1,如下圖所示:

一維射影變換:
二維的圖像是這樣的
射影變換也叫做單應(Homography)
圖1通過H矩陣變換變成圖2,就是這個函數的公式
X′=HX
X′代表圖2
其操作過程
- 在“大”圖像(目標圖像)上選擇4個點和“小”圖像(被合並圖像)的四角做對應,然后根據這4對對應的點計算兩幅圖像的單應矩陣。
- 得到單應矩陣H后,利用函數warpPerspective將H應用到“小”圖像上,得到圖像M
- 將圖像M合並到目標圖像中選擇的四個點的位置
1 Mat cv::findHomography ( InputArray srcPoints, 2 InputArray dstPoints, 3 int method = 0, 4 double ransacReprojThreshold = 3, 5 OutputArray mask = noArray(), 6 const int maxIters = 2000, 7 const double confidence = 0.995
8 )
參數詳解:
srcPoints 源平面中點的坐標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型
dstPoints 目標平面中點的坐標矩陣,可以是CV_32FC2類型,也可以是vector<Point2f>類型
method 計算單應矩陣所使用的方法。不同的方法對應不同的參數,具體如下:
0 - 利用所有點的常規方法
RANSAC - RANSAC-基於RANSAC的魯棒算法
LMEDS - 最小中值魯棒算法
RHO - PROSAC-基於PROSAC的魯棒算法
ransacReprojThreshold
將點對視為內點的最大允許重投影錯誤閾值(僅用於RANSAC和RHO方法)。如果
則點被認為是個外點(即錯誤匹配點對)。若srcPoints和dstPoints是以像素為單位的,則該參數通常設置在1到10的范圍內。
mask
可選輸出掩碼矩陣,通常由魯棒算法(RANSAC或LMEDS)設置。 請注意,輸入掩碼矩陣是不需要設置的。
maxIters RANSAC 算法的最大迭代次數,默認值為2000。
confidence 可信度值,取值范圍為0到1.
首先定義兩個vector保存對應的4對點
1 //圖片映射矩陣把不同角度的圖片矯正
2 void findHomographyText(){ 3
4 // Read source image.
5 Mat src = imread("F:\\視覺\\opencv\\pic\\1.png"); 6 // Four corners of the book in source image
7 vector<Point2f> pts_src; 8 pts_src.push_back(Point2f(0, 0)); 9 pts_src.push_back(Point2f(src.cols, 0)); 10 pts_src.push_back(Point2f(src.cols, src.rows)); 11 pts_src.push_back(Point2f(0, src.rows)); 12
13 // Four corners of the book in destination image.
14 vector<Point2f> pts_dst; 15 pts_dst.push_back(Point2f(0, 0)); 16 pts_dst.push_back(Point2f(src.cols/4, 0)); 17 pts_dst.push_back(Point2f(src.cols/3, src.rows)); 18 pts_dst.push_back(Point2f(0, src.rows/2)); 19
20 // Calculate Homography
21 Mat h = findHomography(pts_src, pts_dst); 22
23 // Output image
24 Mat im_out; 25 // Warp source image to destination based on homography
26 warpPerspective(src, im_out, h, src.size()); 27
28 // Display images
29 imshow("Source Image", src); 30 imshow("Warped Source Image", im_out); 31
32 waitKey(0); 33
34 }
結果如下圖所示對圖像進行拉伸
步驟如下
1,相求H
1 vector<Point2f> pts_src; 2 pts_src.push_back(Point2f(0, 0)); 3 pts_src.push_back(Point2f(src.cols, 0)); 4 pts_src.push_back(Point2f(src.cols, src.rows)); 5 pts_src.push_back(Point2f(0, src.rows)); 6
7 // Four corners of the book in destination image.
8 vector<Point2f> pts_dst; 9 pts_dst.push_back(Point2f(0, 0)); 10 pts_dst.push_back(Point2f(src.cols/4, 0)); 11 pts_dst.push_back(Point2f(src.cols/3, src.rows)); 12 pts_dst.push_back(Point2f(0, src.rows/2)); 13
14 // Calculate Homography
15 Mat h = findHomography(pts_src, pts_dst);
通過H求對應的圖像(映射到輸出圖片上)
warpPerspective(src, im_out, h, src.size());
warpPerspective:通過H求取
im_out輸出值介紹完兩個主要的函數下面開始對圖像進行識別和標記
2,SURF對圖像的識別和標記
1,開發思路
(1)使用SIFT或者SURF進行角點檢測,獲取兩個圖像的的角點集合
(2)根據兩個集合,使用特征點匹配,匹配類似的點 FlannBasedMatcher
(3)過濾特征點對。
(4)通過特征點對,求出H值
(5)畫出特征區域
代碼實現:
1,使用SIFT或者SURF進行角點檢測,獲取兩個圖像的的角點集合
1 src = imread("F:\\視覺\\opencv\\pic\\11.png");//讀圖片
2 src3 = imread("F:\\視覺\\opencv\\pic\\5.png");//讀圖片
3
4 int minHessian = 400; 5 cvtColor(src, src, COLOR_BGR2GRAY); 6 cvtColor(src3, src3, COLOR_BGR2GRAY); 7
8 Ptr<SIFT> detector = SIFT::create(minHessian); 9 vector<KeyPoint> keypoints_obj;//圖片1特征點
10 vector<KeyPoint> keypoints_scene;//圖片2特征點
11 Mat descriptor_obj, descriptor_scene; 12
13 //找出特征點存到keypoints_obj與keypoints_scene點集中
14 detector->detectAndCompute(src, Mat(), keypoints_obj, descriptor_obj); 15 detector->detectAndCompute(src3, Mat(), keypoints_scene, descriptor_scene); 16
17 // matching 找到特征集合
18 FlannBasedMatcher matcher; 19 vector<DMatch> matches; 20 matcher.match(descriptor_obj, descriptor_scene, matches);
2,過濾相似度高的圖像
1 // find good matched points
2 double minDist = 1000; 3 double maxDist = 0; 4
5 for (int i = 0; i < descriptor_obj.rows; i++) { 6 double dist = matches[i].distance; 7 if (dist > maxDist) { 8 maxDist = dist; 9 } 10 if (dist < minDist) { 11 minDist = dist; 12 } 13 } 14 printf("max distance : %f\n", maxDist); 15 printf("min distance : %f\n", minDist); 16
17 vector<DMatch> goodMatches; 18 //過濾相同的點
19 for (int i = 0; i < descriptor_obj.rows; i++) { 20 double dist = matches[i].distance;//相識度
21 printf("distance : %f\n", dist); 22 if (dist < max(3 * minDist, 0.2)) { 23 goodMatches.push_back(matches[i]); 24 } 25 }
3,求出H
1 vector<Point2f> obj; 2 vector<Point2f> objInScene; 3 for (size_t t = 0; t < goodMatches.size(); t++) { 4 //把DMatch轉成坐標 Point2f
5 obj.push_back(keypoints_obj[goodMatches[t].queryIdx].pt); 6
7 objInScene.push_back(keypoints_scene[goodMatches[t].trainIdx].pt); 8 } 9 //用來求取“射影變換”的H轉制矩陣函數 X'=H X ,並使用RANSAC消除一些出錯的點
10 Mat H = findHomography(obj, objInScene, RANSAC);
4,使用H求出映射到大圖的點
1 vector<Point2f> obj_corners(4); 2 vector<Point2f> scene_corners(4); 3 obj_corners[0] = Point(0, 0); 4 obj_corners[1] = Point(src.cols, 0); 5 obj_corners[2] = Point(src.cols, src.rows); 6 obj_corners[3] = Point(0, src.rows); 7 //透視變換(把斜的圖片扶正)
8 cout << H << endl; 9 perspectiveTransform(obj_corners, scene_corners, H);
5,在原圖上畫線段
1 Mat dst; 2 cvtColor(src3, dst, COLOR_GRAY2BGR); 3 line(dst, scene_corners[0], scene_corners[1], Scalar(0, 0, 255), 2, 8, 0); 4 line(dst, scene_corners[1], scene_corners[2], Scalar(0, 0, 255), 2, 8, 0); 5 line(dst, scene_corners[2], scene_corners[3], Scalar(0, 0, 255), 2, 8, 0); 6 line(dst, scene_corners[3], scene_corners[0], Scalar(0, 0, 255), 2, 8, 0); 7
8
9 imshow("Draw object", dst);
相似效果