Medical Imaging Interaction Toolkit  2023.12.00
Medical Imaging Interaction Toolkit
MITK Tutorial - Step 9: A plug-in

MITK uses a very modular concept to maximize reusability and portability. A MITK application based on the BlueBerry application framework (for example the MITK Workbench) consists of several bundles (or plug-ins). A bundle can contain resources and program logic. It can also contribute so-called Views to the main application, which provide a specific user interface for controlling the bundles functions.

documentation\doxygen\
  modules.dox......................... Doxygen file for documenting your plug-in

resources\
  icon.png............................ The icon of your plug-in. GIMP or other programs (including your text editor)
                                       can be used to change this

src\internal\
  QmitkRegionGrowingView.cpp.......... The most important file, implementing behaviour
  QmitkRegionGrowingView.h............ Header file of the functionality
  QmitkRegionGrowingViewControls.ui... XML file of the Qt Designer, describes buttons, combo boxes, etc. of your controls

CMakeLists.txt \...................... Build system related files for CMake
files.cmake    /
manifest_headers.cmake................ Information about your plug-in
plugin.xml ........................... BlueBerry integration

If you are not familiar with Qt development, please look into this Qt company page describing .ui files

The C++ files implement a subclass of QmitkAbstractView. In this special case of QmitkRegionGrowing, we added the option to set some seed points and run a region grower. If you are interested in the concrete changes necessary to turn a freshly generated QmitkRegionGrowing into an integrated one:

The plug-in will be build as part of MITK Workbench. Do use it start MITK Workbench an select the region growing view in the view menu.

To add a mitk::PointSet for the seed points: QmitkRegionGrowingView.h

Add includes and forward declarations:

#include "mitkPointSet.h"
#include <itkImage.h>

Add the point set and a pointer to a QmitkPointListWidget as a private member:

QmitkPointListWidget *m_PointListWidget;

QmitkRegionGrowingView.cpp

CreateQtPartControl():

// create a QmitkPointListWidget and add it to the widget created from .ui file
m_PointListWidget = new QmitkPointListWidget();
m_Controls.verticalLayout->addWidget(m_PointListWidget, 1);
// retrieve a possibly existing IRenderWindowPart
if (mitk::IRenderWindowPart *renderWindowPart = GetRenderWindowPart())
{
// let the point set widget know about the render window part (crosshair updates)
RenderWindowPartActivated(renderWindowPart);
}
// create a new DataNode containing a PointSet with some interaction
m_PointSet = mitk::PointSet::New();
pointSetNode->SetData(m_PointSet);
pointSetNode->SetName("seed points for region growing");
pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true));
pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024));
// add the pointset to the data storage (for rendering and access by other modules)
GetDataStorage()->Add(pointSetNode);
// tell the GUI widget about the point set
m_PointListWidget->SetPointSetNode(pointSetNode);

To use the ITK region grower:

QmitkRegionGrowingView.h

Add the private method:

template <typename TPixel, unsigned int VImageDimension>
void ItkImageProcessing(itk::Image<TPixel, VImageDimension> *itkImage, mitk::BaseGeometry *imageGeometry);

QmitkRegionGrowingView.cpp

Add includes:

// Qmitk
// MITK
#include "mitkImageCast.h"
#include "mitkProperties.h"
// ITK
#include <itkConnectedThresholdImageFilter.h>

DoImageProcessing():

// So we have an image. Let's see if the user has set some seed points already
if (m_PointSet->GetSize() == 0)
{
// no points there. Not good for region growing
QMessageBox::information(nullptr,
"Region growing functionality",
"Please set some seed points inside the image first.\n"
"(hold Shift key and click left mouse button inside the image.)");
return;
}
// actually perform region growing. Here we have both an image and some seed points
image, ItkImageProcessing, image->GetGeometry()) // some magic to call the correctly templated function

And add the new method:

