Medical Imaging Interaction Toolkit  2023.04.00
Medical Imaging Interaction Toolkit
IGT Visualization Filter and MITK Concepts

The following code shows how to insert IGT tracking data into an mitk::DataStorage and render the data with the mitk::NavigationDataObjectVisualizationFilter in an mitk::RenderWindow. The full code is shown below and can be found in MITK-Source/Modules/IGT/Tutorial/mitkIGTTutorialStep2.cpp. This tutorial is an extra target which can be build separately (see IGT Example Build Instructions).

The example we are using here regards a moving tracker and a fixed object, and after tracking a transform to move the fixed object to the tracked one is calculated and applied.

// What we will do...
// This tutorial shows how to compose navigation datas. Therefore we render two objects.
//The first object is a cone that is tracked. The second object is a cylinder at a fixed position
//relative to the cone. At the end of the tracking, the cylinder is moved to its new relative position
//according to the last output of the tracking device.
//In addition to IGT tutorial step 1, the objects are added to a datastorage. Furthermore, a renderwindow
//is used for visual output.

The next image describes, what happens in this example. The blue and red object are labeled with "1" at their initial position. Next, the blue object will move (approximately along the yellow arrow) to the second position, while the red one stayes fixed. Now we calculate the transform of the blue cones initial and moved position (1 -> 2) and apply this transform to shift the red object to its final position (3). Now, the relative distance and orientation of the blue and red object is as it was in the beginning.

Overlay of the three steps in this example: 1. Initial position, 2. Blue object moved along the yellow arc, 3. Final position, the red object is moved to get the initial relative position compared to the blue object.

Set up Render Window and Tracking Device

First of all, we create a new render window. For simplicity, we are not using the MITK workbench yet but run this example as a stand alone application. Hence, we need to create a render window and a data storage.

//General code rendering the data in a renderwindow. See MITK Tutorial Step1 for more details.
//Here, we want a 3D renderwindow
renderWindow->GetVtkRenderWindow()->SetSize(500, 500);
renderWindow->GetRenderer()->Resize(500, 500);
//Connect datastorage and renderwindow

Next, we need to set up the tracking device like we did in the last tutorial step IGT filter pipeline . We set additionally some boundaries for the tracking.

//Virtual tracking device to generate random positions
mitk::VirtualTrackingDevice::Pointer tracker = mitk::VirtualTrackingDevice::New();
//Bounds (within the random numbers are generated) must be set before the tools are added
double bound = 10.0;
mitk::ScalarType bounds[] = { -bound, bound, -bound, bound, -bound, bound };
//Tracking device source to get the data
mitk::TrackingDeviceSource::Pointer source = mitk::TrackingDeviceSource::New();

Create Objects

Now we create a fixed and a moving object. For the moving (tracked) object, we decided for a blue cone. First, we set the name and color and add it to the data storage. Next, we need to create a visualitation filter to display it. Here, we connect in the visualization filter the output of our tracking device source to the cone representation.

//Cone representation for rendering of the moving object
dataNode->SetName("My tracked object");
dataNode->SetColor(0.0, 1.0, 1.0);
//Filter for rendering the cone at correct postion and orientation
mitk::NavigationDataObjectVisualizationFilter::Pointer visualizer = mitk::NavigationDataObjectVisualizationFilter::New();
visualizer->SetInput(0, source->GetOutput());
visualizer->SetRepresentationObject(0, cone.GetPointer());

The fixed object is created accordingly, with a cylindrical shape and red color. As it is not tracked, we define an initial position and orientation, set it to the cylinder object and also store it as fixedNavigationData for later usage. As the object is not continuously updated, we don't need a visualization filter.

//Cylinder representation for rendering of the fixed object
cylinderNode->SetName("My fixed object");
cylinderNode->SetColor(1.0, 0.0, 0.0);
//Define a rotation and a translation for the fixed object
mitk::Matrix3D rotationMatrix;
double alpha = 0.3;
rotationMatrix[1][1] = cos(alpha);
rotationMatrix[1][2] = -sin(alpha);
rotationMatrix[2][1] = sin(alpha);
rotationMatrix[2][2] = cos(alpha);
//Add rotation and translation to affine transform
mitk::AffineTransform3D::Pointer affineTransform3D = mitk::AffineTransform3D::New();
//apply rotation and translation
mitk::NavigationData::Pointer fixedNavigationData = mitk::NavigationData::New(affineTransform3D);

The Tracking loop

Before we start tracking, we need to initialize the rendering manager.

// Global reinit with the bounds of the virtual tracking device
auto timeGeometry = dataStorage->ComputeBoundingGeometry3D(dataStorage->GetAll());
mitk::BaseGeometry::Pointer geometry = timeGeometry->GetGeometryForTimeStep(0);

We now move the tracked blue cone object for 75 steps, update the rendering and print the position to the output console.

//Generate and render 75 time steps to move the tracked object
for (int i = 0; i < 75; ++i)
//Update the cone position
//Update rendering
MITK_INFO << "Position " << source->GetOutput()->GetPosition();
//Slight delay for the random numbers
//Stop the tracking device and disconnect it
//The tracking is done, now we want to move the fixed object to its correct relative position regarding the tracked object.

Final Transform

Finally, we apply the new position of the tracked object (source->GetOutput) to the stored fixedNavigationData transform and update the rendering one last time.

//Now the tracking is finished and we can use the transformation to move
//the fixed object to its correct position relative to the new position
//of the moving/tracked object. Therefore, we compose the navigation datas.
fixedNavigationData->Compose(source->GetOutput(), false);
//Update the transformation matrix of the cylinder
//Update the rendering
//Wait a little before closing the renderwindow

The red cylinder is now moved accodring to the tracked transform.

Return to the [IGT Tutorial Overview]

static RenderingManager * GetInstance()
virtual bool InitializeViews(const BaseGeometry *geometry, RequestType type=REQUEST_UPDATE_ALL, bool resetCamera=true)
Initialize the render windows specified by "type" to the given geometry.
static Pointer New()
#define MITK_INFO
Definition: mitkLogMacros.h:18
itk::SmartPointer< Self >
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
@ Standard3D
Definition: mitkBaseRenderer.h:68
static Pointer New()
mitk::Vector< ScalarType, 3 >
Definition: mitkMatrix.h:25
static Pointer New()
static Pointer New()
static Pointer New()
static Pointer New()
static Pointer New()
static Pointer New()
static Pointer New()
double ScalarType
Definition: mitkNumericConstants.h:20