2013-09-05 34 views
38

Tôi có camera hiệu chỉnh (ma trận nội tại và hệ số méo) và tôi muốn biết vị trí camera biết một số điểm 3d và điểm tương ứng của chúng trong ảnh (2d điểm).Vị trí camera trong phối hợp thế giới từ cv :: resolvePnP

Tôi biết rằng cv::solvePnP có thể giúp tôi, và sau khi đọc thisthis Tôi hiểu rằng tôi các kết quả đầu ra của solvePnP rvectvec là luân chuyển và bản dịch của các đối tượng trong máy ảnh hệ tọa độ.

Vì vậy, tôi cần tìm hiểu về xoay/dịch của máy ảnh trong hệ tọa độ thế giới.

Từ liên kết ở trên có vẻ như rằng mã rất đơn giản, trong python:

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) 

Tôi không biết python/chất liệu NumPy (Tôi đang sử dụng C++) nhưng điều này không kiếm được nhiều ý nghĩa với tôi:

  • rvec, sản lượng tvec từ solvePnP là ma trận 3x1, 3 yếu tố vector
  • cv2.Rodrigues (rvec) là một ma trận 3x3
  • cv2.Rodrigues (rvec) [0] là một Ma trận 3x1, 3 phần tử vectơ
  • cameraĐặt vị trí là phép nhân ma trận 3x1 * 1x3 là ma trận .. 3x3. làm thế nào tôi có thể sử dụng điều này trong opengl với các cuộc gọi glTranslatefglRotate đơn giản?

Trả lời

44

Nếu có "tọa độ thế giới", bạn có nghĩa là "tọa độ đối tượng", bạn phải chuyển đổi nghịch đảo của kết quả được đưa ra bởi thuật toán pnp.

Có một mẹo để đảo ngược ma trận chuyển đổi cho phép bạn lưu hoạt động đảo ngược, thường tốn kém và giải thích mã bằng Python. Với một chuyển đổi [R|t], chúng tôi có số inv([R|t]) = [R'|-R'*t], trong đó R' là chuyển vị của R. Vì vậy, bạn có thể mã hóa (không kiểm tra):

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 

Cập nhật: Sau đó, sử dụng T với OpenGL bạn phải ghi nhớ rằng các trục của khung máy ảnh khác nhau giữa OpenCV và OpenGL.

OpenCV sử dụng tham chiếu thường được sử dụng trong tầm nhìn máy tính: X trỏ sang phải, Y xuống, Z về phía trước (như trong this image). Khung của camera trong OpenGL là: X trỏ sang phải, Y lên, Z về phía sau (như trong this image). Vì vậy, bạn cần phải áp dụng một vòng xoay xung quanh trục X 180 độ. Công thức của ma trận xoay này là 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 

Những biến đổi này luôn gây nhầm lẫn và tôi có thể sai khi thực hiện một số bước, vì vậy hãy dùng nó với một hạt muối.

Cuối cùng, hãy xem xét rằng ma trận trong OpenCV được lưu trữ theo thứ tự hàng lớn trong bộ nhớ, và OpenGL, theo thứ tự cột lớn.

+0

dường như hoạt động, tôi nhận được các góc cho 'glRotatef' với công thức được lấy từ đây: http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToEuler/index.htm và sau đó chuyển đổi bình thường từ radials đến mức độ. Nhưng nếu tôi cắm các giá trị đó vào trong opengl thì tôi vẫn quay nhầm (xoay X là 45 ° sai) và dịch sai một chút. – nkint

+0

Điều đó có thể là do khung máy ảnh trong OpenCV và OpenGL khác nhau . Kiểm tra câu trả lời mở rộng của tôi. – ChronoTrigger

+0

vâng tôi biết sự khác biệt về thứ tự ma trận trong bộ nhớ giữa opencv và opengl. Và tôi cũng phải lật trục y và z (=> sử dụng opencv y như opengl z và sử dụng opencv z làm opengl y) – nkint

3

Nếu bạn muốn biến nó thành ma trận gây ra tiêu chuẩn 4x4 chỉ định vị trí của máy ảnh của bạn. Sử dụng rotM như hình vuông 3x3 phía trên bên trái, tvec là 3 yếu tố trên bên phải, và 0,0,0,1 như hàng dưới cùng

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

sau đó đảo ngược nó (để có được tư thế của máy ảnh thay vì tư thế của thế giới)

Các vấn đề liên quan