template <typename TPixel, unsigned int VImageDimension>
void QmitkRegionGrowingView::ItkImageProcessing(itk::Image<TPixel, VImageDimension> *itkImage,
mitk::BaseGeometry *imageGeometry)
{
typedef itk::Image<TPixel, VImageDimension> InputImageType;
typedef typename InputImageType::IndexType IndexType;
// instantiate an ITK region growing filter, set its parameters
typedef itk::ConnectedThresholdImageFilter<InputImageType, InputImageType> RegionGrowingFilterType;
typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New();
regionGrower->SetInput(itkImage); // don't forget this
// determine a thresholding interval
IndexType seedIndex;
TPixel min(std::numeric_limits<TPixel>::max());
TPixel max(std::numeric_limits<TPixel>::min());
mitk::PointSet::PointsContainer *points = m_PointSet->GetPointSet()->GetPoints();
for (mitk::PointSet::PointsConstIterator pointsIterator = points->Begin(); pointsIterator != points->End();
++pointsIterator)
{
// first test if this point is inside the image at all
if (!imageGeometry->IsInside(pointsIterator.Value()))
{
continue;
}
// convert world coordinates to image indices
imageGeometry->WorldToIndex(pointsIterator.Value(), seedIndex);
// get the pixel value at this point
TPixel currentPixelValue = itkImage->GetPixel(seedIndex);
// adjust minimum and maximum values
if (currentPixelValue > max)
max = currentPixelValue;
if (currentPixelValue < min)
min = currentPixelValue;
regionGrower->AddSeed(seedIndex);
}
MITK_INFO << "Values between " << min << " and " << max;
min -= 30;
max += 30;
// set thresholds and execute filter
regionGrower->SetLower(min);
regionGrower->SetUpper(max);
regionGrower->Update();
mitk::Image::Pointer resultImage;
mitk::CastToMitkImage(regionGrower->GetOutput(), resultImage);
newNode->SetData(resultImage);
// set some properties
newNode->SetProperty("binary", mitk::BoolProperty::New(true));
newNode->SetProperty("name", mitk::StringProperty::New("dumb segmentation"));
newNode->SetProperty("color", mitk::ColorProperty::New(1.0, 0.0, 0.0));
newNode->SetProperty("volumerendering", mitk::BoolProperty::New(true));
newNode->SetProperty("layer", mitk::IntProperty::New(1));
newNode->SetProperty("opacity", mitk::FloatProperty::New(0.5));
// add result to data tree
this->GetDataStorage()->Add(newNode);
}

Have fun using MITK!

If you meet any difficulties during your first steps, don't hesitate to ask on the MITK mailing list mitk-.nosp@m.user.nosp@m.s@lis.nosp@m.ts.s.nosp@m.ource.nosp@m.forg.nosp@m.e.net! People there are kind and will try to help you.

[Previous step] [Next Step] [Main tutorial page]

QmitkPointListWidget
Widget for regular operations on point sets.
Definition: QmitkPointListWidget.h:51
mitk::RenderingManager::GetInstance
static RenderingManager * GetInstance()
MITK_INFO
#define MITK_INFO
Definition: mitkLog.h:209
mitk::PointSet::PointsConstIterator
DataType::PointsContainer::ConstIterator PointsConstIterator
Definition: mitkPointSet.h:132
mitkImageCast.h
mitkImageAccessByItk.h
mitk::IntProperty::New
static Pointer New()
QmitkPointListWidget::SetPointSetNode
void SetPointSetNode(mitk::DataNode *newNode)
assign a point set (contained in a node of DataStorage) for observation
mitk::FloatProperty::New
static Pointer New()
itk::SmartPointer< Self >
mitk::PointSet::New
static Pointer New()
QmitkPointListWidget::QmitkPointListWidget
QmitkPointListWidget(QWidget *parent=nullptr, int orientation=0)
mitk::RenderingManager::RequestUpdateAll
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
mitk::StringProperty::New
static Pointer New()
mitk::CastToMitkImage
void CastToMitkImage(const itk::SmartPointer< ItkOutputImageType > &itkimage, itk::SmartPointer< mitk::Image > &mitkoutputimage)
Cast an itk::Image (with a specific type) to an mitk::Image.
Definition: mitkImageCast.h:74
mitkPointSet.h
mitk::ImageMappingHelper::InputImageType
::mitk::Image InputImageType
Definition: mitkImageMappingHelper.h:47
mitk::IRenderWindowPart
Interface for a MITK Workbench Part providing a render window.
Definition: mitkIRenderWindowPart.h:54
mitk::BaseGeometry
BaseGeometry Describes the geometry of a data object.
Definition: mitkBaseGeometry.h:94
AccessByItk_1
#define AccessByItk_1(mitkImage, itkImageTypeFunction, arg1)
Definition: mitkImageAccessByItk.h:565
mitkITKImageImport.h
mitk::PointSet::PointsContainer
DataType::PointsContainer PointsContainer
Definition: mitkPointSet.h:130
mitk::BaseGeometry::WorldToIndex
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
mitk::BoolProperty::New
static Pointer New()
mitkColorProperty.h
QmitkPointListWidget.h
mitk::ColorProperty::New
static Pointer New()
mitkProperties.h
mitk::DataNode::New
static Pointer New()
mitk::BaseGeometry::IsInside
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
QmitkRenderWindow.h
mitkIRenderWindowPartListener.h