2012-01-19 79 views
38

我在代表四邊形(不一定是正方形或矩形)的視頻(或圖像)中有4個共麪點,我希望能夠在虛擬立方體上顯示虛擬立方體其中頂部立方體的角落正好站在視頻四角的角落。由於點是共面的,我可以計算單位平方的角點(即[0,0] [0,1] [1,0] [1,1])和視頻座標之間的單應性四。基於4個共麪點的單應矩陣計算攝像機姿態

從這個單應性我應該能夠計算正確的相機姿態,即[R | t]其中R是3x3旋轉矩陣,t是3x1平移矢量,以便虛擬立方體位於視頻四邊形上。

我有(其中的一些SO)讀了很多的解決方案,並試圖實現他們,但他們似乎只能在一些「簡單」的情況下工作,但不會在大多數情況下(當視頻四是正方形等)。

這裏是我嘗試的方法(大多數是基於相同的原理,只有翻譯的計算略有不同)。設K是相機的固有矩陣,H是單應矩陣。我們計算:

A = K-1 * H 

令A1,A2,A3是A和R1,R2的列向量,R3旋轉矩陣R.

r1 = a1/||a1|| 
r2 = a2/||a2|| 
r3 = r1 x r2 
t = a3/sqrt(||a1||*||a2||) 

問題的列向量是這樣做在大多數情況下不起作用。爲了檢查我的結果,我將R和t與OpenCV的solvePnP方法(使用以下3D點[0,0,0] [0,1,0] [1,0,0] [1,1 ,0])。

由於我以同樣的方式顯示立方體,我注意到在每種情況下solvePnP都提供了正確的結果,而從單應性得到的姿勢大多是錯誤的。

從理論上講,因爲我的觀點是共面的,它可以計算從單應的姿勢,但我找不到計算姿勢從H.

什麼我做錯了任何見解的正確方法?試圖@ Jav_Rock的方法

Jav_Rock喜後

編輯,非常感謝您的回答,我想你的方法(和其他許多人)這似乎是或多或少確定。 不過,我在計算基於4個共麪點的姿勢時仍然碰到一些問題。爲了檢查結果,我將其與solvePnP的結果進行比較(由於迭代重投影誤差最小化方法,結果會更好)。

下面是一個例子:

cube

  • 黃色立方體:解決PNP
  • 黑色立方體:Jav_Rock的技術
  • 青色(紫色)立方體(S):其他一些技術給完全相同的結果

正如你所看到的,黑色立方體更多或雖然這些向量似乎是正常的,但還不算好,但看起來似乎不太合適。

編輯2:我計算後對其進行了歸一化(爲了強制正交),它似乎也解決了一些問題。

+2

所以OpenCV中的solvepnp提供正確的結果,而你的實現是錯誤的? – nav

+1

是的solvePnP給出了正確的結果,而我只使用單應性的實現不能給出正確的旋轉/平移向量。 – JimN

+1

如果你分享你的代碼,我們可以通過它,看看它是如何修復的。你可能忘記的一件事是強制旋轉矩陣的正交性。 – fireant

回答

25

如果您有單應,可以計算相機姿態像這樣的東西:

void cameraPoseFromHomography(const Mat& H, Mat& pose) 
{ 
    pose = Mat::eye(3, 4, CV_32FC1);  // 3x4 matrix, the camera pose 
    float norm1 = (float)norm(H.col(0)); 
    float norm2 = (float)norm(H.col(1)); 
    float tnorm = (norm1 + norm2)/2.0f; // Normalization value 

    Mat p1 = H.col(0);  // Pointer to first column of H 
    Mat p2 = pose.col(0); // Pointer to first column of pose (empty) 

    cv::normalize(p1, p2); // Normalize the rotation, and copies the column to pose 

    p1 = H.col(1);   // Pointer to second column of H 
    p2 = pose.col(1);  // Pointer to second column of pose (empty) 

    cv::normalize(p1, p2); // Normalize the rotation and copies the column to pose 

    p1 = pose.col(0); 
    p2 = pose.col(1); 

    Mat p3 = p1.cross(p2); // Computes the cross-product of p1 and p2 
    Mat c2 = pose.col(2); // Pointer to third column of pose 
    p3.copyTo(c2);  // Third column is the crossproduct of columns one and two 

    pose.col(3) = H.col(2)/tnorm; //vector t [R|t] is the last column of pose 
} 

