openCV 特征點識別 與findHomography算法過濾


一,首先我們對函數先進行分析

findHomography:

 計算多個二維點對之間的最優單映射變換矩陣 H(3行x3列) (就是對圖片的矯正),使用最小均方誤差或者RANSAC方法

函數功能:找到兩個平面之間的轉換矩陣。


 

這里涉及到映射變換的知識,

 

 

 下面介紹下什么是映射變換:

 1,如下圖所示:

如果平面上點場的點建立了一個一一對應,並且滿足:
(1)任何共線三點的象仍是共線三點;
(2)共線四點的交比不變。
則這個一一對應叫做點場的射影變換,簡稱射影變換
交比:     

 

 

一維射影變換:

 

 

 

 

 

 二維的圖像是這樣的

 

 

 


  射影變換也叫做單應(Homography

 

 

 

 圖1通過H矩陣變換變成圖2,就是這個函數的公式

                                       X=HX

X′代表圖2

其操作過程

  • 在“大”圖像(目標圖像)上選擇4個點和“小”圖像(被合並圖像)的四角做對應,然后根據這4對對應的點計算兩幅圖像的單應矩陣。
  • 得到單應矩陣H后,利用函數warpPerspective將H應用到“小”圖像上,得到圖像M
  • 將圖像M合並到目標圖像中選擇的四個點的位置

 

Mat cv::findHomography ( InputArray srcPoints,
InputArray dstPoints,
int method = 0,
double ransacReprojThreshold = 3,
OutputArray mask = noArray(),
const int maxIters = 2000,
const double confidence = 0.995 
)

參數詳解:

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對點

//圖片映射矩陣把不同角度的圖片矯正
void findHomographyText(){

    // Read source image.
    Mat src = imread("F:\\視覺\\opencv\\pic\\1.png");
    // Four corners of the book in source image
    vector<Point2f> pts_src;
    pts_src.push_back(Point2f(0, 0));
    pts_src.push_back(Point2f(src.cols, 0));
    pts_src.push_back(Point2f(src.cols, src.rows));
    pts_src.push_back(Point2f(0, src.rows));

    // Four corners of the book in destination image.
    vector<Point2f> pts_dst;
    pts_dst.push_back(Point2f(0, 0));
    pts_dst.push_back(Point2f(src.cols/4, 0));
    pts_dst.push_back(Point2f(src.cols/3, src.rows));
    pts_dst.push_back(Point2f(0, src.rows/2));

    // Calculate Homography
    Mat h = findHomography(pts_src, pts_dst);

    // Output image
    Mat im_out;
    // Warp source image to destination based on homography
    warpPerspective(src, im_out, h, src.size());

    // Display images
    imshow("Source Image", src);
    imshow("Warped Source Image", im_out);

    waitKey(0);

}

結果如下圖所示對圖像進行拉伸

步驟如下

1,相求H 

 vector<Point2f> pts_src;
    pts_src.push_back(Point2f(0, 0));
    pts_src.push_back(Point2f(src.cols, 0));
    pts_src.push_back(Point2f(src.cols, src.rows));
    pts_src.push_back(Point2f(0, src.rows));

    // Four corners of the book in destination image.
    vector<Point2f> pts_dst;
    pts_dst.push_back(Point2f(0, 0));
    pts_dst.push_back(Point2f(src.cols/4, 0));
    pts_dst.push_back(Point2f(src.cols/3, src.rows));
    pts_dst.push_back(Point2f(0, src.rows/2));

    // Calculate Homography
    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進行角點檢測,獲取兩個圖像的的角點集合

 src = imread("F:\\視覺\\opencv\\pic\\11.png");//讀圖片
src3 = imread("F:\\視覺\\opencv\\pic\\5.png");//讀圖片

int minHessian = 400;
    cvtColor(src, src, COLOR_BGR2GRAY);
    cvtColor(src3, src3, COLOR_BGR2GRAY);

    Ptr<SIFT> detector = SIFT::create(minHessian);
    vector<KeyPoint> keypoints_obj;//圖片1特征點
    vector<KeyPoint> keypoints_scene;//圖片2特征點
    Mat descriptor_obj, descriptor_scene;

    //找出特征點存到keypoints_obj與keypoints_scene點集中
    detector->detectAndCompute(src, Mat(), keypoints_obj, descriptor_obj);
    detector->detectAndCompute(src3, Mat(), keypoints_scene, descriptor_scene);

    // matching 找到特征集合
    FlannBasedMatcher matcher;
    vector<DMatch> matches;
    matcher.match(descriptor_obj, descriptor_scene, matches);

2,過濾相似度高的圖像

// find good matched points
    double minDist = 1000;
    double maxDist = 0;

    for (int i = 0; i < descriptor_obj.rows; i++) {
        double dist = matches[i].distance;
        if (dist > maxDist) {
            maxDist = dist;
        }
        if (dist < minDist) {
            minDist = dist;
        }
    }
    printf("max distance : %f\n", maxDist);
    printf("min distance : %f\n", minDist);

    vector<DMatch> goodMatches;
    //過濾相同的點
    for (int i = 0; i < descriptor_obj.rows; i++) {
        double dist = matches[i].distance;//相識度
        printf("distance : %f\n", dist);
        if (dist < max(3 * minDist, 0.2)) {
            goodMatches.push_back(matches[i]);
        }
    }

3,求出H

vector<Point2f> obj;
    vector<Point2f> objInScene;
    for (size_t t = 0; t < goodMatches.size(); t++) {
        //把DMatch轉成坐標 Point2f
        obj.push_back(keypoints_obj[goodMatches[t].queryIdx].pt);

        objInScene.push_back(keypoints_scene[goodMatches[t].trainIdx].pt);
    }
    //用來求取“射影變換”的H轉制矩陣函數  X'=H X ,並使用RANSAC消除一些出錯的點
    Mat H = findHomography(obj, objInScene, RANSAC);

4,使用H求出映射到大圖的點

vector<Point2f> obj_corners(4);
    vector<Point2f> scene_corners(4);
    obj_corners[0] = Point(0, 0);
    obj_corners[1] = Point(src.cols, 0);
    obj_corners[2] = Point(src.cols, src.rows);
    obj_corners[3] = Point(0, src.rows);
    //透視變換(把斜的圖片扶正)
    cout << H << endl;
    perspectiveTransform(obj_corners, scene_corners, H);

5,在原圖上畫線段

Mat dst;
	cvtColor(src3, dst, COLOR_GRAY2BGR);
	line(dst, scene_corners[0], scene_corners[1], Scalar(0, 0, 255), 2, 8, 0);
	line(dst, scene_corners[1], scene_corners[2], Scalar(0, 0, 255), 2, 8, 0);
	line(dst, scene_corners[2], scene_corners[3], Scalar(0, 0, 255), 2, 8, 0);
	line(dst, scene_corners[3], scene_corners[0], Scalar(0, 0, 255), 2, 8, 0);


	imshow("Draw object", dst);

  相似效果

 

 

謝謝,如果覺得可以請點個贊!轉發請付鏈接。。。。

 

 原文鏈接:https://blog.csdn.net/fengyeer20120/article/details/87798638

https://www.cnblogs.com/wangguchangqing/p/4645805.html

 

// find good matched pointsdouble minDist = 1000;double maxDist = 0;
for (int i = 0; i < descriptor_obj.rows; i++) {double dist = matches[i].distance;if (dist > maxDist) {maxDist = dist;}if (dist < minDist) {minDist = dist;}}printf("max distance : %f\n", maxDist);printf("min distance : %f\n", minDist);
vector<DMatch> goodMatches;//過濾相同的點for (int i = 0; i < descriptor_obj.rows; i++) {double dist = matches[i].distance;//相識度printf("distance : %f\n", dist);if (dist < max(3 * minDist, 0.2)) {goodMatches.push_back(matches[i]);}}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM