1. 程式人生 > >《視覺SLAM十四講精品總結》6.1:VO—— 2D-2D對極約束求位姿R、t

《視覺SLAM十四講精品總結》6.1:VO—— 2D-2D對極約束求位姿R、t

本節內容已在筆記本進行推導分為2D-2D、3D-2D、3D-3D。

三位場景中的同一個三維點在不同視角下的像點存在著一種約束關係:對極約束基礎矩陣E是這種約束關係的代數表示,並且這種約束關係獨立與場景的結構,只依賴與相機的內參K和外參R t(相對位姿)。

1、可以通過通過匹配的像點對計算出兩幅影象的基礎矩陣E,

2、然後分解基礎矩陣得到相機的相對位姿R t。

本節內容

對極約束

通過匹配點估算基礎矩陣F

OpenCV介面程式碼實現

總結

一、對極約束

1、對極幾何描述的是兩檢視之間的記憶體射影關係,同一個三維點在兩個不同的視角下的像點存在著約束關係,如下圖三維點XX在兩幅影象的像點分分別為x,x′(2D-2D)

已知:x和x'畫素座標,相機內參K

求解:X空間座標(XYZ)、外參R、t

2、單應矩陣H幾何意義

2D單應H指的是將射影平面上的點集xixi對映到另一個射影平面的點集x′ixi′上的射影變換

3、基礎矩陣F幾何意義

點到直線的對映      F=e^ H

4、核心公式推導:

二、通過匹配點對估算基礎矩陣F

基礎矩陣F 表示的是影象中的像點p1到另一幅影象對極線l2的對映,有如下公式: l2=F p1.

對極約束:畫素點p2必定在對極線l2上           

這樣僅通過匹配的點對p1 p2,就可以計算出兩檢視的基礎矩陣F。

1、8點法:基礎矩陣F是一個3×3的矩陣,有9個未知元素。然而,上面的公式中使用的齊次座標,齊次座標在相差一個常數因子下是相等,F也就只有8個未知元素,也就是說,只需要8對匹配的點對就可以求解出兩檢視的基礎矩陣F。

2、最小二乘法:

8點法中,只使用8對匹配的點對估計基礎矩陣,但通常兩幅影象的匹配的點對遠遠多於8對,可以利用更多匹配的點對來求解上面的方程。

基礎矩陣F的秩為2

三、OpenCV 介面

一、整體框架

#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;

//宣告函式
//兩張影象得到關鍵點(keypoints)和描述子之間匹配關係(matches)
void find_feature_matches(
	const Mat& img_1, const Mat& img_2,
	std::vector<KeyPoint>& keypoints_1,
	std::vector<KeyPoint>& keypoints_2,
	std::vector< DMatch >& matches);
//從特徵點(keypoints)和匹配關係(matches)求解位姿(R,t)
void pose_estimation_2d2d(
	std::vector<KeyPoint> keypoints_1,
	std::vector<KeyPoint> keypoints_2,
	std::vector< DMatch > matches,
	Mat& R, Mat& t);
// 畫素座標轉相機歸一化座標
Point2d pixel2cam(const Point2d& p, const Mat& K);

int main(int argc, char** argv)
{
	//1. 讀取影象
	Mat img_1 = imread("1.png");
	Mat img_2 = imread("2.png");
	//2. 得到關鍵點(keypoints)和描述子之間匹配關係(matches)
	vector<KeyPoint> keypoints_1, keypoints_2;
	vector<DMatch> matches;
	find_feature_matches(img_1, img_2, keypoints_1, keypoints_2, matches);
	cout << "一共找到了" << matches.size() << "組匹配點" << endl;
	//3. 估計兩張影象間運動R t
	Mat R, t;
	pose_estimation_2d2d(keypoints_1, keypoints_2, matches, R, t);
	//4. 驗證E=t^R*scale,t^是t的反對稱矩陣
	Mat t_x = (Mat_<double>(3, 3) <<
		0, -t.at<double>(2, 0), t.at<double>(1, 0),
		t.at<double>(2, 0), 0, -t.at<double>(0, 0),
		-t.at<double>(1.0), t.at<double>(0, 0), 0);
	cout << "t^R=" << endl << t_x*R << endl;
	//5. 驗證對極約束
	Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);
	for (DMatch m : matches)
	{
		Point2d pt1 = pixel2cam(keypoints_1[m.queryIdx].pt, K);
		Mat y1 = (Mat_<double>(3, 1) << pt1.x, pt1.y, 1);
		Point2d pt2 = pixel2cam(keypoints_2[m.trainIdx].pt, K);
		Mat y2 = (Mat_<double>(3, 1) << pt2.x, pt2.y, 1);
		Mat d = y2.t() * t_x * R * y1;
		cout << "epipolar constraint = " << d << endl;
	}
	return 0;
}
  •  通過對極約束對求得的R t進行驗證  
  • x2 和 x1是歸一化座標(畫素座標系p到相機座標系x)   
  • Point2d pixel2cam(const Point2d& p, const Mat& K)
    {
    	return Point2d
    		(
    		(p.x - K.at<double>(0, 2)) / K.at<double>(0, 0),
    		(p.y - K.at<double>(1, 2)) / K.at<double>(1, 1)
    		);
    }
  • 使用齊次座標,3*1 ,最後一個是1。
  • keypoints使用vector<KeyPoint> 型別; matches使用vector<DMatch> ; Mat& R; Mat& t;

