2014-08-28 10 views
7

Đối với dự án thực tế tăng cường của tôi, tôi có một mô hình 3D được xem bằng camera VTK và một đối tượng thực sự của mô hình được xem bằng máy ảnh thực.Làm cách nào để áp dụng tính năng chuyển đổi tư thế máy ảnh bằng tính năng EPnP sang máy ảnh VTK?

Tôi đã sử dụng EPnP để ước tính ma trận bên ngoài của camera thực (máy ảnh này đã được hiệu chuẩn trước khi cầm tay, vì vậy tôi biết các thông số bên trong) bằng cách cho điểm 3D từ VTK và điểm 2D tương ứng của nó từ hình ảnh camera thực và các thông số nội bộ của camera thực cho thuật toán EPnP hoạt động.

Sau đó, tôi thu được ma trận xoay và dịch với các phần tử -> R1, R2, R3, ....., R9 và t1, t2 và t3.

Vì vậy, ma trận bên ngoài của tôi về máy ảnh thực sự trông như thế này (chúng ta hãy gọi extrinsicReal này)

R1 R2 R3 T1 
R4 R5 R6 T2 
R7 R8 R9 T3 
0 0 0 1 

Sau này, tôi ước lượng ma trận bên ngoài của máy ảnh VTK của tôi bằng cách sử dụng đoạn mã sau:

vtkSmartPointer<vtkMatrix4x4> extrinsicVTK = vtkSmartPointer<vtkMatrix4x4>::New(); 
extrinsicVTK->DeepCopy(renderer->GetActiveCamera()->GetViewTransformMatrix()); 

Để kết hợp mô hình 3D camera VTK với camera thực, camera VTK phải được đặt ở vị trí giống với vị trí camera thực và độ dài tiêu cự của camera VTK phải giống như camera thực của camera . Một bước quan trọng khác là áp dụng cùng ma trận bên ngoài của camera thực cho camera VTK. Tôi phải làm nó như thế nào?

Những gì tôi đã làm là tôi lấy nghịch đảo của extrinsicReal và nhân với extrinsicVTK để lấy ma trận 4 * 4 mới (hãy gọi nó là newMatrix). Tôi đã áp dụng ma trận này cho việc chuyển đổi camera VTK.

vtkSmartPointer<vtkMatrix4x4> newMatrix = vtkSmartPointer<vtkMatrix4x4>::New(); 
vtkMatrix4x4::Multiply4x4(extrinsicRealInvert,extrinsicVTK,newMatrix); 

vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New(); 
transform->SetMatrix(NewM); 
transform->Update(); 

renderer->GetActiveCamera()->ApplyTransform(transform); 

Tôi không thực sự chắc chắn nếu đây là phương pháp đúng. Nhưng tôi đã kiểm tra vị trí camera thực (mà tôi nhận được sau EPnP) và vị trí camera VTK (sau khi áp dụng phép biến đổi ở trên) và cả hai đều giống hệt nhau. Ngoài ra, định hướng của camera thực và hướng chiếu của camera VTK cũng giống nhau.

Vấn đề là ngay cả sau khi các thông số trên phù hợp với cả VTK và máy ảnh thực, mô hình VTK 3D dường như không hoàn toàn phù hợp với video camera thực. Ai đó có thể hướng dẫn tôi từng bước để gỡ lỗi vấn đề không?

Trả lời

10

Mọi thứ trở nên phức tạp khi áp dụng các thông số đó cho máy ảnh vtk. Đây là cách tôi đã làm nó (chỉ trích đoạn mã quan trọng, toàn bộ mã sẽ là quá nhiều để dán ở đây và sẽ là vô ích cho bạn anyway). Các điểm khác cần xem xét:

  1. Tôi đang hiển thị hình ảnh nội soi làm kết cấu nền trong vtkRenderWindow của tôi.
  2. Tôi đang sử dụng một kết hợp của VTK, ITK (VNL), chức năng OpenCV nhưng họ nên được hoán đổi cho nhau (ví dụ cvRound cũng có thể được thay thế bằng vtkMath :: Round() vv)

