三角測(cè)量

本文緊接著前一篇文章《2D-2D相機(jī)位姿估計(jì)》展開杰扫。在得到了兩張圖片對(duì)應(yīng)的相機(jī)位姿之后刀诬,就可以通過三角測(cè)量的方法計(jì)算出配對(duì)特征點(diǎn)的3D位置究抓。

一蜘欲、三角測(cè)量原理

想必三角測(cè)量這個(gè)詞大家并不陌生益眉,因?yàn)榈乩碚n上我們就學(xué)過它的原理。在兩個(gè)不同地方觀測(cè)同一個(gè)點(diǎn)姥份,只要知道兩個(gè)觀測(cè)地點(diǎn)的距離和觀測(cè)角度郭脂,就可以確定觀測(cè)點(diǎn)到兩地的距離。這是因?yàn)橐粭l邊和兩個(gè)內(nèi)角可以完全確定一個(gè)三角形澈歉,僅此而已展鸡。

如下圖所示,已知O1和O2點(diǎn)的坐標(biāo)埃难、O1P的方向和O2P的方向莹弊,就可以唯一確定P點(diǎn)的位置。但是在SLAM中凯砍,問題稍微復(fù)雜一些箱硕。由于噪聲的影響,O1P和O2P有可能根本沒有交點(diǎn)悟衩,這個(gè)時(shí)候就只能用最小二乘法求取使誤差最小的P點(diǎn)的坐標(biāo)了剧罩。

另外,O1和O2之間的距離對(duì)三角測(cè)量的誤差影響很大座泳。距離太短惠昔,也就是說相機(jī)的平移太小時(shí),對(duì)P點(diǎn)觀測(cè)的角度誤差會(huì)導(dǎo)致較大的深度誤差挑势。而距離太遠(yuǎn)镇防,場(chǎng)景的重疊部分會(huì)少很多,使特征匹配變得困難潮饱。因此相機(jī)的平移需要把握一個(gè)度来氧,既不能太大也不能太小,這是三角測(cè)量的一對(duì)矛盾。

無論怎樣啦扬,OpenCV都提供了非常方便的函數(shù)供我們調(diào)用中狂。只需要調(diào)用cv::triangulatePoints就可以實(shí)現(xiàn)特征點(diǎn)的三角化。

二扑毡、代碼實(shí)現(xiàn)

下面給出關(guān)鍵部分代碼胃榕,包括三角化函數(shù)和主函數(shù)。

void triangulation ( 
    const vector< KeyPoint >& keypoint_1, 
    const vector< KeyPoint >& keypoint_2, 
    const std::vector< DMatch >& matches,
    const Mat& R, const Mat& t, 
    vector< Point3d >& points )
{
    Mat T1 = (Mat_<float> (3,4) <<
        1,0,0,0,
        0,1,0,0,
        0,0,1,0);
    Mat T2 = (Mat_<float> (3,4) <<
        R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), t.at<double>(0,0),
        R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), t.at<double>(1,0),
        R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), t.at<double>(2,0)
    );
    
    Mat K = ( Mat_<double> ( 3,3 ) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1 );
    vector<Point2f> pts_1, pts_2;
    for ( DMatch m:matches )
    {
        // 將像素坐標(biāo)轉(zhuǎn)換至相機(jī)坐標(biāo)
        pts_1.push_back ( pixel2cam( keypoint_1[m.queryIdx].pt, K) );
        pts_2.push_back ( pixel2cam( keypoint_2[m.trainIdx].pt, K) );
    }
    
    Mat pts_4d;
    cv::triangulatePoints( T1, T2, pts_1, pts_2, pts_4d );
    
    // 轉(zhuǎn)換成非齊次坐標(biāo)
    for ( int i=0; i<pts_4d.cols; i++ )
    {
        Mat x = pts_4d.col(i);
        x /= x.at<float>(3,0); // 歸一化   //金戈大王注:此處的歸一化是指從齊次坐標(biāo)變換到非齊次坐標(biāo)瞄摊。而不是變換到歸一化平面勋又。
        Point3d p (
            x.at<float>(0,0), 
            x.at<float>(1,0), 
            x.at<float>(2,0) 
        );
        points.push_back( p );
    }
}

