日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较)

發(fā)布時間:2025/3/21 编程问答 48 豆豆
生活随笔 收集整理的這篇文章主要介紹了 利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较) 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

本文目標(biāo)是通過使用SIFT和RANSAC算法,完成特征點的正確匹配,并求出變換矩陣,通過變換矩陣計算出要識別物體的邊界(文章中有部分源碼,整個工程我也上傳了,請點擊這里)。

SIFT算法是目前公認(rèn)的效果最好的特征點檢測算法,關(guān)于該算法的就不多說了,網(wǎng)上的資料有很多,在此提供兩個鏈接,一個是SIFT原文的譯文,一個是關(guān)于SIFT算法的詳細(xì)解釋:

SIFT算法譯文

SIFT算法詳解

整個實現(xiàn)過程可以復(fù)述如下:提供兩張初始圖片,一幅為模板圖像,一幅為測試圖片,目的就是根據(jù)模板圖片中的物體,檢測出測試圖片中的物體,并表示出物體的具體位置和大小,測試圖片中的物體位置和大小,已經(jīng)事先用白色方框標(biāo)記。

首先,對兩幅圖片,都使用SIFT算法提取特征點,提取結(jié)果如下:(SIFT特征提取方法就用的是上文鏈接“SIFT算法詳解”中提供的代碼)


然后對特征點進行匹配,按照SIFT算法原文作者的思路,每個特征點產(chǎn)生一個128維的向量,計算向量之間的歐式距離,采用最近比次近的方式完成匹配,如果最近距離比上次近距離小于0.8,則認(rèn)為這是一個正確的匹配, 否則認(rèn)為匹配不成功。結(jié)果這種匹配后的情況如下圖:


可以發(fā)現(xiàn),仍然存在著很多錯誤的匹配點,所以再嘗試用RANSAC算法消除錯誤匹配,嘗試使用openCV中的findFundamentalMat函數(shù)消除錯誤匹配:


通過使用findFundamentalMat函數(shù),函數(shù)返回一個3*3的矩陣,一開始我認(rèn)為這個矩陣就是變換矩陣,只要將左圖中的點與這個變換矩陣相乘,就可以得到右圖中的對應(yīng)點。但是這其實是不對的。

在這里有一個誤解,就是findFundamentalMat函數(shù)確實可以使用RANSAC方法消除錯誤匹配,從名字上可以發(fā)現(xiàn),這個函數(shù)的作用是返回基礎(chǔ)矩陣的,基礎(chǔ)矩陣和變換矩陣是兩個不同的概念?;A(chǔ)矩陣描述是三維場景中的像點之間的對應(yīng)關(guān)系(其實到現(xiàn)在為止這個函數(shù)求出的基礎(chǔ)矩陣有個毛用我也不知道)。所以說,如果使用這個函數(shù),這個實驗也就能做到這一步了,沒法再往下做了。

所以,為了得到變換矩陣,后來我才發(fā)現(xiàn)openCV中還有函數(shù)findHomography,這個函數(shù)才是真正的計算變換矩陣的函數(shù),它的函數(shù)返回值才是真正的變換矩陣。

其實這個問題困擾了我很久,關(guān)于消除錯誤匹配的方法,網(wǎng)上查出來的多數(shù)都是通過findFundamentalMat函數(shù)來進行,所以我就想當(dāng)然的認(rèn)為該函數(shù)的返回值是變換矩陣了。而網(wǎng)上關(guān)于findHomography的介紹比較少,所以才會讓人們誤解findFundamentalMat會計算出變換矩陣了。

嘗試用findHomography函數(shù)返回的矩陣,在模板圖像中,已經(jīng)用綠色方框標(biāo)示出物體輪廓,根據(jù)物體的四個邊界點,與變換矩陣相乘,即可得到變換后的物體的輪廓的四個邊界點,將此邊界點連接即為物體輪廓,如下圖所示(綠色方框為事先標(biāo)注的模板物體中的輪廓,白色方框為事先標(biāo)注的測試圖片中的輪廓,紅色方框為經(jīng)過綠色方框經(jīng)變換矩陣變換后計算出的輪廓):


從結(jié)果可以看出,這才是比較正確的結(jié)果。