Trước hết, tôi sử dụng máy ảnh hoạt động từ vtkRenderer của tôi:

d->m_Renderer->GetActiveCamera() 

Bước tiếp theo là liên tục cập nhật máy ảnh hiện hoạt bằng cách áp dụng biến đổi của bạn. Tùy thuộc vào việc cửa sổ hiển thị của bạn có thể thay đổi kích thước hay không, bạn phải khởi tạo hoặc liên tục cập nhật hai tham số khác: 1. ViewAngle, 2.WindowCenter (cực kỳ quan trọng, không phải tài liệu nào cả bởi vtk. Nhưng cuối cùng bạn phải áp dụng điểm chính của bạn ở đây mà bạn tìm thấy bằng cách hiệu chuẩn hoặc bạn sẽ có bề mặt của bạn được bù đắp. dung dịch).

Tính góc nhìn:

double focalLengthY = _CameraIntrinsics->GetFocalLengthY(); 
    if(_WindowSize.height != _ImageSize.height) 
    { 
    double factor = static_cast<double>(_WindowSize.height)/static_cast<double>(_ImageSize.height); 
    focalLengthY = _CameraIntrinsics->GetFocalLengthY() * factor; 
    } 

    _ViewAngle = 2 * atan((_WindowSize.height/2)/focalLengthY) * 180/vnl_math::pi; 

Áp dụng các góc nhìn:

d->m_Renderer->GetActiveCamera()->SetViewAngle(viewAngle); 

Tính toán WindowCenter:

double px = 0; 
    double width = 0; 

    double py = 0; 
    double height = 0; 

    if(_ImageSize.width != _WindowSize.width || _ImageSize.height != _WindowSize.height) 
    { 
    double factor = static_cast<double>(_WindowSize.height)/static_cast<double>(_ImageSize.height); 

    px = factor * _CameraIntrinsics->GetPrincipalPointX(); 
    width = _WindowSize.width; 
    int expectedWindowSize = cvRound(factor * static_cast<double>(_ImageSize.width)); 
    if(expectedWindowSize != _WindowSize.width) 
    { 
     int diffX = (_WindowSize.width - expectedWindowSize)/2; 
     px = px + diffX; 
    } 

    py = factor * _CameraIntrinsics->GetPrincipalPointY(); 
    height = _WindowSize.height; 
    } 
    else 
    { 
    px = _CameraIntrinsics->GetPrincipalPointX(); 
    width = _ImageSize.width; 

    py = _CameraIntrinsics->GetPrincipalPointY(); 
    height = _ImageSize.height; 
    } 

    double cx = width - px; 
    double cy = py; 

    _WindowCenter.x = cx/((width-1)/2) - 1 ; 
    _WindowCenter.y = cy/((height-1)/2) - 1; 

Thiết lập Trung tâm Window:

d->m_Renderer->GetActiveCamera()->SetWindowCenter(_WindowCenter.x, _WindowCenter.y); 

Áp dụng ma trận bên ngoài về phía camera:

// create a scaling matrix (THE CLASS TRANSFORM IS A WRAPPER FOR A 4x4 Matrix, methods should be self-documenting) 
d->m_ScaledTransform = Transform::New(); 
d->m_ScaleMat.set_identity(); 
d->m_ScaleMat(1,1) = -d->m_ScaleMat(1,1); 
d->m_ScaleMat(2,2) = -d->m_ScaleMat(2,2); 

// scale the matrix appropriately (m_VnlMat is a VNL 4x4 Matrix) 
d->m_VnlMat = d->m_CameraExtrinsicMatrix->GetMatrix(); 
d->m_VnlMat = d->m_ScaleMat * d->m_VnlMat; 
d->m_ScaledTransform->SetMatrix(d->m_VnlMat); 

d->m_VnlRotation = d->m_ScaledTransform->GetVnlRotationMatrix(); 
d->m_VnlRotation.normalize_rows(); 
d->m_VnlInverseRotation = vnl_matrix_inverse<mitk::ScalarType>(d->m_VnlRotation); 

