Page MenuHomePhabricator

Implement robust, easy-to-use ExtractSliceFilter
Closed, ResolvedPublic

Description

mitk::ExtractSliceFilter has many quirks and some complex geometry-related bugs that really give you a hard time using the filter. We need a robust, easy-to-use alternative.

Related Objects

Event Timeline

kislinsk triaged this task as Normal priority.Dec 18 2017, 6:59 AM
kislinsk created this task.
This comment was removed by kislinsk.
This comment was removed by kislinsk.
kislinsk renamed this task from Implement robust, easy-to-use ResliceImageFilter to Implement robust, easy-to-use ExtractSliceFilter.Jan 12 2018, 2:47 PM

This is some code from a plugin that I used for testing mitk::ExtractSliceFilter2:

void QmitkTestView::OnButtonClicked()
{
  mitk::DataNode::Pointer selectedNode = m_Controls.imageComboBox->GetSelectedNode();
  mitk::Image::Pointer image = dynamic_cast<mitk::Image*>(selectedNode->GetData());

  auto predicate = mitk::NodePredicateFunction::New([](const mitk::DataNode *node) {
    return "stdmulti.widget1.plane" == node->GetName();
  });

  auto planeNode = this->GetDataStorage()->GetNode(predicate);
  mitk::PlaneGeometryData::Pointer plane = dynamic_cast<mitk::PlaneGeometryData*>(planeNode->GetData());

  auto planeGeometry = plane->GetPlaneGeometry()->Clone();
  planeGeometry->SetImageGeometry(true);

  auto extractSliceFilter = mitk::ExtractSliceFilter2::New();
  extractSliceFilter->SetInput(image);
  extractSliceFilter->SetOutputGeometry(planeGeometry);

  try
  {
    extractSliceFilter->Update();
  }
  catch(const mitk::Exception& exception)
  {
    MITK_ERROR << exception.GetDescription();
    return;
  }

  mitk::Image::Pointer slice = extractSliceFilter->GetOutput();

  mitk::DataNode::Pointer newNode = mitk::DataNode::New();
  newNode->SetData(slice);
  newNode->SetName("Slice");
  newNode->SetColor(0.0f, 1.0f, 0.0f);

  mitk::LevelWindow levelWindow;
  selectedNode->GetLevelWindow(levelWindow);
  newNode->SetLevelWindow(levelWindow);

  this->GetDataStorage()->Add(newNode, selectedNode);
}
WARNING: Even though you can change the default interpolator of the filter from nearst neighbor to linear or cubic, you should not do so for segmentations as it will result in fake interpolation artifacts at the segmentation borders and you would have to apply a binary threshold to receive a valid segmentation.

The filter is not as fast as the VTK-based mitk::ExtractSliceFilter and is not designed for high perfomance scenarios. It is robust and easy-to-use, though. Pixels of the output image that do not intersect with the input image are set to the lowest possible value.

Compile errors with Visual Studio 2015:

mitkExtractSliceFilter2.cpp(215): error C2672: 'CreateInterpolateImageFunction': no matching overloaded function found
mitkExtractSliceFilter2.cpp(223): error C2672: '`anonymous-namespace'::GenerateData': no matching overloaded function found

Moving the template functions out of the anonymous namespace didn't help. I have to investigate on the dart client to get an idea of the actual problem here...

Visual Studio 2015 can't handle pointers to nested classes as template function parameters in certain cases.

Currently I am writing a test for the new mitk::ExtractSliceFilter2 class and I noticed that the interpolation results do not match the expected results. They do match the mitk::ExtractSliceFilter VTK output, though, which leads to the assumption, that the latter needs to be corrected as well.

Tested linear interpolator so far and it seems that the half output spacing, which I am subtracting from the origin for the interpolate image function is wrong. I should leave the origin as it is but I need to be really aware of the center based coordinates of images. For example, imagine an image at origin (2, 2, 2) with spacing (1, 1, 1). And I want to perfectly align the output geometry to sample with spacing (2, 2, 2), its origin must be (2.5, 2.5, 2.5).

Okay, fixed. I leave this task open until I finished the test.