二、兩張影象得到關鍵點(keypoints)和描述子之間匹配關係(matches)

上一節知識點。

三、從特徵點(keypoints)和匹配關係(matches)求解位姿(R,t)

void pose_estimation_2d2d(std::vector<KeyPoint> keypoints_1,
	std::vector<KeyPoint> keypoints_2,
	std::vector< DMatch > matches,
	Mat& R, Mat& t)
{
	// 相機內參K
	Mat K = (Mat_<double>(3, 3) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1);

	//-- 對齊匹配的點對,並用.pt轉化為畫素座標。把匹配點轉換為簡單的Point2f形式,
	vector<Point2f> points1;
	vector<Point2f> points2;
	for (int i = 0; i < (int)matches.size(); i++)
	{
		points1.push_back(keypoints_1[matches[i].queryIdx].pt);//queryIdx第一個影象索引
		points2.push_back(keypoints_2[matches[i].trainIdx].pt);//trainIdx第二個影象索引
	}

	//-- 計算基礎矩陣F
	Mat fundamental_matrix;
	fundamental_matrix = findFundamentalMat(points1, points2, CV_FM_8POINT);
	cout << "fundamental_matrix is " << endl << fundamental_matrix << endl;

	//-- 計算本質矩陣E
	Point2d principal_point(325.1, 249.7);	//相機光心
	double focal_length = 521;			//相機焦距

	Mat essential_matrix;
	essential_matrix = findEssentialMat(points1, points2, focal_length, principal_point);
	cout << "essential_matrix is " << endl << essential_matrix << endl;

	//-- 計算單應矩陣H
	Mat homography_matrix;
	homography_matrix = findHomography(points1, points2, RANSAC, 3);
	cout << "homography_matrix is " << endl << homography_matrix << endl;

	//-- 從本質矩陣E中恢復旋轉和平移資訊.
	recoverPose(essential_matrix, points1, points2, R, t, focal_length, principal_point);
	cout << "R is " << endl << R << endl;
	cout << "t is " << endl << t << endl;

}

1、findFundamentalMat函式(計算基礎矩陣F)

Mat cv::findFundamentalMat(points1,points2,method = FM_RANSAC,
double ransacReprojThreshold = 3.,double confidence = 0.99, OutputArray mask = noArray() )

points1,points2 是匹配點對的畫素座標,並且能夠一一對應

method 使用那種方法,預設的是FM_RANSAC也就是RANSAC的方法估算基礎矩陣。CV_FM_8POINT是8點法。

ransacReprojThreshold表示RANSAC迭代過程中,判斷點是內點還是外點的閾值(到對極線的畫素距離);

confidence表示內點佔的比例,以此來判斷估計出的基礎矩陣是否正確。

2、findEssentialMat函式(計算本質矩陣E)

Mat cv::findEssentialMat(points1,points2,cameraMatrix,method = RANSAC,
double prob = 0.999,double threshold = 1.0,OutputArray mask = noArray() )	

 cameraMatrix        

Mat K=(Mat_<double> (3,3)<<520.9,0,325.1,0,521.0,249.7,0,0,1);

prob 本質矩陣E正確的概率

threshold  RANSAC閾值

3、findHomography函式(計算單應矩陣H)

Mat cv::findHomography	(Points1,Points2,method = RANSAC,
double 	ransacReprojThreshold = 3,OutputArray mask = noArray(),
const int 	maxIters = 2000, const double 	confidence = 0.995 )	

 maxIter 最大迭代次數

