7

Tôi đang cố gắng đạt được ước tính đặt ra toàn cầu từ một hình ảnh của bốn tài liệu có vị trí toàn cầu đã biết bằng cách sử dụng webcam của tôi.Ước tính đặt ra máy ảnh (OpenCV PnP)

Tôi đã kiểm tra nhiều câu hỏi stackexchange và một vài giấy tờ và tôi dường như không thể có được một giải pháp đúng. Các số vị trí tôi nhận được có thể lặp lại nhưng không có cách nào tỷ lệ thuận với chuyển động của máy ảnh. FYI Tôi đang sử dụng C++ OpenCV 2.1.

At this link is pictured hệ thống tọa độ của tôi và dữ liệu thử nghiệm được sử dụng bên dưới.

% 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] 

Cho đến nay, ai cũng có thể thấy điều gì sai với những số này? Tôi sẽ đánh giá cao nếu ai đó sẽ kiểm tra chúng trong ví dụ MatLAB (mã ở trên là m-file thân thiện).

Từ thời điểm này, tôi không chắc chắn về cách có được tư thế toàn cầu từ rMat và tVec. Từ những gì tôi đã đọc trong this question, để có được những tư thế từ rMat và tVec chỉ đơn giản là:

position = transpose(rMat) * tVec % matrix multiplication 

Tuy nhiên tôi nghi ngờ từ các nguồn khác mà tôi đã đọc nó không phải là đơn giản.

Để có được vị trí của máy ảnh trong các tọa độ thực tế, tôi cần phải làm gì? Vì tôi không chắc liệu đây có phải là vấn đề triển khai hay không (tuy nhiên có thể là vấn đề lý thuyết). Tôi muốn người dùng đã sử dụng hàm resolvePnP thành công trong OpenCV để trả lời câu hỏi này, mặc dù mọi ý tưởng đều được chào đón!

Cảm ơn bạn rất nhiều vì đã dành thời gian.

+0

bạn quên nghịch đảo tVec. Vì vậy, đúng cách để làm điều này là -transpose (rMat) * tVec – Vlad

Trả lời

4

Tôi đã giải quyết điều này một lúc trước, xin lỗi vì sự chậm trễ hàng năm.

Trong python OpenCV 2.1 Tôi đã sử dụng, và các phiên bản mới hơn 3.0.0-dev, tôi đã xác minh rằng để có được tư thế của máy ảnh trong khung toàn cầu quý vị phải:

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

Bây giờ pos là vị trí của máy ảnh được thể hiện trong khung toàn cầu (cùng một khung mà các đối tượng được thể hiện trong). R là một ma trận thái độ DCM là một hình thức tốt để lưu trữ thái độ trong. Nếu bạn yêu cầu góc Euler thì bạn có thể chuyển đổi góc DCM thành Euler cho chuỗi quay XYZ bằng cách sử dụng:

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

OpenCV không có hệ tọa độ X-Y-Z. Làm thế nào để chuyển đổi sang góc Euler với opencv? –

+1

@tokam Ý của bạn là gì bởi 'nó không có hệ tọa độ X-Y-Z'? Có chức năng 'RQdecomp3x3' trong OpenCV 3.0. Tôi thấy nó mang lại cho tôi kết quả tương tự như chuyển đổi mà đôi khi bạn tìm thấy trên internet (ví dụ tại đây 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

+0

Tôi cho rằng hệ tọa độ của opencv khác với hệ tọa độ tiêu chuẩn cho máy bay và các khu vực khác. –

2

vị trí của máy ảnh sẽ là {- transpose (r) * t}. Đó là nó.

Và bạn đã làm mọi thứ một cách chính xác ngoại trừ, cv :: resolvePnp cho (4 x 1) vectơ để dịch nếu tôi nhớ đúng, bạn sẽ phải chia x, y, z với toạ độ w.

+0

Avanindra, cảm ơn bạn đã trả lời của bạn. resolvePnP chưa bao giờ trả về một véc-tơ 4x1 cho tôi, tôi tin từ những gì tôi thấy trong mã nguồn mà nó được trả về theo dạng bình thường (không chuẩn hóa) của nó. Có thể là các giá trị mà tôi đang sử dụng cho nội tại máy ảnh không chính xác (tôi đã khuyên cố gắng phủ nhận một số yếu tố) hoặc khung của tôi được xác định không chính xác? Cảm ơn bạn. – Gouda

+0

Tôi đồng ý nhưng đối với một số lý do lạ -T * R.t() là một trong đó làm cho nó hoạt động. – Vlad

4

Nếu bạn có ý nghĩa với tư thế toàn cầu một máy ảnh 4x4 pose ma trận, có thể được sử dụng trong OpenGL, tôi làm theo cách này

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; 
} 

Tôi nghĩ rằng flipping hệ toạ độ là cần thiết, bởi vì OpenCV và OpenGL/VTK/v.v. sử dụng các hệ tọa độ khác nhau, như được minh họa trong ảnh này OpenGL and OpenCV Coordinate Systems

Vâng, nó hoạt động theo cách này nhưng ai đó có thể có giải thích tốt hơn.

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