實驗過程中的主要代碼如下(這是主要的代碼,SIFT算法和一些其他的功能函數(shù)我都寫在了其他的文件中):

#include<math.h> #include<time.h>#include <windows.h> #include <iostream> using namespace std; #include <cv.h> #include <highgui.h> #include <cxcore.h> using namespace cv; #include "sift.h" #include "my_function.h"int main() {//加載兩幅圖片Mat src1 = imread("F:\\ylab\\image database\\camera\\obj01_001.jpg");Mat src2 = imread("F:\\ylab\\image database\\imagesTest2\\test01_.jpg");//這四個坐標(biāo)是模板圖像中綠色方框的四個頂點Point2f m1(173.0,0.0),m2(168.0,464.0),m3(507.0,464.0),m4(499.0,0.0);std::vector<Point2f> obj_corners(4);obj_corners[0] = cvPoint(173.0,0.0); obj_corners[1] = cvPoint(168.0,464.0);obj_corners[2] = cvPoint(507.0,464.0); obj_corners[3] = cvPoint(499.0,0.0);//原始圖片比較大,我這里將圖片同一處理成了640*480的大小Size certainsize=Size(640,480);Mat src_1;Mat src_2;resize(src1,src_1,certainsize);resize(src2,src_2,certainsize);//兩個圖像的特征點序列Vector<Keypoint> feature_1,feature_2;//采用sift算法,計算特征點序列,這個SIFT函數(shù)是在另外的文件中寫好的Sift(src_1, feature_1, 1.6);Sift(src_2, feature_2, 1.6);//feature_dis為帶有距離的特征點結(jié)構(gòu)體序列Vector<Key_point> feature_dis_1;Vector<Key_point> feature_dis_2;Vector<Key_point> result;//對特征點進行匹配,這個Match_feature是我自己寫的,就是采用最近比次近小于0.8即為合適的匹配,這種匹配方式//openCV中并沒有,所以我就自己寫了Match_feature(feature_1,feature_2,feature_dis_1,feature_dis_2); printf("The number of features is %d\n",feature_1.size());printf("The number of the match features is %d\n",feature_dis_1.size());//從這里開始使用RANSAC方法進行運算//下面的程序都好無奈,所有的結(jié)構(gòu)都只能轉(zhuǎn)化成openCV的類型才能用openCV的函數(shù)。。Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create( "BruteForce" );//創(chuàng)建特征匹配器 int count=feature_dis_1.size();//把特征點序列轉(zhuǎn)化成openCV能夠使用的類型vector<KeyPoint>keypoints1,keypoints2;KeyPoint keyp;for(int i=0;i<count;i++){keyp.pt.x=feature_dis_1[i].dx;keyp.pt.y=feature_dis_1[i].dy;keypoints1.push_back(keyp);keyp.pt.x=feature_dis_2[i].dx;keyp.pt.y=feature_dis_2[i].dy;keypoints2.push_back(keyp);}Mat descriptors1(count,FEATURE_ELEMENT_LENGTH, CV_32F);Mat descriptors2(count,FEATURE_ELEMENT_LENGTH, CV_32F);for (int i=0; i<count; i++){for(int j=0;j<FEATURE_ELEMENT_LENGTH;j++){descriptors1.at<float>(i,j)=feature_dis_1[i].descriptor[j];descriptors2.at<float>(i,j)=feature_dis_2[i].descriptor[j];}}Mat img_match;vector<DMatch> matches; descriptor_matcher->match( descriptors1, descriptors2, matches ); Mat img_matches;drawMatches(src_1,keypoints1,src_2,keypoints2,matches,img_matches);//其實我前面已經(jīng)完成匹配了,到這里,用openCV自帶的方式重新匹配了一遍,并且顯示了一下imshow("SIFT",img_matches);//imwrite("F:\\ylab\\CSDN_image\\3.jpg",img_matches);Mat p1(feature_dis_1.size(),2,CV_32F);Mat p2(feature_dis_1.size(),2,CV_32F);for(int i=0;i<feature_dis_1.size();i++){p1.at<float>(i,0)=feature_dis_1[i].dx;p1.at<float>(i,1)=feature_dis_1[i].dy;p2.at<float>(i,0)=feature_dis_2[i].dx;p2.at<float>(i,1)=feature_dis_2[i].dy;}// 用RANSAC方法計算FMat m_Fundamental;// 上面這個變量是基本矩陣vector<uchar> m_RANSACStatus;// 上面這個變量已經(jīng)定義過,用于存儲RANSAC后每個點的狀態(tài)//一開始使用findFundamentalMat函數(shù),發(fā)現(xiàn)可以消除錯誤匹配,實現(xiàn)很好的效果,但是//就是函數(shù)返回值不是變換矩陣,而是沒有什么用的基礎(chǔ)矩陣m_Fundamental = findFundamentalMat(p1,p2,m_RANSACStatus,CV_FM_RANSAC);//這里使用findHomography函數(shù),這個函數(shù)的返回值才是真正的變換矩陣Mat m_homography;vector<uchar> m;m_homography=findHomography(p1,p2,CV_RANSAC,3,m); //由變換矩陣,求得變換后的物體邊界四個點std::vector<Point2f> scene_corners(4);perspectiveTransform( obj_corners, scene_corners, m_homography);line( src_2, scene_corners[0] , scene_corners[1] , Scalar(0, 0, 255), 2 );line( src_2, scene_corners[1] , scene_corners[2] , Scalar(0, 0, 255), 2 );line( src_2, scene_corners[2] , scene_corners[3] , Scalar(0, 0, 255), 2 );line( src_2, scene_corners[3] , scene_corners[0] , Scalar(0, 0, 255), 2 );int nr=m_Fundamental.rows; // number of rows int nc=m_Fundamental.cols *m_Fundamental.channels(); // total number of elements per line // 計算野點個數(shù)int OutlinerCount = 0;for (int i=0; i<Count; i++){if (m_RANSACStatus[i] == 0) // 狀態(tài)為0表示野點{OutlinerCount++;}}// 計算內(nèi)點vector<Point2f> m_LeftInlier;vector<Point2f> m_RightInlier;vector<DMatch> m_InlierMatches;// 上面三個變量用于保存內(nèi)點和匹配關(guān)系int ptCount = (int)matches.size();int InlinerCount = ptCount - OutlinerCount;m_InlierMatches.resize(InlinerCount);m_LeftInlier.resize(InlinerCount);m_RightInlier.resize(InlinerCount);InlinerCount = 0;for (int i=0; i<ptCount; i++){if (m_RANSACStatus[i] != 0){m_LeftInlier[InlinerCount].x = p1.at<float>(i, 0);m_LeftInlier[InlinerCount].y = p1.at<float>(i, 1);m_RightInlier[InlinerCount].x = p2.at<float>(i, 0);m_RightInlier[InlinerCount].y = p2.at<float>(i, 1);m_InlierMatches[InlinerCount].queryIdx = InlinerCount;m_InlierMatches[InlinerCount].trainIdx = InlinerCount;InlinerCount++;}}// //printf("最終的匹配點個數(shù)為:%d\n",InlinerCount);把內(nèi)點轉(zhuǎn)換為drawMatches可以使用的格式vector<KeyPoint> key1(InlinerCount);vector<KeyPoint> key2(InlinerCount);KeyPoint::convert(m_LeftInlier, key1);KeyPoint::convert(m_RightInlier, key2);// 顯示計算F過后的內(nèi)點匹配//Mat m_matLeftImage;//Mat m_matRightImage;// 以上兩個變量保存的是左右兩幅圖像line(src_1,m1,m2,Scalar(0,255,0),2);line(src_1,m2,m3,Scalar(0,255,0),2);line(src_1,m3,m4,Scalar(0,255,0),2);line(src_1,m4,m1,Scalar(0,255,0),2);Mat OutImage;drawMatches(src_1, key1, src_2, key2, m_InlierMatches, OutImage); imshow("SIFT_RANSAC",OutImage); //imwrite("F:\\ylab\\CSDN_image\\5.jpg",OutImage);cvWaitKey( 0 );return 0; }

確定有窮自動機 2015年7月17日 ? 西安交通大學(xué)

總結(jié)

以上是生活随笔為你收集整理的利用SIFT和RANSAC算法(openCV框架)实现物体的检测与定位,并求出变换矩阵(findFundamentalMat和findHomography的比较)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。