這種方法的作品形成了我。祝你好運。

+1

你能評論代碼中發生了什麼? –

+7

嗨Jav_Rock,非常感謝您的回答,我嘗試了您的方法並編輯了帖子,以便您可以查看獲得的結果。再次感謝。 – JimN

+3

我認爲圖像不可見。無論如何,如果你想深入理論,你可以從dsp.stackexchange中閱讀這個問題 http://dsp.stackexchange.com/q/2736/1473 –

4

萬一有人需要通過@Jav_Rock編寫的功能蟒蛇移植:在我的任務

def cameraPoseFromHomography(H): 
    H1 = H[:, 0] 
    H2 = H[:, 1] 
    H3 = np.cross(H1, H2) 

    norm1 = np.linalg.norm(H1) 
    norm2 = np.linalg.norm(H2) 
    tnorm = (norm1 + norm2)/2.0; 

    T = H[:, 2]/tnorm 
    return np.mat([H1, H2, H3, T]) 

工作正常。

+0

這是如何工作沒有固有的攝像頭參數? – Mehdi

+0

@Mehdi我想假設單應性在標準化座標上工作:p'= K ^( - 1)[p; 1]。 –

-1

下面是一個python版本,基於Dmitriy Voloshyn提交的一個python版本,該版本將旋轉矩陣歸一化並將結果轉換爲3x4。

def cameraPoseFromHomography(H): 
    norm1 = np.linalg.norm(H[:, 0]) 
    norm2 = np.linalg.norm(H[:, 1]) 
    tnorm = (norm1 + norm2)/2.0; 

    H1 = H[:, 0]/norm1 
    H2 = H[:, 1]/norm2 
    H3 = np.cross(H1, H2) 
    T = H[:, 2]/tnorm 

    return np.array([H1, H2, H3, T]).transpose() 
5

計算單應矩陣的[R | T]比Jav_Rock的答案稍微複雜一些。

在OpenCV 3.0中,有一種稱爲cv :: decomposeHomographyMat的方法,它返回四個潛在的解決方案,其中一個是正確的。但是,OpenCV沒有提供一種方法來挑選出正確的。

我現在正在研究這個,也許會在本月晚些時候在這裏發佈我的代碼。

+3

你有沒有想過如何選擇正確的解決方案? –

7

Jav_Rock提出的答案不能爲三維空間中的攝像機姿態提供有效的解決方案。

爲了估計由單應性引起的樹維變換和旋轉,存在多種方法。 One of them提供了用於分解單應性的封閉公式,但它們非常複雜。而且,解決方案從來都不是唯一的。

幸運的是,OpenCV 3已經實現了這個分解(decomposeHomographyMat)。鑑於單應矩陣和正確縮放的內在矩陣,該函數提供了一組四種可能的旋轉和平移。

+0

從最後兩個可能的解決方案中挑選正確解決方案的計算非常複雜。您是否知道可以從最終的兩種解決方案中返回一種解決方案的論文的任何實現? –

0

在圖像上包含您的Square的平面消失車道代理您的相機。 這條線的方程是A x + B y + C = 0。

您的飛機正常情況是(A,B,C)!

設p00,p01,p10,p11爲應用攝像機固有參數後的點座標,並且是均勻形式e。克,P00 =(X00,y00,1)

消失線可以被計算爲:

  • 向下= P00 P01交叉;
  • left = p00 cross p10;
  • right = p01 cross p11;
  • up = p10 cross p11;
  • v1 =左十字右邊;
  • v2 =向上交叉向下;
  • vanish_line = v1 cross v2;

凡在標準的矢量叉積交叉