Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
mitkShowSegmentationAsSmoothedSurface.cpp
Go to the documentation of this file.
1 /*===================================================================
2 
3 The Medical Imaging Interaction Toolkit (MITK)
4 
5 Copyright (c) German Cancer Research Center,
6 Division of Medical and Biological Informatics.
7 All rights reserved.
8 
9 This software is distributed WITHOUT ANY WARRANTY; without
10 even the implied warranty of MERCHANTABILITY or FITNESS FOR
11 A PARTICULAR PURPOSE.
12 
13 See LICENSE.txt or http://www.mitk.org for details.
14 
15 ===================================================================*/
16 
19 #include "mitkImageCast.h"
20 #include "mitkImageToItk.h"
21 #include <itkAddImageFilter.h>
22 #include <itkBinaryMedianImageFilter.h>
23 #include <itkBinaryThresholdImageFilter.h>
24 #include <itkConnectedThresholdImageFilter.h>
25 #include <itkConstantPadImageFilter.h>
26 #include <itkDiscreteGaussianImageFilter.h>
27 #include <itkImageRegionIteratorWithIndex.h>
28 #include <itkMultiplyImageFilter.h>
29 #include <itkRegionOfInterestImageFilter.h>
30 #include <mitkGeometry3D.h>
31 #include <mitkImageTimeSelector.h>
33 #include <mitkProgressBar.h>
34 #include <mitkStatusBar.h>
35 #include <mitkUIDGenerator.h>
37 #include <vtkCleanPolyData.h>
38 #include <vtkPolyDataNormals.h>
39 #include <vtkQuadricDecimation.h>
40 
41 using namespace mitk;
42 using namespace std;
43 
44 ShowSegmentationAsSmoothedSurface::ShowSegmentationAsSmoothedSurface()
45 {
46 }
47 
48 ShowSegmentationAsSmoothedSurface::~ShowSegmentationAsSmoothedSurface()
49 {
50 }
51 
53 {
54  Superclass::Initialize(other);
55 
56  bool syncVisibility = false;
57 
58  if (other != nullptr)
59  other->GetParameter("Sync visibility", syncVisibility);
60 
61  SetParameter("Sync visibility", syncVisibility);
62  SetParameter("Wireframe", false);
63 
64  // The Smoothing value is used as variance for a Gauss filter.
65  // A reasonable default value equals the image spacing in mm.
66  SetParameter("Smoothing", 1.0f);
67 
68  // Valid range for decimation value is [0, 1). High values
69  // increase decimation, especially when very close to 1.
70  // A value of 0 disables decimation.
71  SetParameter("Decimation", 0.5f);
72 
73  // Valid range for closing value is [0, 1]. Higher values
74  // increase closing. A value of 0 disables closing.
75  SetParameter("Closing", 0.0f);
76 }
77 
79 {
80  try
81  {
83  GetPointerParameter("Input", image);
84 
85  return image.IsNotNull() && GetGroupNode();
86  }
87  catch (const invalid_argument &)
88  {
89  return false;
90  }
91 }
92 
94 {
95  Image::Pointer image;
96  GetPointerParameter("Input", image);
97 
98  float smoothing;
99  GetParameter("Smoothing", smoothing);
100 
101  float decimation;
102  GetParameter("Decimation", decimation);
103 
104  float closing;
105  GetParameter("Closing", closing);
106 
107  int timeNr = 0;
108  GetParameter("TimeNr", timeNr);
109 
110  if (image->GetDimension() == 4)
111  MITK_INFO << "CREATING SMOOTHED POLYGON MODEL (t = " << timeNr << ')';
112  else
113  MITK_INFO << "CREATING SMOOTHED POLYGON MODEL";
114 
115  MITK_INFO << " Smoothing = " << smoothing;
116  MITK_INFO << " Decimation = " << decimation;
117  MITK_INFO << " Closing = " << closing;
118 
119  Geometry3D::Pointer geometry = dynamic_cast<Geometry3D *>(image->GetGeometry()->Clone().GetPointer());
120 
121  // Make ITK image out of MITK image
122 
123  typedef itk::Image<unsigned char, 3> CharImageType;
124  typedef itk::Image<unsigned short, 3> ShortImageType;
125  typedef itk::Image<float, 3> FloatImageType;
126 
127  if (image->GetDimension() == 4)
128  {
130  imageTimeSelector->SetInput(image);
131  imageTimeSelector->SetTimeNr(timeNr);
132  imageTimeSelector->UpdateLargestPossibleRegion();
133  image = imageTimeSelector->GetOutput(0);
134  }
135 
137 
138  try
139  {
140  imageToItkFilter->SetInput(image);
141  }
142  catch (const itk::ExceptionObject &e)
143  {
144  // Most probably the input image type is wrong. Binary images are expected to be
145  // >unsigned< char images.
146  MITK_ERROR << e.GetDescription() << endl;
147  return false;
148  }
149 
150  imageToItkFilter->Update();
151 
152  CharImageType::Pointer itkImage = imageToItkFilter->GetOutput();
153 
154  // Get bounding box and relabel
155 
156  MITK_INFO << "Extracting VOI...";
157 
158  int imageLabel = 1;
159  bool roiFound = false;
160 
161  CharImageType::IndexType minIndex;
163 
164  CharImageType::IndexType maxIndex;
166 
167  itk::ImageRegionIteratorWithIndex<CharImageType> iter(itkImage, itkImage->GetLargestPossibleRegion());
168 
169  for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter)
170  {
171  if (iter.Get() == imageLabel)
172  {
173  roiFound = true;
174  iter.Set(1);
175 
176  CharImageType::IndexType currentIndex = iter.GetIndex();
177 
178  for (unsigned int dim = 0; dim < 3; ++dim)
179  {
180  minIndex[dim] = min(currentIndex[dim], minIndex[dim]);
181  maxIndex[dim] = max(currentIndex[dim], maxIndex[dim]);
182  }
183  }
184  else
185  {
186  iter.Set(0);
187  }
188  }
189 
190  if (!roiFound)
191  {
193  MITK_ERROR << "Didn't found segmentation labeled with " << imageLabel << "!" << endl;
194  return false;
195  }
196 
198 
199  // Extract and pad bounding box
200 
201  typedef itk::RegionOfInterestImageFilter<CharImageType, CharImageType> ROIFilterType;
202 
204  CharImageType::RegionType region;
205  CharImageType::SizeType size;
206 
207  for (unsigned int dim = 0; dim < 3; ++dim)
208  {
209  size[dim] = maxIndex[dim] - minIndex[dim] + 1;
210  }
211 
212  region.SetIndex(minIndex);
213  region.SetSize(size);
214 
215  roiFilter->SetInput(itkImage);
216  roiFilter->SetRegionOfInterest(region);
217  roiFilter->ReleaseDataFlagOn();
218  roiFilter->ReleaseDataBeforeUpdateFlagOn();
219 
220  typedef itk::ConstantPadImageFilter<CharImageType, CharImageType> PadFilterType;
221 
223  const PadFilterType::SizeValueType pad[3] = {10, 10, 10};
224 
225  padFilter->SetInput(roiFilter->GetOutput());
226  padFilter->SetConstant(0);
227  padFilter->SetPadLowerBound(pad);
228  padFilter->SetPadUpperBound(pad);
229  padFilter->ReleaseDataFlagOn();
230  padFilter->ReleaseDataBeforeUpdateFlagOn();
231  padFilter->Update();
232 
233  CharImageType::Pointer roiImage = padFilter->GetOutput();
234 
235  roiImage->DisconnectPipeline();
236  roiFilter = nullptr;
237  padFilter = nullptr;
238 
239  // Correct origin of real geometry (changed by cropping and padding)
240 
241  typedef Geometry3D::TransformType TransformType;
242 
244  TransformType::OutputVectorType translation;
245 
246  for (unsigned int dim = 0; dim < 3; ++dim)
247  translation[dim] = (int)minIndex[dim] - (int)pad[dim];
248 
249  transform->SetIdentity();
250  transform->Translate(translation);
251  geometry->Compose(transform, true);
252 
254 
255  // Median
256 
257  MITK_INFO << "Median...";
258 
259  typedef itk::BinaryMedianImageFilter<CharImageType, CharImageType> MedianFilterType;
260 
262  CharImageType::SizeType radius = {0};
263 
264  medianFilter->SetRadius(radius);
265  medianFilter->SetBackgroundValue(0);
266  medianFilter->SetForegroundValue(1);
267  medianFilter->SetInput(roiImage);
268  medianFilter->ReleaseDataFlagOn();
269  medianFilter->ReleaseDataBeforeUpdateFlagOn();
270  medianFilter->Update();
271 
273 
274  // Intelligent closing
275 
276  MITK_INFO << "Intelligent closing...";
277 
278  unsigned int surfaceRatio = (unsigned int)((1.0f - closing) * 100.0f);
279 
281 
283 
284  closingFilter->SetInput(medianFilter->GetOutput());
285  closingFilter->ReleaseDataFlagOn();
286  closingFilter->ReleaseDataBeforeUpdateFlagOn();
287  closingFilter->SetSurfaceRatio(surfaceRatio);
288  closingFilter->Update();
289 
290  ShortImageType::Pointer closedImage = closingFilter->GetOutput();
291 
292  closedImage->DisconnectPipeline();
293  roiImage = nullptr;
294  medianFilter = nullptr;
295  closingFilter = nullptr;
296 
298 
299  // Gaussian blur
300 
301  MITK_INFO << "Gauss...";
302 
303  typedef itk::BinaryThresholdImageFilter<ShortImageType, FloatImageType> BinaryThresholdToFloatFilterType;
304 
306 
307  binThresToFloatFilter->SetInput(closedImage);
308  binThresToFloatFilter->SetLowerThreshold(1);
309  binThresToFloatFilter->SetUpperThreshold(1);
310  binThresToFloatFilter->SetInsideValue(100);
311  binThresToFloatFilter->SetOutsideValue(0);
312  binThresToFloatFilter->ReleaseDataFlagOn();
313  binThresToFloatFilter->ReleaseDataBeforeUpdateFlagOn();
314 
315  typedef itk::DiscreteGaussianImageFilter<FloatImageType, FloatImageType> GaussianFilterType;
316 
317  // From the following line on, IntelliSense (VS 2008) is broken. Any idea how to fix it?
319 
320  gaussFilter->SetInput(binThresToFloatFilter->GetOutput());
321  gaussFilter->SetUseImageSpacing(true);
322  gaussFilter->SetVariance(smoothing);
323  gaussFilter->ReleaseDataFlagOn();
324  gaussFilter->ReleaseDataBeforeUpdateFlagOn();
325 
326  typedef itk::BinaryThresholdImageFilter<FloatImageType, CharImageType> BinaryThresholdFromFloatFilterType;
327 
329 
330  binThresFromFloatFilter->SetInput(gaussFilter->GetOutput());
331  binThresFromFloatFilter->SetLowerThreshold(50);
332  binThresFromFloatFilter->SetUpperThreshold(255);
333  binThresFromFloatFilter->SetInsideValue(1);
334  binThresFromFloatFilter->SetOutsideValue(0);
335  binThresFromFloatFilter->ReleaseDataFlagOn();
336  binThresFromFloatFilter->ReleaseDataBeforeUpdateFlagOn();
337  binThresFromFloatFilter->Update();
338 
339  CharImageType::Pointer blurredImage = binThresFromFloatFilter->GetOutput();
340 
341  blurredImage->DisconnectPipeline();
342  closedImage = nullptr;
343  binThresToFloatFilter = nullptr;
344  gaussFilter = nullptr;
345 
347 
348  // Fill holes
349 
350  MITK_INFO << "Filling cavities...";
351 
352  typedef itk::ConnectedThresholdImageFilter<CharImageType, CharImageType> ConnectedThresholdFilterType;
353 
355 
356  CharImageType::IndexType corner;
357 
358  corner[0] = 0;
359  corner[1] = 0;
360  corner[2] = 0;
361 
362  connectedThresFilter->SetInput(blurredImage);
363  connectedThresFilter->SetSeed(corner);
364  connectedThresFilter->SetLower(0);
365  connectedThresFilter->SetUpper(0);
366  connectedThresFilter->SetReplaceValue(2);
367  connectedThresFilter->ReleaseDataFlagOn();
368  connectedThresFilter->ReleaseDataBeforeUpdateFlagOn();
369 
370  typedef itk::BinaryThresholdImageFilter<CharImageType, CharImageType> BinaryThresholdFilterType;
371 
373 
374  binThresFilter->SetInput(connectedThresFilter->GetOutput());
375  binThresFilter->SetLowerThreshold(0);
376  binThresFilter->SetUpperThreshold(0);
377  binThresFilter->SetInsideValue(50);
378  binThresFilter->SetOutsideValue(0);
379  binThresFilter->ReleaseDataFlagOn();
380  binThresFilter->ReleaseDataBeforeUpdateFlagOn();
381 
382  typedef itk::AddImageFilter<CharImageType, CharImageType, CharImageType> AddFilterType;
383 
385 
386  addFilter->SetInput1(blurredImage);
387  addFilter->SetInput2(binThresFilter->GetOutput());
388  addFilter->ReleaseDataFlagOn();
389  addFilter->ReleaseDataBeforeUpdateFlagOn();
390  addFilter->Update();
391 
393 
394  // Surface extraction
395 
396  MITK_INFO << "Surface extraction...";
397 
398  Image::Pointer filteredImage = Image::New();
399  CastToMitkImage(addFilter->GetOutput(), filteredImage);
400 
401  filteredImage->SetGeometry(geometry);
402 
404 
405  imageToSurfaceFilter->SetInput(filteredImage);
406  imageToSurfaceFilter->SetThreshold(50);
407  imageToSurfaceFilter->SmoothOn();
408  imageToSurfaceFilter->SetDecimate(ImageToSurfaceFilter::NoDecimation);
409 
410  m_Surface = imageToSurfaceFilter->GetOutput(0);
411 
413 
414  // Mesh decimation
415 
416  if (decimation > 0.0f && decimation < 1.0f)
417  {
418  MITK_INFO << "Quadric mesh decimation...";
419 
420  vtkQuadricDecimation *quadricDecimation = vtkQuadricDecimation::New();
421  quadricDecimation->SetInputData(m_Surface->GetVtkPolyData());
422  quadricDecimation->SetTargetReduction(decimation);
423  quadricDecimation->AttributeErrorMetricOn();
424  quadricDecimation->GlobalWarningDisplayOff();
425  quadricDecimation->Update();
426 
427  vtkCleanPolyData *cleaner = vtkCleanPolyData::New();
428  cleaner->SetInputConnection(quadricDecimation->GetOutputPort());
429  cleaner->PieceInvariantOn();
430  cleaner->ConvertLinesToPointsOn();
431  cleaner->ConvertStripsToPolysOn();
432  cleaner->PointMergingOn();
433  cleaner->Update();
434 
435  m_Surface->SetVtkPolyData(cleaner->GetOutput());
436  }
437 
439 
440  // Compute Normals
441 
442  vtkPolyDataNormals *computeNormals = vtkPolyDataNormals::New();
443  computeNormals->SetInputData(m_Surface->GetVtkPolyData());
444  computeNormals->SetFeatureAngle(360.0f);
445  computeNormals->AutoOrientNormalsOn();
446  computeNormals->FlipNormalsOff();
447  computeNormals->Update();
448 
449  m_Surface->SetVtkPolyData(computeNormals->GetOutput());
450 
451  return true;
452 }
453 
455 {
457 
458  bool wireframe = false;
459  GetParameter("Wireframe", wireframe);
460 
461  if (wireframe)
462  {
463  VtkRepresentationProperty *representation =
464  dynamic_cast<VtkRepresentationProperty *>(node->GetProperty("material.representation"));
465 
466  if (representation != nullptr)
467  representation->SetRepresentationToWireframe();
468  }
469 
470  node->SetProperty("opacity", FloatProperty::New(1.0));
471  node->SetProperty("line width", IntProperty::New(1));
472  node->SetProperty("scalar visibility", BoolProperty::New(false));
473 
474  std::string groupNodeName = "surface";
475  DataNode *groupNode = GetGroupNode();
476 
477  if (groupNode != nullptr)
478  groupNode->GetName(groupNodeName);
479 
480  node->SetProperty("name", StringProperty::New(groupNodeName));
481  node->SetData(m_Surface);
482 
483  BaseProperty *colorProperty = groupNode->GetProperty("color");
484 
485  if (colorProperty != nullptr)
486  node->ReplaceProperty("color", colorProperty->Clone());
487  else
488  node->SetProperty("color", ColorProperty::New(1.0f, 0.0f, 0.0f));
489 
490  bool showResult = true;
491  GetParameter("Show result", showResult);
492 
493  bool syncVisibility = false;
494  GetParameter("Sync visibility", syncVisibility);
495 
496  Image::Pointer image;
497  GetPointerParameter("Input", image);
498 
499  BaseProperty *organTypeProperty = image->GetProperty("organ type");
500 
501  if (organTypeProperty != nullptr)
502  m_Surface->SetProperty("organ type", organTypeProperty);
503 
504  BaseProperty *visibleProperty = groupNode->GetProperty("visible");
505 
506  if (visibleProperty != nullptr && syncVisibility)
507  node->ReplaceProperty("visible", visibleProperty->Clone());
508  else
509  node->SetProperty("visible", BoolProperty::New(showResult));
510 
511  InsertBelowGroupNode(node);
512 
513  Superclass::ThreadedUpdateSuccessful();
514 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
itk::SmartPointer< Self > Pointer
Standard implementation of BaseGeometry.
#define MITK_INFO
Definition: mitkLogMacros.h:22
#define MITK_ERROR
Definition: mitkLogMacros.h:24
static Pointer New()
bool GetName(std::string &nodeName, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="name") const
Convenience access method for accessing the name of an object (instance of StringProperty with proper...
Definition: mitkDataNode.h:366
GeometryTransformHolder::TransformType TransformType
STL namespace.
DataCollection - Class to facilitate loading/accessing structured data.
itk::Image< double, 3 > FloatImageType
Definition: CLBrainMask.cpp:35
mitk::BaseProperty * GetProperty(const char *propertyKey, const mitk::BaseRenderer *renderer=nullptr) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList of the rendere...
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
static Pointer New()
Abstract base class for properties.
static Pointer New()
static T max(T x, T y)
Definition: svm.cpp:70
static Pointer New()
static Pointer New()
static T min(T x, T y)
Definition: svm.cpp:67
static Pointer New()
Pointer Clone() const
static Pointer New()
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:78
void Initialize(const NonBlockingAlgorithm *other=nullptr) override
static Pointer New()
void GetParameter(const char *parameter, T &value) const
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static Pointer New()
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.