iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
0
自我挑戰組

我的影像視覺定位學習筆記系列 第 13

day13-epipolar geometry對極幾何

  • 分享至 

  • xImage
  •  


當我有一個觀察物體,同時出現在兩幅影像上,
這個觀測物體分別在影像中被偵測出來的特徵點的有特殊的對應關係,
而這個特殊的對應關係能夠被描述為一連串的代數等式,
還記得我們day3-pinhole camera model 針孔成像原理
我們將從一個相機擴展為兩個相機,或者你說一個相機在兩個不同的位子,都是同樣的道理。
而這個對應關係以目前的不知道相機內參數矩陣的情況,
我們只能得知相機的基礎矩陣,

物點與兩個相機中心能形成一個平面(epipolar plan),
而這個平面與相機成像平面會形成一個線(epipolar line)

其詳細的公式推論,我建議可以參考以下資源,
淺談基礎矩陣、本質矩陣與相機移動 Beginner’s Guide to Fundamental Matrix, Essential Matrix and Camera Motion Recovery

而讓我們回到openCV要怎麼利用昨天的特徵點對應關係來求解兩個相機之間的基礎矩陣呢?
openCV封裝的方法如下
https://ithelp.ithome.com.tw/upload/images/20190929/20121127UPd14s2oe0.png
其中第2~4參數是有關於RANSAC過濾內群與外群的演算法設定,這邊暫時不管。
而我們需要給這個方法的輸入值是兩組對應的poind2d(根據解法點數應該要大於8個點,四組匹配)

std::vector<cv::Point2d> good_point_img1, good_point_img2;
good_point_img1.reserve(good_matches.size());
good_point_img2.reserve(good_matches.size());

for ( auto i = good_matches.begin(); i != good_matches.end(); i++)
{
	good_point_img1.emplace_back(cv::Point(SURFkeypoints_ofbox.at(i->queryIdx).pt.x, SURFkeypoints_ofbox.at(i->queryIdx).pt.y));
    
	good_point_img2.emplace_back(cv::Point(SURFkeypoints_ofscene.at(i->trainIdx).pt.x, SURFkeypoints_ofscene.at(i->trainIdx).pt.y));
}

先讓我準備兩個vector容器用以存放兩張影像的特徵點位置資訊,其順序就是對應的匹配關係
然後分別將昨天經過ratio_test過濾過的匹配,查詢當初偵測出來的特徵點的(x,y)座標,
將其塞入容器內。

cv::Mat Fundamental,mask_ofF;
Fundamental = cv::findFundamentalMat(good_point_img1, good_point_img2, mask_ofF);

最後我需要一個mat,來存放這個方法的回傳值結果(3X3基礎矩陣),
而這裡的mask是用來儲存 RANSAC過濾後的結果,
我可以透過drawMatches來觀測過濾後的匹配關係

cv::Mat img_Match_F;

cv::drawMatches(image01, SURFkeypoints_ofbox, image02, SURFkeypoints_ofscene, good_matches, img_Match_F, cv::Scalar::all(-1), cv::Scalar::all(-1), mask_ofF, cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

cv::imshow("img_Match_F", img_Match_F);

Fundamental
https://ithelp.ithome.com.tw/upload/images/20190929/20121127xDyzGPFis9.png
retio test
https://ithelp.ithome.com.tw/upload/images/20190929/20121127IbLNGoAI9u.png
兩個影像可能很相似肉眼難以看出差別,我們只好透過計算匹配的數量才能比較清楚知道過濾的結果,

std::cout << "Fundamental" << Fundamental << std::endl;
std::cout << "mask_ofF" << mask_ofF.size() << std::endl;
std::cout << "good_matches.size()" << good_matches.size() << std::endl;
std::cout << "countNonZero" << cv::countNonZero(mask_ofF) << std::endl;

https://ithelp.ithome.com.tw/upload/images/20190929/20121127LPyjzyrJqe.png
我們先來看 mask的size應該要跟 good_matches的size一致
而最後我們來看mask裡面有幾組匹配是被RANSAC過濾的,
而這裡opencv有提供一種方法來計算矩陣內的內容有幾個不為0,
透過計算不為零的個數我就能知道有幾組匹配是被RANSAC判斷為內群點。
你也可以使用這個方法來計算黑白影像中,白色的影像與黑色的影像格的個數。

最後簡單總結一下,基礎矩陣代表的是對極幾何的約束,當我左邊偵測出一個特徵點的同時
乘上這個基礎矩陣會出現一條直線方乘,代表的意義是如果右邊的影像中也有這個特徵點,
那麼他一定會在這條直線上面。

之後的內容會講道RANSAC的運作機制。


上一篇
day12-匹配過濾 cross_check &kNN with ratio_test
下一篇
day14-RANSAC在求解Fundamental的應用
系列文
我的影像視覺定位學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言