opencv3/C++ 平面對象識別&透視變換方式
findHomography( )
函數(shù)findHomography( )找到兩個平面之間的透視變換H。
參數(shù)說明:
Mat findHomography( InputArray srcPoints, //原始平面中點的坐標 InputArray dstPoints, //目標平面中點的坐標 int method = 0, //用于計算單應性矩陣的方法 double ransacReprojThreshold = 3, OutputArray mask=noArray(), //通過魯棒法(RANSAC或LMEDS)設置的可選輸出掩碼 const int maxIters = 2000, //RANSAC迭代的最大次數(shù),2000是它可以達到的最大值 const double confidence = 0.995 //置信度 );
用于計算單應性矩陣的方法有:
0 :使用所有點的常規(guī)方法;
RANSAC:基于RANSAC的魯棒法;
LMEDS :最小中值魯棒法;
RHO :基于PROSAC的魯棒法;
被最小化。如果參數(shù)方法被設置為默認值0,則函數(shù)使用所有的點對以簡單的最小二乘方案計算初始單應性估計。
然而,如果不是所有的點對 都符合剛性透視變換(也就是說有一些異常值),那么這個初始估計就會很差。在這種情況下,可以使用三種魯棒法之一。方法RANSAC,LMeDS和RHO嘗試使用這個子集和一個簡單的最小二乘算法來估計單應矩陣的各個隨機子集(每個子集有四對),然后計算計算的單應性的質量/良好度(這是RANSAC的內點數(shù)或LMeD的中值重投影誤差)。然后使用最佳子集來產生單應矩陣的初始估計和內點/外點的掩碼。
不管方法是否魯棒,計算的單應性矩陣都用Levenberg-Marquardt方法進一步細化(僅在魯棒法的情況下使用inlier)以更多地減少再投影誤差。
RANSAC和RHO方法幾乎可以處理任何異常值的比率,但需要一個閾值來區(qū)分異常值和異常值。 LMeDS方法不需要任何閾值,但只有在超過50%的內部值時才能正常工作。最后,如果沒有異常值且噪聲相當小,則使用默認方法(method = 0)。
perspectiveTransform()
函數(shù)perspectiveTransform()執(zhí)行矢量的透視矩陣變換。
參數(shù)說明:
void perspectiveTransform( InputArray src, //輸入雙通道或三通道浮點數(shù)組/圖像 OutputArray dst, //輸出與src相同大小和類型的數(shù)組/圖像 InputArray m //3x3或4x4浮點轉換矩陣 );
平面對象識別:
#include<opencv2/opencv.hpp> #include<opencv2/xfeatures2d.hpp> using namespace cv; using namespace cv::xfeatures2d; int main() { Mat src1,src2; src1 = imread("E:/image/image/card.jpg"); src2 = imread("E:/image/image/cards.jpg"); if (src1.empty() || src2.empty()) { printf("can ont load images....\n"); return -1; } imshow("image1", src1); imshow("image2", src2); int minHessian = 400; //選擇SURF特征 Ptr<SURF>detector = SURF::create(minHessian); std::vector<KeyPoint>keypoints1; std::vector<KeyPoint>keypoints2; Mat descriptor1, descriptor2; //檢測關鍵點并計算描述符 detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1); detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2); //基于Flann的描述符匹配器 FlannBasedMatcher matcher; std::vector<DMatch>matches; //從查詢集中查找每個描述符的最佳匹配 matcher.match(descriptor1, descriptor2, matches); double minDist = 1000; double maxDist = 0; for (int i = 0; i < descriptor1.rows; i++) { double dist = matches[i].distance; printf("%f \n", dist); if (dist > maxDist) { maxDist = dist; } if (dist < minDist) { minDist = dist; } } //DMatch類用于匹配關鍵點描述符的 std::vector<DMatch>goodMatches; for (int i = 0; i < descriptor1.rows; i++) { double dist = matches[i].distance; if (dist < max(2*minDist, 0.02)) { goodMatches.push_back(matches[i]); } } Mat matchesImg; drawMatches(src1, keypoints1, src2, keypoints2, goodMatches, matchesImg, Scalar::all(-1), Scalar::all(-1), std::vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); std::vector<Point2f>point1, point2; for (int i = 0; i < goodMatches.size(); i++) { point1.push_back(keypoints1[goodMatches[i].queryIdx].pt); point2.push_back(keypoints2[goodMatches[i].trainIdx].pt); } Mat H = findHomography(point1, point2, RANSAC); std::vector<Point2f>cornerPoints1(4); std::vector<Point2f>cornerPoints2(4); cornerPoints1[0] = Point(0, 0); cornerPoints1[1] = Point(src1.cols, 0); cornerPoints1[2] = Point(src1.cols, src1.rows); cornerPoints1[3] = Point(0,src1.rows); perspectiveTransform(cornerPoints1, cornerPoints2, H); //繪制出變換后的目標輪廓,由于左側為圖像src2故坐標點整體右移src1.cols line(matchesImg, cornerPoints2[0] + Point2f(src1.cols, 0), cornerPoints2[1] + Point2f(src1.cols, 0), Scalar(0,255,255), 4, 8, 0); line(matchesImg, cornerPoints2[1] + Point2f(src1.cols, 0), cornerPoints2[2] + Point2f(src1.cols, 0), Scalar(0,255,255), 4, 8, 0); line(matchesImg, cornerPoints2[2] + Point2f(src1.cols, 0), cornerPoints2[3] + Point2f(src1.cols, 0), Scalar(0,255,255), 4, 8, 0); line(matchesImg, cornerPoints2[3] + Point2f(src1.cols, 0), cornerPoints2[0] + Point2f(src1.cols, 0), Scalar(0,255,255), 4, 8, 0); //在原圖上繪制出變換后的目標輪廓 line(src2, cornerPoints2[0], cornerPoints2[1], Scalar(0,255,255), 4, 8, 0); line(src2, cornerPoints2[1], cornerPoints2[2], Scalar(0,255,255), 4, 8, 0); line(src2, cornerPoints2[2], cornerPoints2[3], Scalar(0,255,255), 4, 8, 0); line(src2, cornerPoints2[3], cornerPoints2[0], Scalar(0,255,255), 4, 8, 0); imshow("output", matchesImg); imshow("output2", src2); waitKey(); return 0; }
以上這篇opencv3/C++ 平面對象識別&透視變換方式就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
Python基于hashlib模塊的文件MD5一致性加密驗證示例
這篇文章主要介紹了Python基于hashlib模塊的文件MD5一致性加密驗證,涉及Python使用hashlib模塊進行字符串與文件的MD5加密驗證操作相關實現(xiàn)技巧,需要的朋友可以參考下2018-02-02解決Python中的modf()函數(shù)取小數(shù)部分不準確問題
這篇文章主要介紹了解決Python中的modf()函數(shù)取小數(shù)部分不準確問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05python:批量統(tǒng)計xml中各類目標的數(shù)量案例
這篇文章主要介紹了python:批量統(tǒng)計xml中各類目標的數(shù)量案例,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-03-03python讀取圖片的方式,以及將圖片以三維數(shù)組的形式輸出方法
今天小編就為大家分享一篇python讀取圖片的方式,以及將圖片以三維數(shù)組的形式輸出方法,具有好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-07-07pygame實現(xiàn)俄羅斯方塊游戲(對戰(zhàn)篇1)
這篇文章主要為大家詳細介紹了pygame實現(xiàn)俄羅斯方塊游戲的對戰(zhàn)篇,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-10-10