7

我正在嘗試使用我的攝像頭從已知全局位置的四個基準圖像獲取全局姿態估計值。攝像機姿態估計(OpenCV PnP)

我檢查了很多stackexchange問​​題和一些論文,我似乎無法得到一個正確的解決方案。我確實得到的位置編號是可重複的,但與攝像機的運動絲毫不成比例。僅供參考我正在使用C++ OpenCV 2.1。

At this link is pictured我的座標系和下面使用的測試數據。

% Input to solvePnP(): 
imagePoints =  [ 481, 831; % [x, y] format 
        520, 504; 
        1114, 828; 
        1106, 507] 
objectPoints = [0.11, 1.15, 0; % [x, y, z] format 
       0.11, 1.37, 0; 
       0.40, 1.15, 0; 
       0.40, 1.37, 0] 

% camera intrinsics for Logitech C910 
cameraMat = [1913.71011, 0.00000, 1311.03556; 
      0.00000, 1909.60756, 953.81594; 
      0.00000, 0.00000, 1.00000] 
distCoeffs = [0, 0, 0, 0, 0] 

% output of solvePnP(): 
tVec = [-0.3515; 
     0.8928; 
     0.1997] 

rVec = [2.5279; 
     -0.09793; 
     0.2050] 
% using Rodrigues to convert back to rotation matrix: 

rMat = [0.9853, -0.1159, 0.1248; 
     -0.0242, -0.8206, -0.5708; 
     0.1686, 0.5594, -0.8114] 

到目前爲止,任何人都可以看到什麼毛病這些數字?如果有人會檢查他們,例如MatLAB(上面的代碼是m文件友好的),我將不勝感激。

從這一點,我不確定如何從rMat和tVec獲得全局姿態。 從我讀this question,擺脫RMAT和tVec姿勢很簡單:

position = transpose(rMat) * tVec % matrix multiplication 

不過,我從我讀過它不是簡單其它來源的懷疑。

要獲得相機在真實世界座標系中的位置,我需要做什麼? 由於我不確定這是否是一個實現問題(但最有可能是一個理論問題),我希望有人在OpenCV中成功使用solvePnP函數來回答這個問題,儘管也歡迎任何想法!

非常感謝您的時間。

+0

。所以正確的做法是 - 傳輸(rMat)* tVec – Vlad 2014-04-23 02:19:58

回答

4

我前一段時間解決了這個問題,對延誤一年表示歉意。

在Python 2.1的OpenCV我所用,而新版本3.0.0-dev的,我已經驗證,讓相機的姿態在全球框架必須:

_, rVec, tVec = cv2.solvePnP(objectPoints, imagePoints, cameraMatrix, distCoeffs) 
Rt = cv2.Rodrigues(rvec) 
R = Rt.transpose() 
pos = -R * tVec 

現在正是相機在全局幀中表示的位置(表示objectPoints的相同幀)。 R是姿態矩陣DCM,它是存儲姿態的好形式。 如果您需要歐拉角,那麼你可以轉換DCM歐拉角度給出使用XYZ的輪轉順序:你忘了逆tVec

roll = atan2(-R[2][1], R[2][2]) 
pitch = asin(R[2][0]) 
yaw = atan2(-R[1][0], R[0][0]) 
+0

OpenCV沒有X-Y-Z座標系。如何使用opencv轉換爲歐拉角? – 2015-03-13 14:20:33

+1

@tokam你的意思是'它沒有X-Y-Z座標系'? OpenCV 3.0中有'RQdecomp3x3'函數。我發現它給了我與在互聯網上有時找到的轉換相同的結果(例如http://nghiaho.com/?page_id=846): 'theta_x = atan2(R.at (2,1), R.at (2,2)); theta_y = atan2(-R.at (2,0),sqrt(pow(R.at (2,1),2)+ pow(R.at (2,2),2))); theta_z = atan2(R.at (1,0),R.at (0,0));' – oarfish 2015-05-08 15:06:06

+0

請注意,opencv的座標系與飛機和其他區域的標準座標系不同。 – 2015-05-19 07:56:34

2

相機的位置是{ - 轉置(r)* t}。而已。

除了cv :: solvePnp給出了(4 x 1)的轉換向量,如果我沒有記錯的話,你必須用w座標來分割x,y,z。

+0

Avanindra,謝謝你的回覆。 solvePnP從來沒有爲我返回一個4x1向量,我相信從我在源代碼中看到它以規則(非規範化)形式返回。 難道是我用於相機內在函數的值不正確(我曾建議嘗試否定某些元素),或者我的幀被錯誤定義? 謝謝。 – Gouda 2013-05-02 05:27:41

+0

我同意,但一些奇怪的原因-T * R.t()是使它的工作。 – Vlad 2014-04-23 02:08:48

4

如果你的意思全球姿態一個4x4相機姿態矩陣,可在OpenGL中使用,我做這種方式

CvMat* ToOpenGLCos(const CvMat* tVec, const CvMat* rVec) 
{ 
    //** flip COS 180 degree around x-axis **// 

    // Rodrigues to rotation matrix 
    CvMat* extRotAsMatrix = cvCreateMat(3,3,CV_32FC1); 
    cvRodrigues2(rVec,extRotAsMatrix); 

    // Simply merge rotation matrix and translation vector to 4x4 matrix 
    CvMat* world2CameraTransformation = CreateTransformationMatrixH(tVec, 
    extRotAsMatrix); 

    // Create correction rotation matrix (180 deg x-axis) 
    CvMat* correctionMatrix = cvCreateMat(4,4,CV_32FC1); 
    /* 1.00000 0.00000 0.00000 0.00000 
     0.00000 -1.00000 -0.00000 0.00000 
     0.00000 0.00000 -1.00000 0.00000 
     0.00000 0.00000 0.00000 1.00000 */ 
    cvmSet(correctionMatrix,0,0,1.0); cvmSet(correctionMatrix,0,1,0.0); 
    ... 

    // Flip it 
    CvMat* world2CameraTransformationOpenGL = cvCreateMat(4,4,CV_32FC1); 
    cvMatMul(correctionMatrix,world2CameraTransformation, world2CameraTransformationOpenGL); 

    CvMat* camera2WorldTransformationOpenGL = cvCreateMat(4,4,CV_32FC1); 
    cvInv(world2CameraTransformationOpenGL,camera2WorldTransformationOpenGL, 
    CV_LU); 

    cvReleaseMat(&world2CameraTransformationOpenGL); 
    ... 

    return camera2WorldTransformationOpenGL; 
} 

我想翻轉的座標系統是必要的,因爲OpenCV的和OpenGL/VTK /等。使用不同的座標系統,如圖所示OpenGL and OpenCV Coordinate Systems

那麼,它的工作方式,但有人可能有更好的解釋。