Custom User Matrix to Align Image With DICOM#
Note
Wish List Still needs additional work to finish proper creation of example.
Synopsis#
Uses a custom user matrix to align the image with DICOM physical space.
Results#
Note
Help Wanted Implementation of Results for sphinx examples containing this message. Reconfiguration of CMakeList.txt may be necessary. Write An Example <https://itk.org/ITKExamples/Documentation/Contribute/WriteANewExample.html>
Code#
C++#
/*
* #include <itkRandomImageSource.h>
#include "itkImageToVTKImageFilter.h"
#include "vtkVersion.h"
#include <vtkSmartPointer.h>
#include <vtkGPUVolumeRayCastMapper.h>
#include <vtkColorTransferFunction.h>
#include <vtkPiecewiseFunction.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVolumeProperty.h>
#include <vtkMatrix4x4.h>
#include <vtkAxesActor.h>
using VisualizingImageType = itk::Image<unsigned char, 3>;
VisualizingImageType::Pointer createImage()
{
itk::Size<3> size;
size[0]=512;
size[1]=512;
size[2]=16;
itk::RandomImageSource<VisualizingImageType>::Pointer randomImageSource =
itk::RandomImageSource<VisualizingImageType>::New();
randomImageSource->SetNumberOfThreads(1); // to produce non-random results
randomImageSource->SetSize(size);
randomImageSource->Update();
VisualizingImageType::Pointer image=randomImageSource->GetOutput();
double t[3]={0, -200, 150};
image->SetOrigin(t);
t[0]=0.68;
t[1]=0.68;
t[2]=4.4;
image->SetSpacing(t);
VisualizingImageType::DirectionType m;
m(0,0)=0;
m(0,1)=1;
m(0,2)=0;
m(1,0)=0.707;
m(1,1)=0;
m(1,2)=-0.707;
m(2,0)=-0.707;
m(2,1)=0;
m(2,2)=-0.707;
m=m.GetTranspose();
image->SetDirection(m);
return image;
}
int main(int argc, char *argv[])
{
VisualizingImageType::Pointer image=createImage();
vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();
vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer<vtkRenderer>::New();
ren1->SetBackground(0.5f,0.5f,1.0f);
renWin->AddRenderer(ren1);
renWin->SetSize(1280,1024);
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
iren->SetRenderWindow(renWin);
renWin->Render(); // make sure we have an OpenGL context.
using itkVtkConverter = itk::ImageToVTKImageFilter<VisualizingImageType>;
itkVtkConverter::Pointer conv=itkVtkConverter::New();
conv->SetInput(image);
vtkSmartPointer<vtkGPUVolumeRayCastMapper> volumeMapper =
vtkSmartPointer<vtkGPUVolumeRayCastMapper>::New();
#if VTK_MAJOR_VERSION <= 5
volumeMapper->SetInput(conv->GetOutput());
#else
conv->Update();
volumeMapper->SetInputData(conv->GetOutput());
#endif
vtkSmartPointer<vtkVolumeProperty> volumeProperty =
vtkSmartPointer<vtkVolumeProperty>::New();
vtkSmartPointer<vtkPiecewiseFunction> compositeOpacity =
vtkSmartPointer<vtkPiecewiseFunction>::New();
compositeOpacity->AddPoint(0.0,0.1);
compositeOpacity->AddPoint(80.0,0.2);
compositeOpacity->AddPoint(255.0,0.1);
volumeProperty->SetScalarOpacity(compositeOpacity);
vtkSmartPointer<vtkColorTransferFunction> color =
vtkSmartPointer<vtkColorTransferFunction>::New();
color->AddRGBPoint(0.0 ,0.0,0.0,1.0);
color->AddRGBPoint(40.0 ,1.0,0.0,0.0);
color->AddRGBPoint(255.0,1.0,1.0,1.0);
volumeProperty->SetColor(color);
vtkSmartPointer<vtkVolume> volume =
vtkSmartPointer<vtkVolume>::New();
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
// Here we take care of position and orientation
// so that volume is in DICOM patient physical space
VisualizingImageType::DirectionType d=image->GetDirection();
vtkMatrix4x4 *mat=vtkMatrix4x4::New(); //start with identity matrix
for (int i=0; i<3; ++i)
for (int k=0; k<3; ++k)
mat->SetElement(i,k, d(i,k));
// Counteract the built-in translation by origin
VisualizingImageType::PointType origin=image->GetOrigin();
volume->SetPosition(-origin[0], -origin[1], -origin[2]);
// Add translation to the user matrix
for (int i=0; i<3; ++i)
{
mat->SetElement(i,3, origin[i]);
}
volume->SetUserMatrix(mat);
// Add coordinate system axes, so we have a reference for position and orientation
vtkSmartPointer<vtkAxesActor> axes = vtkSmartPointer<vtkAxesActor>::New();
axes->SetTotalLength(250,250,250);
axes->SetShaftTypeToCylinder();
axes->SetCylinderRadius(0.01);
ren1->AddActor(axes);
ren1->AddVolume( volume );
ren1->ResetCamera();
renWin->Render();
renWin->Render();
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
Classes demonstrated#
-
template<typename TInputImage>
class ImageToVTKImageFilter : public itk::ProcessObject Converts an ITK image into a VTK image and plugs a itk data pipeline to a VTK datapipeline.
This class puts together an itkVTKImageExporter and a vtkImageImporter. It takes care of the details related to the connection of ITK and VTK pipelines. The User will perceive this filter as an adaptor to which an itk::Image can be plugged as input and a vtkImage is produced as output.