溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換

發(fā)布時(shí)間:2022-04-16 10:48:43 來源:億速云 閱讀:244 作者:iii 欄目:編程語言

本篇內(nèi)容主要講解“opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換”,感興趣的朋友不妨來看看。本文介紹的方法操作簡(jiǎn)單快捷,實(shí)用性強(qiáng)。下面就讓小編來帶大家學(xué)習(xí)“opencv3/C++中怎么實(shí)現(xiàn)平面對(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的魯棒法;

opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換

被最小化。如果參數(shù)方法被設(shè)置為默認(rèn)值0,則函數(shù)使用所有的點(diǎn)對(duì)以簡(jiǎn)單的最小二乘方案計(jì)算初始單應(yīng)性估計(jì)。

然而,如果不是所有的點(diǎn)對(duì) opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換 都符合剛性透視變換(也就是說有一些異常值),那么這個(gè)初始估計(jì)就會(huì)很差。在這種情況下,可以使用三種魯棒法之一。方法RANSAC,LMeDS和RHO嘗試使用這個(gè)子集和一個(gè)簡(jiǎn)單的最小二乘算法來估計(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;
 //檢測(cè)關(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++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換

opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換

opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換

到此,相信大家對(duì)“opencv3/C++中怎么實(shí)現(xiàn)平面對(duì)象識(shí)別和透視變換”有了更深的了解,不妨來實(shí)際操作一番吧!這里是億速云網(wǎng)站,更多相關(guān)內(nèi)容可以進(jìn)入相關(guān)頻道進(jìn)行查詢,關(guān)注我們,繼續(xù)學(xué)習(xí)!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI