Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
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.