2013-09-05 2 views
38

저는 보정 된 카메라 (고유 행렬 및 왜곡 계수)를 가지고 있으며 이미지의 일부 3d 점과 해당 점 (2d 점)을 알고있는 카메라 위치를 알고 싶습니다.세계 좌표계에서 카메라의 위치는 cv :: solvePnP에서

나는 cv::solvePnP가 나를 도울 수 있다는 것을 알고, thisthis을 읽은 후 나는 solvePnP rvectvec의 I 출력이 회전 카메라에서 개체의 번역 좌표계 것으로 알고 있습니다.

그래서 세계 좌표계에서 카메라 회전/평행 이동을 찾아야합니다.

found,rvec,tvec = cv2.solvePnP(object_3d_points, object_2d_points, camera_matrix, dist_coefs) 
rotM = cv2.Rodrigues(rvec)[0] 
cameraPosition = -np.matrix(rotM).T * np.matrix(tvec) 

내가 파이썬/NumPy와 거즈를 모르는 (나는 C를 사용하고 있습니다 ++) 그러나 이것은 많이하지 않습니다 : 링크에서

는 코드가 Python으로, 간단 것으로 보인다 위 그다지 의미 :

  • rvec, solvePnP에서 tvec 출력은 3 × 1 행렬이고, 3 요소 벡터
  • cv2.Rodrigues (rvec)는 3 × 3 행렬
  • cv2.Rodrigues (rvec) [0]이다 3x1 매트릭스, 3 요소 벡터
  • cameraPosition은 3x1 행렬 인 3x1 * 1x3 행렬 곱셈입니다. opengl에서 간단하게 glTranslatefglRotate을 호출하면 어떻게 사용할 수 있습니까?

답변

44

"세계 좌표"를 사용하면 "개체 좌표"를 의미하는 경우 pnp 알고리즘에 의해 주어진 결과의 역변환을 얻어야합니다.

일반적으로 비용이 많이 드는 반전 작업을 저장하고 Python의 코드를 설명하는 변환 행렬을 반전하는 트릭이 있습니다. 변환 [R|t]이 주어지면, inv([R|t]) = [R'|-R'*t]이됩니다. 여기에서 R'은 전치 코드 R입니다. 그래서, 당신은 (테스트하지) 코딩 할 수 있습니다 :

cv::Mat rvec, tvec; 
solvePnP(..., rvec, tvec, ...); 
// rvec is 3x1, tvec is 3x1 

cv::Mat R; 
cv::Rodrigues(rvec, R); // R is 3x3 

R = R.t(); // rotation of inverse 
tvec = -R * tvec; // translation of inverse 

cv::Mat T(4, 4, R.type()); // T is 4x4 
T(cv::Range(0,3), cv::Range(0,3)) = R * 1; // copies R into T 
T(cv::Range(0,3), cv::Range(3,4)) = tvec * 1; // copies tvec into T 
// fill the last row of T (NOTE: depending on your types, use float or double) 
double *p = T.ptr<double>(3); 
p[0] = p[1] = p[2] = 0; p[3] = 1; 

// T is a 4x4 matrix with the pose of the camera in the object frame 

업데이트 : 나중에 카메라 프레임의 축이 OpenCV의와 OpenGL 사이에 차이가 있음을 명심해야 OpenGL을 함께 T를 사용 할 수 있습니다.

OpenCV는 일반적으로 컴퓨터 비전에 사용되는 참조를 사용합니다. X는 오른쪽을 가리키고 Y는 아래를, Z는 앞을 나타냅니다 (this image). OpenGL에서 카메라의 프레임은 다음과 같습니다. X는 오른쪽을 가리키고 Y는 위로, Z는 뒤를 나타냅니다 (this image에서와 같이). 따라서 180도 X 축을 중심으로 회전을 적용해야합니다. 이 회전 행렬의 공식은 wikipedia입니다.

// T is your 4x4 matrix in the OpenCV frame 
cv::Mat RotX = ...; // 4x4 matrix with a 180 deg rotation around X 
cv::Mat Tgl = T * RotX; // OpenGL camera in the object frame 

이 변환은 항상 혼란과 나는 어떤 단계에서 잘못 때문에 에누리이 걸릴 수 있습니다.

마지막으로 OpenCV의 행렬은 행 우선 순서로 메모리에 저장되고 OpenGL 행렬은 행 우선 순서로 저장된다는 점을 고려하십시오.

+0

이 작동하는 것처럼 보입니다.이 글에서 얻은 수식으로 'glRotatef'의 각도를 얻습니다. http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm 방사형을 학위로. 하지만 OpenGL에서 이러한 값을 연결하면 여전히 잘못된 카메라 회전 (회전 X는 45 °와 비슷합니다)과 약간 잘못된 변환이 발생합니다. – nkint

+0

OpenCV 및 OpenGL에서 카메라 프레임이 다르기 때문일 수 있습니다 . 내 확장 된 대답을 확인하십시오. – ChronoTrigger

+0

예 Opencv와 OpenGL 사이의 메모리에서 행렬의 순서가 어떻게 다른지 알고 있습니다. 그리고 저는 y 축과 z 축을 뒤집어 야합니다 (=> opencv y를 opengl z로 사용하고 opencv z를 opengl y로 사용하십시오) – nkint

3

카메라의 위치를 ​​지정하는 표준 4x4 자세 매트릭스로 바꾸려면 여기를 선택하십시오. 그것을 반전

pose = [rotation tvec(0) 
     matrix  tvec(1) 
     here  tvec(2) 
     0 , 0, 0, 1] 

다음 아래 행으로 오른쪽의 3 개 요소로 왼쪽 상단 3 × 광장, tvec로 rotM를 사용하여 0,0,0,1 (대신 포즈의 카메라에 포즈 얻을 수 세계)

관련 문제