int main ( int argc, char** argv )
{
    if ( argc != 3 )
    {
        cout<<"usage: triangulation img1 img2"<<endl;
        return 1;
    }
    //-- 讀取圖像
    Mat img_1 = imread ( argv[1], CV_LOAD_IMAGE_COLOR );
    Mat img_2 = imread ( argv[2], CV_LOAD_IMAGE_COLOR );

    vector<KeyPoint> keypoints_1, keypoints_2;
    vector<DMatch> matches;
    find_feature_matches ( img_1, img_2, keypoints_1, keypoints_2, matches );
    cout<<"一共找到了"<<matches.size() <<"組匹配點(diǎn)"<<endl;

    //-- 估計(jì)兩張圖像間運(yùn)動(dòng)
    Mat R,t;
    pose_estimation_2d2d ( keypoints_1, keypoints_2, matches, R, t );

    //-- 三角化
    vector<Point3d> points;
    triangulation( keypoints_1, keypoints_2, matches, R, t, points );
    
    //-- 驗(yàn)證三角化點(diǎn)與特征點(diǎn)的重投影關(guān)系
    Mat K = ( Mat_<double> ( 3,3 ) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1 );
    for ( int i=0; i<matches.size(); i++ )
    {
        Point2d pt1_cam = pixel2cam( keypoints_1[ matches[i].queryIdx ].pt, K );
        Point2d pt1_cam_3d(
            points[i].x/points[i].z, 
            points[i].y/points[i].z 
        );
        
        cout<<"point in the first camera frame: "<<pt1_cam<<endl;
        cout<<"point projected from 3D "<<pt1_cam_3d<<", d="<<points[i].z<<endl;
        
        // 第二個(gè)圖
        Point2f pt2_cam = pixel2cam( keypoints_2[ matches[i].trainIdx ].pt, K );
        Mat pt2_trans = R*( Mat_<double>(3,1) << points[i].x, points[i].y, points[i].z ) + t;
        pt2_trans /= pt2_trans.at<double>(2,0);
        cout<<"point in the second camera frame: "<<pt2_cam<<endl;
        cout<<"point reprojected from second frame: "<<pt2_trans.t()<<endl;
        cout<<endl;
    }
    
    return 0;
}

//其它函數(shù)略

其中,cv::triangulatePoints函數(shù)接受的參數(shù)是兩個(gè)相機(jī)位姿和特征點(diǎn)在兩個(gè)相機(jī)坐標(biāo)系下的坐標(biāo)换帜,輸出三角化后的特征點(diǎn)的3D坐標(biāo)楔壤。但需要注意的是,輸出的3D坐標(biāo)是齊次坐標(biāo)膜赃,共四個(gè)維度挺邀,因此需要將前三個(gè)維度除以第四個(gè)維度以得到非齊次坐標(biāo)xyz。這個(gè)坐標(biāo)是在相機(jī)坐標(biāo)系下的坐標(biāo)跳座,以輸入的兩個(gè)相機(jī)位姿所在的坐標(biāo)系為準(zhǔn)端铛。

在主函數(shù)中,通過把3D坐標(biāo)重投影到兩個(gè)相機(jī)的歸一化平面上疲眷,從而計(jì)算重投影誤差禾蚕。因此需要再次對(duì)xyz坐標(biāo)同時(shí)除以z,以得到歸一化平面上的坐標(biāo)狂丝。

以下是一部分三角化結(jié)果换淆,可以看到誤差很小,大約在小數(shù)點(diǎn)后第3位的量級(jí)几颜。d的值是特征點(diǎn)到第一個(gè)相機(jī)光心O1的距離倍试,但這個(gè)距離沒有單位,只能表示相對(duì)大小蛋哭。

...

point in the first camera frame: [-0.153772, -0.0742802]
point projected from 3D [-0.153832, -0.0754351], d=16.6993
point in the second camera frame: [-0.180649, -0.0589251]
point reprojected from second frame: [-0.1806478467687954, -0.05780866898967527, 1]

point in the first camera frame: [-0.468612, 0.119578]
point projected from 3D [-0.468523, 0.118851], d=14.046
point in the second camera frame: [-0.499328, 0.1119]
point reprojected from second frame: [-0.4994513059407403, 0.1125883903930561, 1]