4、computeCorrespondEpilines函式(計算對極線)

void cv::computeCorrespondEpilines(points,int whichImage,F,OutputArray lines )
points Input points. N×1 or 1×N matrix of type CV_32FC2 or vector<Point2f> .
whichImage 影象索引Index of the image (1 or 2) that contains the points .
F 基礎矩陣Fundamental matrix that can be estimated using findFundamentalMat or stereoRectify .
lines 對極線Output vector of the epipolar lines corresponding to the points in the other image. 

5、recoverPose函式(從 E 中恢復R和t)

int cv::recoverPose	(E,points1,points2,cameraMatrix,R,t,mask = noArray() )	
int cv::recoverPose	(E,points1,points2,R,t,double focal = 1.0,Point2d pp = Point2d(0, 0),
mask = noArray() )	

focal: 相機焦距

pp :相機光心

四、總結

1、主要用E分解運動,H需要假設特徵點在平面上。

2、E本身具有尺度等價性,通常對t進行歸一化,令它的長度為1。

  • 尺度不確定性

對t的歸一化 相當於固定了尺度,導致單目視覺的尺度不確定性,釐米還是米

把特徵點深度歸一化可以控制場景規模大小,樹枝上更穩定些。

 純旋轉導致t 為0,E也是0 ,無法求解R。單目初始化不能只有純旋轉,必須要有一定平移。

  • 初始化的純旋轉
  • 多餘8點的情況

傾向於用RANSAC

相關推薦

視覺SLAM精品總結6.1VO—— 2D-2D約束姿Rt

本節內容已在筆記本進行推導分為2D-2D、3D-2D、3D-3D。 三位場景中的同一個三維點在不同視角下的像點存在著一種約束關係:對極約束,基礎矩陣E是這種約束關係的代數表示,並且這種約束關係獨立與場景的結構,只依賴與相機的內參K和外參R t(相對位姿)。 1、可以通過通

視覺SLAM精品總結》12 迴環檢測建立字典

  這部分並不難,主要用到了一個詞袋模型(BoW),對兩幅影象的特徵點進行匹配。 建立字典:一個單詞是某一類特徵的集合,字典生成是個聚類問題,可使用K-meams演算法。 匹配相似性:暴力計算量太大,可用二分查詢提升效率,以及k叉樹表達字典(層次聚類) 目錄:

視覺SLAM精品總結》9:直接法和光流法

內容: 二者關係 光流法 直接法 一、二者關係 引出原因:關鍵點和描述子計算非常耗時,可以保留特徵點,使用光流法跟蹤特徵點運動。 關係:光流法描述畫素在影象中運動,直接法利用相機運動模型計算特徵點在下一時刻影象中位置。 使用條件:直接法利用影象的畫素灰度資訊計算

視覺SLAM精品總結》10.3: 新增g2o優化姿T

0.3版本的VO就是在0.2的基礎上增加了g2o優化:  1、在visual_odometry.cpp中的poseEstimationPNP()函式中,用PNP求出T_c_r_estimated_後,增加了g2o優化,對位姿進行優化。  2、同時增加的還有g2o相關的標頭檔案

SLAM學習基礎(二)——《視覺SLAM》讀後感SLAM核心技術總結(部分)

(1)《視覺SLAM十四講》_高翔 第一遍學習: 《視覺SLAM十四講》這本書,很詳細的從幾何學的角度講述了SLAM的各種核心技術。是成為一名SLAM技術的邊緣OB者的不二選擇。 本書的前六講主要是在安裝庫(當然,順道介紹書數學基礎知識),SLAM執行需要的各種庫,因為我是在ub

視覺slamch5 joinMap.cpp 代碼註釋(筆記版)

iterator 實驗 article ons 如果 false 結果 插入 智能指針類 1 #include <iostream> 2 #include <fstream> 3 using namespace std; 4 #in

視覺SLAM》課後習題—ch7(更新中……)

一個 main slam 為什麽 技術分享 .com span point fde 參考:https://blog.csdn.net/zilanpotou182/article/details/66478915(SIFT、SURF、ORB三種特征點的區別) 1.除了本書

視覺SLAM》筆記(ch10)

bundle gin ont 學習 重建 16px 方程 進行 img ch 10—— 後端1 主要目標:1.理解後端的概念      2.理解以EFK為代表的濾波器後端工作原理      3.理解非線性優化得後端,明白稀疏性是如何利用的      4.使用g2

視覺SLAM(二)——SLAM 學習資料

