I have a set of matching .nii image files and .obj model files. After importing them into 3D Slicer, I found that the .obj model file is offset far from the world origin, basically out of the image’s range in the world coordinate system. However, it is still possible to achieve position-based interaction between the image and the model. How is this accomplished?
Could you take a screenshot with the slice views visible in 3D so that we can see where the image is? (click the pushpin and then the eye icon above each slice view).
However, when I load these .obj models into my self-written VTK software, the displayed positions are significantly offset from the origin, and there is a large discrepancy between the positions selected on the image and the model.
This is the relevant code I wrote
void vtkSliceLoader::Load(std::string fileName)
{
reader->SetFileName(fileName.c_str());
reader->Update();
//计算center
double spacing[3];
double origin[3];
int extent[6];
reader->GetOutputInformation(0)->Get(
vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), extent);
reader->GetOutput()->GetSpacing(spacing);
reader->GetOutput()->GetOrigin(origin);
this->center[0] = origin[0] + spacing[0] * 0.5 * (extent[0] + extent[1]);
this->center[1] = origin[1] + spacing[1] * 0.5 * (extent[2] + extent[3]);
this->center[2] = origin[2] + spacing[2] * 0.5 * (extent[4] + extent[5]);
}
void asclepios::gui::vtkResliceCallback::moveCursor(double* t_position) const
{
vtkMatrix4x4* matrix = nullptr;
vtkMatrix4x4* matrix2 = nullptr;
vtkMatrix4x4* sourceMatrix =
m_resliceWidget->getImageReslicers()[m_handleNumber]->GetResliceAxes();
switch (m_handleNumber)
{
case 0:
matrix = m_resliceWidget->getImageReslicers()[1]->GetResliceAxes();
matrix2 = m_resliceWidget->getImageReslicers()[2]->GetResliceAxes();
break;
case 1:
matrix = m_resliceWidget->getImageReslicers()[0]->GetResliceAxes();
matrix2 = m_resliceWidget->getImageReslicers()[2]->GetResliceAxes();
break;
case 2:
matrix = m_resliceWidget->getImageReslicers()[0]->GetResliceAxes();
matrix2 = m_resliceWidget->getImageReslicers()[1]->GetResliceAxes();
break;
default:
break;
}
if (m_window)
{
vtkNew<vtkTransform> transform;
transform->SetMatrix(sourceMatrix);
transform->Translate(t_position[0], t_position[1], 0);
double center[3] =
{
transform->GetMatrix()->GetElement(0, 3),
transform->GetMatrix()->GetElement(1, 3),
transform->GetMatrix()->GetElement(2, 3)
};
matrix->SetElement(0, 3, center[0]);
matrix->SetElement(1, 3, center[1]);
matrix->SetElement(2, 3, center[2]);
matrix2->SetElement(0, 3, center[0]);
matrix2->SetElement(1, 3, center[1]);
matrix2->SetElement(2, 3, center[2]);
emit EventManager::instance()->moveCursor(m_handleNumber,center);
}
}
void vtkThreeDViewerLogic::onSliceMoveCursor(int handleIdx, double* slicePos) {
double worldPoint[3];
double* center = vtkSliceLoader::instance().GetCenter();
worldPoint[0] = slicePos[0] - center[0];
worldPoint[1] = slicePos[1] - center[1];
worldPoint[2] = slicePos[2] - center[2];
if (!mRenderer->HasViewProp(mPickMark)) {
mRenderer->AddActor(mPickMark);
}
mPickMark->SetPosition(worldPoint);
mInteractor->Render();
}
The code snippets are incomplete, it is not possible to even guess what they might be doing.
Slicer is open-source, you can inspect the code and figure out what it does and reimplement in your own software. However, you will experience that there is just way too much to copy from Slicer - you are probably better off customizing and extending Slicer - see https://www.kitware.com/slicercat-creating-custom-applications-based-on-3d-slicer/