// rotate translation vector by inverse rotation P = P' 
d->m_VnlTranslation = d->m_ScaledTransform->GetVnlTranslation(); 
d->m_VnlTranslation = d->m_VnlInverseRotation * d->m_VnlTranslation; 
d->m_VnlTranslation *= -1; // save -P' 

// from here proceed as normal 
// focalPoint = P-viewPlaneNormal, viewPlaneNormal is rotation[2] 
d->m_ViewPlaneNormal[0] = d->m_VnlRotation(2,0); 
d->m_ViewPlaneNormal[1] = d->m_VnlRotation(2,1); 
d->m_ViewPlaneNormal[2] = d->m_VnlRotation(2,2); 

d->m_vtkCamera->SetPosition(d->m_VnlTranslation[0], d->m_VnlTranslation[1], d->m_VnlTranslation[2]); 

d->m_vtkCamera->SetFocalPoint(d->m_VnlTranslation[0] - d->m_ViewPlaneNormal[0], 
           d->m_VnlTranslation[1] - d->m_ViewPlaneNormal[1], 
           d->m_VnlTranslation[2] - d->m_ViewPlaneNormal[2]); 
d->m_vtkCamera->SetViewUp(d->m_VnlRotation(1,0), d->m_VnlRotation(1,1), d->m_VnlRotation(1,2)); 

Và cuối cùng làm một clipping phạm vi thiết lập lại:

d->m_Renderer->ResetCameraClippingRange(); 

Hope điều này có ích. Tôi không có thời gian để giải thích thêm chi tiết. Đặc biệt là mã cuối cùng (áp dụng các extrinsics cho máy ảnh) có một số ý nghĩa được kết nối với định hướng hệ tọa độ. Nhưng điều đó làm việc cho tôi.

Tốt nhất Michael

+3

Chỉ muốn nói rằng điều này thực sự là điểm trên. Các tài liệu VTK là một cơn ác mộng vì vậy nó tuyệt vời để vấp ngã khi một cái gì đó như thế này sau khi đập đầu của chúng tôi chống lại một bức tường trong 4 tháng qua. Tôi thậm chí không bao giờ coi chức năng SetWindowCenter! Chúng tôi vẫn nhận được khoản chênh lệch khá rõ ràng do kích thước cửa sổ (Lỗi thay đổi với thay đổi kích thước), nhưng mọi thứ khác hoạt động tốt ngay bây giờ mà chúng tôi đã điều chỉnh một số kỹ thuật của bạn. Tôi cảm thấy bạn trên tài liệu VTK. Nó thực sự là một cơn ác mộng để tìm ra những gì đang xảy ra. Ai đó cần phải sửa lại điều đó. – SwarthyMantooth

+0

Tôi không hiểu phần áp dụng bên ngoài. Vai trò của ma trận quy mô với hai dấu hiệu tiêu cực là gì? Nếu R và t là các giá trị từ ma trận bên ngoài OpenCV, vị trí của máy ảnh phải là '-Rinv * t', và xem nên là' Rinv [:, 1] 'và tiêu điểm nên là' camera_pos - Rinv [:, 2 ] '. Khi tôi áp dụng điều này, tôi không có được sự chồng chất chính xác của mô hình. Ngay cả khi tôi áp dụng chuyển đổi của bạn giả định m_CameraExtrinsicMatrix có định dạng của ma trận OpenCV, tôi không nhận được kết xuất chính xác. – krips89

+0

Một phiên bản sạch hơn trong cùng một cách tiếp cận được chỉ ra trong câu trả lời tuyệt vời của @ Michael cho phần 'bên ngoài' bên dưới (trong python): (1) camera.SetPosition (* eye) (2) camera.SetFocalPoint (* center) (3) camera.SetViewUp (* up), trong đó '' 'eye = (-R'T), center = eye + R '(0,0,1)', up = -R [0] [1]' ' ' – squid

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