(1) orb_slam 官網(網站最後有5篇論文,價值很高) http://webdiis.unizar.es/~raulmur/orbslam/ (2)半仙居士blog(可以都看,很經典) http://www.cnblogs.com/gaoxiang12/ (3) 賀一加 blog(m

視覺SLAM學習筆記——第二

2.1引子:小蘿蔔的例子   1. 慣性測量單元(Inertial Measurement Unit, IMU)   2. 按照工作方式的不同,相機可以分為單目相機(Monocular)、雙目相機(Stereo)、和深度相機(RGB-D)三大類。   3. RGB-D除了能夠採集到彩色圖片之外,還能夠讀

視覺SLAM學習筆記——第三講--三維空間剛體運動

3.1 旋轉矩陣   3.1.1 點和向量,座標系   內積可以描述向量之間的投影關係。   外積的方向垂直於這兩個向量,是兩個向量張成的四邊形的有向面積。還能用外積表示向量的旋轉。   3.1.2 座標系間的歐式變換   旋轉矩陣是行列式為1的正交矩陣。旋轉矩陣可以描述相機的旋轉。SO(n)是特殊

視覺SLAM學習筆記——第--李群與李代數

4.1李群與李代數基礎   旋轉矩陣和變換矩陣對加法是不封閉的。換句話說,對於任意兩個旋轉矩陣R1, R2,按照矩陣加法的定義,和不再是一個旋轉矩陣。   SO(3) 和 SE(3)對乘法是封閉的。兩個旋轉矩陣相乘,表示做了兩次旋轉。對於這種只有一個運算的集合,我們稱之為群。   4.1.1 群   

視覺SLAM學習筆記——第五講--相機與影象

5.1 相機模型   5.1.1 針孔相機模型   畫素座標系與成像平面之間,相差了一個縮放和一個原點的平移。   內參數矩陣(Camera Intrinsics)K   標定:自己確定內參。   5.1.2 畸變   由透鏡形狀引起的畸變稱為徑向畸變。   桶形畸變是由於影象放大率隨著與光軸之

視覺SLAM學習筆記——第六--非線性優化

6.1 狀態估計問題   6.1.1 最大後驗與最大似然   貝葉斯法則   似然是指"在現在的位姿下,可能產生怎樣的觀測資料"。   最大似然估計“在什麼樣的狀態下,最可能產生現在觀測到的資料”。   6.1.2 最小二乘的引出 6.2 非線性最小二乘   6.2.1 一階和二階梯度法   

視覺slam》之第3-三維剛體運動

  第三講:三維空間剛體運動 旋轉的幾種表達方式 向量 關於向量: 注:其中e1,e2,e3為線性空間下的一組基。 向量的內積: 注:向量的內積表示向量間的投影關係。 向量的外積 注:可以使用外積表示向量的旋轉。 注:^ 記成一個反對稱符

視覺SLAM(三)——A星演算法詳解

點開全文 點開全文 點開全文 A* 尋路演算法 原文地址: http://www.gamedev.net/reference/articles/art

SLAM學習小組 : 視覺SLAM 第三講 + 視覺SLAM理論與實踐 第二節

一、熟悉Eigen矩陣運算 Wiki Eigen 設線性⽅程 Ax = b,在 A 為⽅陣的前提下,請回答以下問題: 1. 在什麼條件下,x 有解且唯⼀? 線性方程組的矩陣滿秩(非奇異矩陣) 2. 高斯消元法的原理是什麼? 高斯消元法是將方程組中的一方程的未知數用含有另一

視覺SLAM》課後習題—ch6

7.請更改曲線擬合實驗中的曲線模型,並用Ceres和g2o進行優化實驗。例如,可以使用更多的引數和更復雜的模型   Ceres:以使用更多的引數為例:y-exp(ax^3+bx^2+cx+d)   僅僅是在程式中將模型引數增加到4維,沒什麼創新而言    1 #include <iost

視覺SLAM講課後習題—ch8 《視覺SLAM》筆記(ch8)

1.除了LK光流之外,還有哪些光流方法?它們各有什麼特點?   參考:https://blog.csdn.net/on2way/article/details/48953975 1)LK(Lucas-Kanada)光流: 一種經典的方法,基於區域性特徵計算光流2)Horn-Schunck光流方法:全域性性

SLAM學習--視覺SLAM第三方庫安裝

echo "安裝eigen3" sudo apt-get --yes --force-yes install libeigen3-dev cd ~/ThirtyLib echo "安裝Sopus" g