opencv3/C++ 平面對(duì)象識(shí)別&透視變換方式
findHomography( )
函數(shù)findHomography( )找到兩個(gè)平面之間的透視變換H。
參數(shù)說明:
Mat findHomography( InputArray srcPoints, //原始平面中點(diǎn)的坐標(biāo) InputArray dstPoints, //目標(biāo)平面中點(diǎn)的坐標(biāo) int method = 0, //用于計(jì)算單應(yīng)性矩陣的方法 double ransacReprojThreshold = 3, OutputArray mask=noArray(), //通過魯棒法(RANSAC或LMEDS)設(shè)置的可選輸出掩碼 const int maxIters = 2000, //RANSAC迭代的最大次數(shù),2000是它可以達(dá)到的最大值 const double confidence = 0.995 //置信度 );
用于計(jì)算單應(yīng)性矩陣的方法有:
0 :使用所有點(diǎn)的常規(guī)方法;
RANSAC:基于RANSAC的魯棒法;
LMEDS :最小中值魯棒法;
RHO :基于PROSAC的魯棒法;

被最小化。如果參數(shù)方法被設(shè)置為默認(rèn)值0,則函數(shù)使用所有的點(diǎn)對(duì)以簡單的最小二乘方案計(jì)算初始單應(yīng)性估計(jì)。
然而,如果不是所有的點(diǎn)對(duì)
都符合剛性透視變換(也就是說有一些異常值),那么這個(gè)初始估計(jì)就會(huì)很差。在這種情況下,可以使用三種魯棒法之一。方法RANSAC,LMeDS和RHO嘗試使用這個(gè)子集和一個(gè)簡單的最小二乘算法來估計(jì)單應(yīng)矩陣的各個(gè)隨機(jī)子集(每個(gè)子集有四對(duì)),然后計(jì)算計(jì)算的單應(yīng)性的質(zhì)量/良好度(這是RANSAC的內(nèi)點(diǎn)數(shù)或LMeD的中值重投影誤差)。然后使用最佳子集來產(chǎn)生單應(yīng)矩陣的初始估計(jì)和內(nèi)點(diǎn)/外點(diǎn)的掩碼。
不管方法是否魯棒,計(jì)算的單應(yīng)性矩陣都用Levenberg-Marquardt方法進(jìn)一步細(xì)化(僅在魯棒法的情況下使用inlier)以更多地減少再投影誤差。
RANSAC和RHO方法幾乎可以處理任何異常值的比率,但需要一個(gè)閾值來區(qū)分異常值和異常值。 LMeDS方法不需要任何閾值,但只有在超過50%的內(nèi)部值時(shí)才能正常工作。最后,如果沒有異常值且噪聲相當(dāng)小,則使用默認(rèn)方法(method = 0)。
perspectiveTransform()
函數(shù)perspectiveTransform()執(zhí)行矢量的透視矩陣變換。
參數(shù)說明:
void perspectiveTransform( InputArray src, //輸入雙通道或三通道浮點(diǎn)數(shù)組/圖像 OutputArray dst, //輸出與src相同大小和類型的數(shù)組/圖像 InputArray m //3x3或4x4浮點(diǎn)轉(zhuǎn)換矩陣 );
平面對(duì)象識(shí)別:
#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;
//檢測關(guān)鍵點(diǎn)并計(jì)算描述符
detector->detectAndCompute(src1, Mat(), keypoints1, descriptor1);
detector->detectAndCompute(src2, Mat(), keypoints2, descriptor2);
//基于Flann的描述符匹配器
FlannBasedMatcher matcher;
std::vector<DMatch>matches;
//從查詢集中查找每個(gè)描述符的最佳匹配
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類用于匹配關(guān)鍵點(diǎn)描述符的
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);
//繪制出變換后的目標(biāo)輪廓,由于左側(cè)為圖像src2故坐標(biāo)點(diǎn)整體右移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);
//在原圖上繪制出變換后的目標(biāo)輪廓
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++ 平面對(duì)象識(shí)別&透視變換方式就是小編分享給大家的全部內(nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Python3實(shí)現(xiàn)定時(shí)任務(wù)的四種方式
Python實(shí)現(xiàn)定點(diǎn)與定時(shí)任務(wù)方式比較多,找到下面四中實(shí)現(xiàn)方式,每個(gè)方式都有自己應(yīng)用場景;下面來快速介紹Python中常用的定時(shí)任務(wù)實(shí)現(xiàn)方式,一起看看吧2019-06-06
詳解Python list和numpy array的存儲(chǔ)和讀取方法
這篇文章主要介紹了詳解Python list和numpy array的存儲(chǔ)和讀取方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-11-11
python讀取圖像矩陣文件并轉(zhuǎn)換為向量實(shí)例
這篇文章主要介紹了python讀取圖像矩陣文件并轉(zhuǎn)換為向量實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-06-06
PyTorch實(shí)現(xiàn)MNIST數(shù)據(jù)集手寫數(shù)字識(shí)別詳情
這篇文章主要介紹了PyTorch實(shí)現(xiàn)MNIST數(shù)據(jù)集手寫數(shù)字識(shí)別詳情,文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-09-09
Python跨文件實(shí)現(xiàn)字符串填充的三種實(shí)現(xiàn)方法
本文主要介紹了Python跨文件實(shí)現(xiàn)字符串填充的三種實(shí)現(xiàn)方法,包括format方法、%格式化操作符和eval函數(shù)結(jié)合f-string,具有一定的參考價(jià)值,感興趣的可以了解一下2024-12-12
Scrapy啟動(dòng)報(bào)錯(cuò)invalid syntax的解決
這篇文章主要介紹了Scrapy啟動(dòng)報(bào)錯(cuò)invalid syntax的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-09-09
pycharm部署django項(xiàng)目到云服務(wù)器的詳細(xì)流程
今天重點(diǎn)給大家介紹pycharm部署django項(xiàng)目到云服務(wù)器的詳細(xì)流程,首先大家需要先下載python3.8壓縮包,然后通過一系列命令完成操作,具體實(shí)現(xiàn)方法,跟隨小編一起看看吧2021-06-06
Python實(shí)現(xiàn)遍歷目錄的方法【測試可用】
這篇文章主要介紹了Python實(shí)現(xiàn)遍歷目錄的方法,涉及Python針對(duì)目錄與文件的遍歷、判斷、讀取相關(guān)操作技巧,需要的朋友可以參考下2017-03-03