...

完整代碼的下載地址:https://github.com/jingedawang/FeatureMethod

三县习、參考資料

《視覺SLAM十四講》第7講 視覺里程計(jì)1 高翔

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谆趾,隨后出現(xiàn)的幾起案子躁愿,更是在濱河造成了極大的恐慌,老刑警劉巖沪蓬,帶你破解...
    沈念sama閱讀 218,941評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件彤钟,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡跷叉,警方通過查閱死者的電腦和手機(jī)逸雹,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,397評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門营搅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人峡眶,你說我怎么就攤上這事剧防。” “怎么了辫樱?”我有些...
    開封第一講書人閱讀 165,345評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)俊庇。 經(jīng)常有香客問我狮暑,道長(zhǎng),這世上最難降的妖魔是什么辉饱? 我笑而不...
    開封第一講書人閱讀 58,851評(píng)論 1 295
  • 正文 為了忘掉前任搬男,我火速辦了婚禮,結(jié)果婚禮上彭沼,老公的妹妹穿的比我還像新娘缔逛。我一直安慰自己,他們只是感情好姓惑,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,868評(píng)論 6 392
  • 文/花漫 我一把揭開白布褐奴。 她就那樣靜靜地躺著,像睡著了一般于毙。 火紅的嫁衣襯著肌膚如雪敦冬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,688評(píng)論 1 305
  • 那天唯沮,我揣著相機(jī)與錄音脖旱,去河邊找鬼。 笑死介蛉,一個(gè)胖子當(dāng)著我的面吹牛萌庆,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播币旧,決...
    沈念sama閱讀 40,414評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼践险,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了佳恬?” 一聲冷哼從身側(cè)響起捏境,我...
    開封第一講書人閱讀 39,319評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎毁葱,沒想到半個(gè)月后垫言,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,775評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倾剿,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,945評(píng)論 3 336
  • 正文 我和宋清朗相戀三年筷频,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了蚌成。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,096評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡凛捏,死狀恐怖担忧,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 35,789評(píng)論 5 346
  • 正文 年R本政府宣布涧团,位于F島的核電站捕犬,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,437評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轧房。 院中可真熱鬧,春花似錦绍绘、人聲如沸奶镶。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,993評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽厂镇。三九已至,卻和暖如春藻丢,著一層夾襖步出監(jiān)牢的瞬間剪撬,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,107評(píng)論 1 271
  • 我被黑心中介騙來泰國(guó)打工悠反, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留残黑,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,308評(píng)論 3 372
  • 正文 我出身青樓斋否,卻偏偏與公主長(zhǎng)得像梨水,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子茵臭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,037評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 高級(jí)鉗工應(yīng)知鑒定題庫(858題) ***單選題*** 1. 000003難易程度:較難知識(shí)范圍:相關(guān)4 01答案:...
    開源時(shí)代閱讀 5,781評(píng)論 1 9
  • 第十五章 隧道與橋梁測(cè)量 1.隧道測(cè)量概述 隧道自兩端洞口相對(duì)開挖疫诽,在洞內(nèi)預(yù)定位置挖通,稱為貫通旦委,因?yàn)槠嫱剑淼罍y(cè)量也...
    1915萬憑麓閱讀 1,541評(píng)論 0 3
  • 世間世事 誰能料 苦短人生 難磨多 孤行不如八十難 沒有圣僧 菩薩心
    李子柚閱讀 283評(píng)論 0 0
  • 1. 孤獨(dú)這兩個(gè)字拆開來看摩钙,有孩童,有瓜果查辩,有走獸胖笛,有飛蟲网持,足以撐起一個(gè)盛夏的傍晚,人情味兒十足长踊」σǎ“稚兒擎瓜柳鵬下...
    尚夏sunny閱讀 374評(píng)論 9 8
  • 早上培訓(xùn)的時(shí)間太多,不夠休息身弊,每天都累辟汰。 今晚回家吃飯了。和家人一起阱佛,加上公眾號(hào)里面理念莉擒。累s了 最近做單比較少,...
    DeathKnightR閱讀 305評(píng)論 0 0