将OpenECV的 cv::solvePnP
的RVEC和TVEC(摄像机的估计姿势)应用于虚拟3D场景中的 vtkCamera
时,我遇到很多麻烦。我希望有人能告诉我我犯的错误。
我正在尝试使用 vtkActor
(胸部上放置有基准标记的3D DICOM渲染):
并使用 cv::solvePnP
将基准标记与下图所示的红色圆圈对齐(注意:红色圆圈是来自具有特定相机视角的基准标记图片的硬编码坐标):
如您所见,在将以下 vtkTransform
应用于 vtkCamera
之后,叠加的体积渲染未对齐。
cv::Mat op(model_points);
cv::Mat rvec;
cv::Mat tvec;
// op = the 3D coordinates of the markers in the scene
// ip = the 2D coordinates of the markers in the image
// camera = the intrinsic camera parameters (for calibration)
// dists = the camera distortion coefficients
cv::solvePnP(op, *ip, camera, dists, rvec, tvec, false, CV_ITERATIVE);
cv::Mat rotM;
cv::Rodrigues(rvec, rotM);
rotM = rotM.t();
cv::Mat rtvec = -(rotM*tvec);
std::cout << "rotM: \n" << rotM << std::endl;
std::cout << "tvec: \n" << tvec << std::endl;
std::cout << "rtvec: \n" << rtvec << std::endl;
double cam[16] = {
rotM.at<double>(0), rotM.at<double>(1), rotM.at<double>(2), rtvec.at<double>(0),
rotM.at<double>(3), rotM.at<double>(4), rotM.at<double>(5), rtvec.at<double>(1),
rotM.at<double>(6), rotM.at<double>(7), rotM.at<double>(8), rtvec.at<double>(2),
0, 0, 0, 1
};
vtkSmartPointer<vtkTransform> T = vtkSmartPointer<vtkTransform>::New();
T->SetMatrix(cam);
vtkSmartPointer<vtkRenderer> renderer = v->renderer();
double b_p[3];
double a_p[3];
double *b_o;
double b_o_store[3];
double *a_o;
double b_f[3];
double a_f[3];
vtkSmartPointer<vtkCamera> scene_camera = v->camera();
// Reset Position/Focal/Orientation before applying transformation
// so the transform does not compound
v->ResetCameraPositionOrientation();
// Apply the transformation
scene_camera->ApplyTransform(T);
scene_camera->SetClippingRange(1, 2000);
在下面的场景捕获中强调了这一点(胸部向屏幕鞠躬,您可以在场景中 Actor 的最底部看到三个最高基准标记):
以下屏幕截图显示了我获得的RVEC和TVEC,以及转换前后的位置/方向/焦点。
场景通过以下方式初始化:
this->actor_ = vtkVolume::New();
this->actor_->SetMapper(mapper);
this->actor_->SetProperty(volumeProperty);
this->actor_->SetPosition(0,0,0);
this->actor_->RotateX(90.0);
this->renderer_ = vtkRenderer::New();
this->renderer_->AddViewProp(this->actor_);
this->renderer_->SetBackground(0.3,0.3,0.3);
this->camera_ = this->renderer_->GetActiveCamera();
// Center the scene so that we can grab the position/focal-point for later
// use.
this->renderer_->ResetCamera();
// Get the position/focal-point for later use.
double pos[3];
double orientation[3];
this->camera_->GetPosition(pos);
this->camera_->GetFocalPoint(this->focal_);
double *_o = this->camera_->GetOrientation();
this->orientation_[0] = _o[0];
this->orientation_[1] = _o[1];
this->orientation_[2] = _o[2];
this->position_[0] = pos[0];
this->position_[1] = pos[1];
this->position_[2] = pos[2];
// Set the camera in hopes of it "sticking"
this->camera_->SetPosition(pos);
this->camera_->SetFocalPoint(this->focal_);
this->camera_->SetViewUp(0, 1, 0);
this->camera_->SetFreezeFocalPoint(true);
对于这么长的问题,我深表歉意。我想提供尽可能多的信息。我已经在这个问题上工作了几天了,无法解决!
最佳答案
这可能为时已晚,但是我目前几乎在做确切的事情,而我们只是解决了这个问题。我什至都在使用VTK! SolvePnP
返回的内容(假设我没有误会OpenCV的Rodrigues
返回相似的矩阵)是全局转换矩阵。该矩阵表示全局框架中的旋转和平移。由于转换的工作方式,必须先对全局变量进行预乘,而对局部转换进行后乘,因此需要在代码中完成。我们这样做的方法是使用生产线((vtkMRMLLinearTransformNode*)(d->CameraVideoTransformComboBox->currentNode()))->SetMatrixTransformFromParent(staticVideoTransform4x4);
哪里:d
是对3d Slicer模块的UI的引用,该模块基本上可以被视为大型VTK工具箱CameraVideoTransformComboBox
只是一个存储转换的UI组合框staticVideoTransform4x4
是我们的翻译矩阵。
然后,我们通过用户界面应用了转换,而不是通过代码进行转换的方法,因此不幸的是,其中存在一些黑框,这让我无法就如何自己编写代码给出确切的答案。如果您(或更可能是阅读此书的人)遇到此问题,我建议您查看vtkMRMLTransformNode::SetMatrixTransformFromParent()
以获得指导。如果那不能完全解决问题,请尝试反转矩阵!
关于c++ - 来自OpenCV的来自solvePnP的估计姿势的VTK摄像机姿势,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22441782/