Medical Imaging Interaction Toolkit  2016.11.0
Medical Imaging Interaction Toolkit
QmitkAdaptiveRegionGrowingToolGUI.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 ===================================================================*/
17 
18 #include "QmitkStdMultiWidget.h"
19 
20 #include <qmessagebox.h>
21 
22 #include "mitkITKImageImport.h"
23 #include "mitkImageAccessByItk.h"
24 #include "mitkImageTimeSelector.h"
26 #include "mitkProperties.h"
28 
30 
31 #include "itkMaskImageFilter.h"
32 #include "itkNumericTraits.h"
33 #include <itkBinaryThresholdImageFilter.h>
35 #include <itkImageIterator.h>
36 #include <itkMinimumMaximumImageCalculator.h>
37 
39 #include "itkOrImageFilter.h"
40 #include "mitkImageCast.h"
41 
43 #include "mitkPixelTypeMultiplex.h"
44 
45 #include "mitkImageCast.h"
46 
48 
50  : QmitkToolGUI(),
51  m_MultiWidget(nullptr),
52  m_DataStorage(nullptr),
53  m_UseVolumeRendering(false),
54  m_UpdateSuggestedThreshold(true),
55  m_SuggestedThValue(0.0)
56 {
57  this->setParent(parent);
58 
59  m_Controls.setupUi(this);
60 
61  m_Controls.m_ThresholdSlider->setDecimals(1);
62  m_Controls.m_ThresholdSlider->setSpinBoxAlignment(Qt::AlignVCenter);
63 
64  m_Controls.m_PreviewSlider->setEnabled(false);
65  m_Controls.m_PreviewSlider->setSingleStep(0.5);
66  // Not yet available
67  // m_Controls.m_PreviewSlider->InvertedAppearance(true);
68 
69  this->CreateConnections();
70  this->SetDataNodeNames("labeledRGSegmentation", "RGResult", "RGFeedbackSurface", "maskedSegmentation");
71 
72  connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *)));
73 }
74 
76 {
77  // Removing the observer of the PointSet node
78  if (m_RegionGrow3DTool->GetPointSetNode().IsNotNull())
79  {
80  m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetAddObserverTag);
81  m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetMoveObserverTag);
82  }
83  this->RemoveHelperNodes();
84 }
85 
87 {
89  if (m_RegionGrow3DTool.IsNotNull())
90  {
91  SetInputImageNode(this->m_RegionGrow3DTool->GetReferenceData());
92  this->m_DataStorage = this->m_RegionGrow3DTool->GetDataStorage();
93  this->EnableControls(true);
94 
95  // Watch for point added or modified
98  pointAddedCommand->SetCallbackFunction(this, &QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded);
99  m_PointSetAddObserverTag =
100  m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand);
101  m_PointSetMoveObserverTag =
102  m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand);
103  }
104  else
105  {
106  this->EnableControls(false);
107  }
108 }
109 
110 void QmitkAdaptiveRegionGrowingToolGUI::RemoveHelperNodes()
111 {
112  mitk::DataNode::Pointer imageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
113  if (imageNode.IsNotNull())
114  {
115  m_DataStorage->Remove(imageNode);
116  }
117 
118  mitk::DataNode::Pointer maskedSegmentationNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
119  if (maskedSegmentationNode.IsNotNull())
120  {
121  m_DataStorage->Remove(maskedSegmentationNode);
122  }
123 }
124 
126 {
127  // Connecting GUI components
128  connect((QObject *)(m_Controls.m_pbRunSegmentation), SIGNAL(clicked()), this, SLOT(RunSegmentation()));
129  connect(m_Controls.m_PreviewSlider, SIGNAL(valueChanged(double)), this, SLOT(ChangeLevelWindow(double)));
130  connect((QObject *)(m_Controls.m_pbConfirmSegementation), SIGNAL(clicked()), this, SLOT(ConfirmSegmentation()));
131  connect((QObject *)(m_Controls.m_cbVolumeRendering), SIGNAL(toggled(bool)), this, SLOT(UseVolumeRendering(bool)));
132  connect(
133  m_Controls.m_ThresholdSlider, SIGNAL(maximumValueChanged(double)), this, SLOT(SetUpperThresholdValue(double)));
134  connect(
135  m_Controls.m_ThresholdSlider, SIGNAL(minimumValueChanged(double)), this, SLOT(SetLowerThresholdValue(double)));
136 }
137 
138 void QmitkAdaptiveRegionGrowingToolGUI::SetDataNodeNames(std::string labledSegmentation,
139  std::string binaryImage,
140  std::string surface,
141  std::string maskedSegmentation)
142 {
143  m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation;
144  m_NAMEFORBINARYIMAGE = binaryImage;
145  m_NAMEFORSURFACE = surface;
146  m_NAMEFORMASKEDSEGMENTATION = maskedSegmentation;
147 }
148 
150 {
151  m_DataStorage = dataStorage;
152 }
153 
155 {
156  m_MultiWidget = multiWidget;
157 }
158 
160 {
161  m_InputImageNode = node;
162  mitk::Image *inputImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
163  if (inputImage)
164  {
167  m_Controls.m_ThresholdSlider->setMaximum(max);
168  m_Controls.m_ThresholdSlider->setMinimum(min);
169  // Just for initialization
170  m_Controls.m_ThresholdSlider->setMaximumValue(max);
171  m_Controls.m_ThresholdSlider->setMinimumValue(min);
172  }
173 }
174 
175 template <typename TPixel>
176 static void AccessPixel(mitk::PixelType /*ptype*/, const mitk::Image::Pointer im, mitk::Point3D p, int &val)
177 {
179  val = access.GetPixelByWorldCoordinates(p);
180 }
181 
183 {
184  if (m_RegionGrow3DTool.IsNull())
185  return;
186 
187  mitk::DataNode *node = m_RegionGrow3DTool->GetPointSetNode();
188 
189  if (node != NULL)
190  {
191  mitk::PointSet::Pointer pointSet = dynamic_cast<mitk::PointSet *>(node->GetData());
192 
193  if (pointSet.IsNull())
194  {
195  QMessageBox::critical(NULL, "QmitkAdaptiveRegionGrowingToolGUI", "PointSetNode does not contain a pointset");
196  return;
197  }
198 
199  m_Controls.m_lblSetSeedpoint->setText("");
200 
201  mitk::Image *image = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
202 
203  mitk::Point3D seedPoint =
204  pointSet
205  ->GetPointSet(
207  ->GetPoints()
208  ->ElementAt(0);
209 
210  if (image->GetGeometry()->IsInside(seedPoint))
212  AccessPixel, image->GetChannelDescriptor().GetPixelType(), image, seedPoint, m_SeedpointValue) else return;
213 
214  /* In this case the seedpoint is placed e.g. in the lung or bronchialtree
215  * The lowerFactor sets the windowsize depending on the regiongrowing direction
216  */
217  m_CurrentRGDirectionIsUpwards = true;
218  if (m_SeedpointValue < -500)
219  {
220  m_CurrentRGDirectionIsUpwards = false;
221  }
222 
223  // Initializing the region by the area around the seedpoint
224  m_SeedPointValueMean = 0;
225 
226  itk::Index<3> currentIndex, runningIndex;
227  mitk::ScalarType pixelValues[125];
228  unsigned int pos(0);
229 
230  image->GetGeometry(0)->WorldToIndex(seedPoint, currentIndex);
231  runningIndex = currentIndex;
232 
233  for (int i = runningIndex[0] - 2; i <= runningIndex[0] + 2; i++)
234  {
235  for (int j = runningIndex[1] - 2; j <= runningIndex[1] + 2; j++)
236  {
237  for (int k = runningIndex[2] - 2; k <= runningIndex[2] + 2; k++)
238  {
239  currentIndex[0] = i;
240  currentIndex[1] = j;
241  currentIndex[2] = k;
242 
243  if (image->GetGeometry()->IsIndexInside(currentIndex))
244  {
245  int component = 0;
246  m_InputImageNode->GetIntProperty("Image.Displayed Component", component);
249  image,
250  NULL,
251  currentIndex,
252  pixelValues[pos]);
253 
254  pos++;
255  }
256  else
257  {
258  pixelValues[pos] = std::numeric_limits<long>::min();
259  pos++;
260  }
261  }
262  }
263  }
264 
265  // Now calculation mean of the pixelValues
266  // Now calculation mean of the pixelValues
267  unsigned int numberOfValues(0);
268  for (auto &pixelValue : pixelValues)
269  {
270  if (pixelValue > std::numeric_limits<long>::min())
271  {
272  m_SeedPointValueMean += pixelValue;
273  numberOfValues++;
274  }
275  }
276  m_SeedPointValueMean = m_SeedPointValueMean / numberOfValues;
277 
278  mitk::ScalarType var = 0;
279  if (numberOfValues > 1)
280  {
281  for (auto &pixelValue : pixelValues)
282  {
284  {
285  var += (pixelValue - m_SeedPointValueMean) * (pixelValue - m_SeedPointValueMean);
286  }
287  }
288  var /= numberOfValues - 1;
289  }
290  mitk::ScalarType stdDev = sqrt(var);
291 
292  /*
293  * Here the upper- and lower threshold is calculated:
294  * The windowSize is 20% of the maximum range of the intensity values existing in the current image
295  * If the RG direction is upwards the lower TH is meanSeedValue-0.15*windowSize and upper TH is
296  * meanSeedValue+0.85*windowsSize
297  * if the RG direction is downwards the lower TH is meanSeedValue-0.85*windowSize and upper TH is
298  * meanSeedValue+0.15*windowsSize
299  */
302  mitk::ScalarType windowSize = max - min;
303 
304  windowSize = 0.15 * windowSize;
305 
306  if (m_CurrentRGDirectionIsUpwards)
307  {
308  m_LOWERTHRESHOLD = m_SeedPointValueMean - stdDev;
309  m_UPPERTHRESHOLD = m_SeedpointValue + windowSize;
310  if (m_UPPERTHRESHOLD > max)
311  m_UPPERTHRESHOLD = max;
312  m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD);
313  m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD);
314  }
315  else
316  {
317  m_UPPERTHRESHOLD = m_SeedPointValueMean;
318  if (m_SeedpointValue > m_SeedPointValueMean)
319  m_UPPERTHRESHOLD = m_SeedpointValue;
320  m_LOWERTHRESHOLD = m_SeedpointValue - windowSize;
321  if (m_LOWERTHRESHOLD < min)
322  m_LOWERTHRESHOLD = min;
323  m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD);
324  m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD);
325  }
326  }
327 }
328 
330 {
331  if (m_InputImageNode.IsNull())
332  {
333  QMessageBox::information(NULL, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!");
334  return;
335  }
336 
337  mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode();
338 
339  if (node.IsNull())
340  {
341  QMessageBox::information(NULL, "Adaptive Region Growing functionality", "Please insert a seed point inside the "
342  "image.\n\nFirst press the \"Define Seed "
343  "Point\" button,\nthen click left mouse "
344  "button inside the image.");
345  return;
346  }
347 
348  // safety if no pointSet or pointSet empty
349  mitk::PointSet::Pointer seedPointSet = dynamic_cast<mitk::PointSet *>(node->GetData());
350  if (seedPointSet.IsNull())
351  {
352  m_Controls.m_pbRunSegmentation->setEnabled(true);
353  QMessageBox::information(
354  NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point.");
355  return;
356  }
357 
358  int timeStep =
360 
361  if (!(seedPointSet->GetSize(timeStep)))
362  {
363  m_Controls.m_pbRunSegmentation->setEnabled(true);
364  QMessageBox::information(
365  NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point.");
366  return;
367  }
368 
369  QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
370 
371  mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet(timeStep)->GetPoints()->Begin().Value();
372 
373  mitk::Image::Pointer orgImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
374 
375  if (orgImage.IsNotNull())
376  {
377  if (orgImage->GetDimension() == 4)
378  {
380  timeSelector->SetInput(orgImage);
381  timeSelector->SetTimeNr(timeStep);
382  timeSelector->UpdateLargestPossibleRegion();
383  mitk::Image *timedImage = timeSelector->GetOutput();
384  AccessByItk_2(timedImage, StartRegionGrowing, timedImage->GetGeometry(), seedPoint);
385  }
386  else if (orgImage->GetDimension() == 3)
387  {
388  // QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); //set the cursor to waiting
389  AccessByItk_2(orgImage, StartRegionGrowing, orgImage->GetGeometry(), seedPoint);
390  // QApplication::restoreOverrideCursor();//reset cursor
391  }
392  else
393  {
394  QApplication::restoreOverrideCursor(); // reset cursor
395  QMessageBox::information(
396  NULL, "Adaptive Region Growing functionality", "Only images of dimension 3 or 4 can be processed!");
397  return;
398  }
399  }
400  EnableControls(true); // Segmentation ran successfully, so enable all controls.
401  node->SetVisibility(true);
402  QApplication::restoreOverrideCursor(); // reset cursor
403 }
404 
405 template <typename TPixel, unsigned int VImageDimension>
406 void QmitkAdaptiveRegionGrowingToolGUI::StartRegionGrowing(itk::Image<TPixel, VImageDimension> *itkImage,
407  mitk::BaseGeometry *imageGeometry,
408  mitk::PointSet::PointType seedPoint)
409 {
410  typedef itk::Image<TPixel, VImageDimension> InputImageType;
411  typedef typename InputImageType::IndexType IndexType;
414  typedef itk::MinimumMaximumImageCalculator<InputImageType> MinMaxValueFilterType;
415  typedef itk::BinaryThresholdImageFilter<InputImageType, InputImageType> ThresholdFilterType;
416  typedef itk::MaskImageFilter<InputImageType, InputImageType, InputImageType> MaskImageFilterType;
417 
418  if (!imageGeometry->IsInside(seedPoint))
419  {
420  QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor
421  QMessageBox::information(NULL,
422  "Segmentation functionality",
423  "The seed point is outside of the image! Please choose a position inside the image!");
424  return;
425  }
426 
427  IndexType seedIndex;
428  imageGeometry->WorldToIndex(seedPoint, seedIndex); // convert world coordinates to image indices
429 
430  if (m_SeedpointValue > m_UPPERTHRESHOLD || m_SeedpointValue < m_LOWERTHRESHOLD)
431  {
432  QApplication::restoreOverrideCursor(); // reset cursor to be able to click ok with the regular mouse cursor
433  QMessageBox::information(
434  NULL,
435  "Segmentation functionality",
436  "The seed point is outside the defined thresholds! Please set a new seed point or adjust the thresholds.");
437  MITK_INFO << "Mean: " << m_SeedPointValueMean;
438  return;
439  }
440 
441  // Setting the direction of the regiongrowing. For dark structures e.g. the lung the regiongrowing
442  // is performed starting at the upper value going to the lower one
443  regionGrower->SetGrowingDirectionIsUpwards(m_CurrentRGDirectionIsUpwards);
444  regionGrower->SetInput(itkImage);
445  regionGrower->AddSeed(seedIndex);
446  // In some cases we have to subtract 1 for the lower threshold and add 1 to the upper.
447  // Otherwise no region growing is done. Maybe a bug in the ConnectiveAdaptiveThresholdFilter
448  regionGrower->SetLower(m_LOWERTHRESHOLD - 1);
449  regionGrower->SetUpper(m_UPPERTHRESHOLD + 1);
450 
451  try
452  {
453  regionGrower->Update();
454  }
455  catch (itk::ExceptionObject &exc)
456  {
457  QMessageBox errorInfo;
458  errorInfo.setWindowTitle("Adaptive RG Segmentation Functionality");
459  errorInfo.setIcon(QMessageBox::Critical);
460  errorInfo.setText("An error occurred during region growing!");
461  errorInfo.setDetailedText(exc.what());
462  errorInfo.exec();
463  return; // can't work
464  }
465  catch (...)
466  {
467  QMessageBox::critical(NULL, "Adaptive RG Segmentation Functionality", "An error occurred during region growing!");
468  return;
469  }
470 
471  mitk::Image::Pointer resultImage = mitk::ImportItkImage(regionGrower->GetOutput())->Clone();
472  // initialize slider
473  m_Controls.m_PreviewSlider->setMinimum(m_LOWERTHRESHOLD);
474 
475  mitk::ScalarType max = m_SeedpointValue + resultImage->GetStatistics()->GetScalarValueMax();
476  if (max < m_UPPERTHRESHOLD)
477  m_Controls.m_PreviewSlider->setMaximum(max);
478  else
479  m_Controls.m_PreviewSlider->setMaximum(m_UPPERTHRESHOLD);
480 
481  this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint();
482 
483  if (m_CurrentRGDirectionIsUpwards)
484  {
485  m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean - 1);
486  }
487  else
488  {
489  m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean + 1);
490  }
491  this->m_SliderInitialized = true;
492 
493  // create new node and then delete the old one if there is one
495  newNode->SetData(resultImage);
496 
497  // set some properties
498  newNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORLABLEDSEGMENTATIONIMAGE));
499  newNode->SetProperty("helper object", mitk::BoolProperty::New(true));
500  newNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0));
501  newNode->SetProperty("layer", mitk::IntProperty::New(1));
502  newNode->SetProperty("opacity", mitk::FloatProperty::New(0.7));
503 
504  // delete the old image, if there was one:
505  mitk::DataNode::Pointer binaryNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
506  m_DataStorage->Remove(binaryNode);
507 
508  // now add result to data tree
510 
511  typename InputImageType::Pointer inputImageItk;
512  mitk::CastToItkImage<InputImageType>(resultImage, inputImageItk);
513  // volume rendering preview masking
514  typename ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
515  thresholdFilter->SetInput(inputImageItk);
516  thresholdFilter->SetInsideValue(1);
517  thresholdFilter->SetOutsideValue(0);
518 
519  double sliderVal = this->m_Controls.m_PreviewSlider->value();
520  if (m_CurrentRGDirectionIsUpwards)
521  {
522  thresholdFilter->SetLowerThreshold(sliderVal);
523  thresholdFilter->SetUpperThreshold(itk::NumericTraits<TPixel>::max());
524  }
525  else
526  {
527  thresholdFilter->SetLowerThreshold(itk::NumericTraits<TPixel>::min());
528  thresholdFilter->SetUpperThreshold(sliderVal);
529  }
530  thresholdFilter->SetInPlace(false);
531 
533  maskFilter->SetInput(inputImageItk);
534  maskFilter->SetInPlace(false);
535  maskFilter->SetMaskImage(thresholdFilter->GetOutput());
536  maskFilter->SetOutsideValue(0);
537  maskFilter->UpdateLargestPossibleRegion();
538 
539  mitk::Image::Pointer mitkMask;
540  mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMask);
542  maskedNode->SetData(mitkMask);
543 
544  // set some properties
545  maskedNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORMASKEDSEGMENTATION));
546  maskedNode->SetProperty("helper object", mitk::BoolProperty::New(true));
547  maskedNode->SetProperty("color", mitk::ColorProperty::New(0.0, 1.0, 0.0));
548  maskedNode->SetProperty("layer", mitk::IntProperty::New(1));
549  maskedNode->SetProperty("opacity", mitk::FloatProperty::New(0.0));
550 
551  // delete the old image, if there was one:
552  mitk::DataNode::Pointer deprecatedMask = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
553  m_DataStorage->Remove(deprecatedMask);
554 
555  // now add result to data tree
556  m_DataStorage->Add(maskedNode, m_InputImageNode);
557 
558  this->InitializeLevelWindow();
559 
560  if (m_UseVolumeRendering)
561  this->EnableVolumeRendering(true);
562 
563  m_UpdateSuggestedThreshold = true; // reset first stored threshold value
564  // Setting progress to finished
567 }
568 
569 void QmitkAdaptiveRegionGrowingToolGUI::InitializeLevelWindow()
570 {
571  // get the preview from the datatree
572  mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
573 
574  mitk::LevelWindow tempLevelWindow;
575  newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow");
576 
577  mitk::ScalarType *level = new mitk::ScalarType(0.0);
578  mitk::ScalarType *window = new mitk::ScalarType(1.0);
579 
580  int upper;
581  if (m_CurrentRGDirectionIsUpwards)
582  {
583  upper = m_UPPERTHRESHOLD - m_SeedpointValue;
584  }
585  else
586  {
587  upper = m_SeedpointValue - m_LOWERTHRESHOLD;
588  }
589 
590  tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper));
591 
592  // get the suggested threshold from the detected leakage-point and adjust the slider
593 
594  if (m_CurrentRGDirectionIsUpwards)
595  {
596  this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
597  *level = m_UPPERTHRESHOLD - (m_SeedpointValue) + 0.5;
598  }
599  else
600  {
601  this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
602  *level = (m_SeedpointValue)-m_LOWERTHRESHOLD + 0.5;
603  }
604 
605  tempLevelWindow.SetLevelWindow(*level, *window);
606  newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow");
607  // update the widgets
609 
610  m_SliderInitialized = true;
611 
612  // inquiry need to fix bug#1828
613  static int lastSliderPosition = 0;
614  if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition)
615  {
616  this->ChangeLevelWindow(lastSliderPosition);
617  }
618  lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1;
619 
620  if (m_MultiWidget)
621  {
624  static_cast<mitk::LevelWindowProperty *>(newNode->GetProperty("levelwindow")));
625  }
626 
627  if (m_UseVolumeRendering)
628  this->UpdateVolumeRenderingThreshold((int)(*level + 0.5)); // lower threshold for labeled image
629 }
630 
632 {
633  if (m_SliderInitialized)
634  {
635  // do nothing, if no preview exists
636  mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
637  if (newNode.IsNull())
638  return;
639 
640  mitk::LevelWindow tempLevelWindow;
641 
642  newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); // get the levelWindow associated with the preview
643 
644  mitk::ScalarType level; // = this->m_UPPERTHRESHOLD - newValue + 0.5;
645  mitk::ScalarType *window = new mitk::ScalarType(1);
646 
647  // adjust the levelwindow according to the position of the slider (newvalue)
648  if (m_CurrentRGDirectionIsUpwards)
649  {
650  level = m_UPPERTHRESHOLD - newValue + 0.5;
651  tempLevelWindow.SetLevelWindow(level, *window);
652  }
653  else
654  {
655  level = newValue - m_LOWERTHRESHOLD + 0.5;
656  tempLevelWindow.SetLevelWindow(level, *window);
657  }
658 
659  newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow");
660 
661  if (m_UseVolumeRendering)
662  this->UpdateVolumeRenderingThreshold((int)(level - 0.5)); // lower threshold for labeled image
663 
664  newNode->SetVisibility(true);
666  }
667 }
668 
670 {
671  // moves the slider one step to the left, when the "-"-button is pressed
672  if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->minimum())
673  {
674  int newValue = this->m_Controls.m_PreviewSlider->value() - 1;
675  this->ChangeLevelWindow(newValue);
676  this->m_Controls.m_PreviewSlider->setValue(newValue);
677  }
678 }
679 
681 {
682  // moves the slider one step to the right, when the "+"-button is pressed
683  if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->maximum())
684  {
685  int newValue = this->m_Controls.m_PreviewSlider->value() + 1;
686  this->ChangeLevelWindow(newValue);
687  this->m_Controls.m_PreviewSlider->setValue(newValue);
688  }
689 }
690 
692 {
693  // get image node
694  if (m_InputImageNode.IsNull())
695  {
696  QMessageBox::critical(NULL, "Adaptive region growing functionality", "Please specify the image in Datamanager!");
697  return;
698  }
699  // get image data
700  mitk::Image::Pointer orgImage = dynamic_cast<mitk::Image *>(m_InputImageNode->GetData());
701  if (orgImage.IsNull())
702  {
703  QMessageBox::critical(NULL, "Adaptive region growing functionality", "No Image found!");
704  return;
705  }
706  // get labeled segmentation
707  mitk::Image::Pointer labeledSeg =
708  (mitk::Image *)m_DataStorage->GetNamedObject<mitk::Image>(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
709  if (labeledSeg.IsNull())
710  {
711  QMessageBox::critical(NULL, "Adaptive region growing functionality", "No Segmentation Preview found!");
712  return;
713  }
714 
715  mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
716  if (newNode.IsNull())
717  return;
718 
720  QString segName = QString::fromStdString(m_RegionGrow3DTool->GetCurrentSegmentationName());
721 
722  dialog.SetSegmentationName(segName);
723  int result = dialog.exec();
724 
725  switch (result)
726  {
728  m_RegionGrow3DTool->SetOverwriteExistingSegmentation(false);
729  break;
731  m_RegionGrow3DTool->SetOverwriteExistingSegmentation(true);
732  break;
734  return;
735  }
736 
737  mitk::Image::Pointer img = dynamic_cast<mitk::Image *>(newNode->GetData());
738  AccessByItk(img, ITKThresholding);
739 
740  // disable volume rendering preview after the segmentation node was created
741  this->EnableVolumeRendering(false);
742  newNode->SetVisibility(false);
743  m_Controls.m_cbVolumeRendering->setChecked(false);
744  // TODO disable slider etc...
745 
746  if (m_RegionGrow3DTool.IsNotNull())
747  {
748  m_RegionGrow3DTool->ConfirmSegmentation();
749  }
750 }
751 
752 template <typename TPixel, unsigned int VImageDimension>
753 void QmitkAdaptiveRegionGrowingToolGUI::ITKThresholding(itk::Image<TPixel, VImageDimension> *itkImage)
754 {
755  mitk::Image::Pointer originalSegmentation =
756  dynamic_cast<mitk::Image *>(this->m_RegionGrow3DTool->GetTargetSegmentationNode()->GetData());
757 
758  int timeStep =
760 
761  if (originalSegmentation)
762  {
763  typedef itk::Image<TPixel, VImageDimension> InputImageType;
764  typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
765 
766  // select single 3D volume if we have more than one time step
767  typename SegmentationType::Pointer originalSegmentationInITK = SegmentationType::New();
768  if (originalSegmentation->GetTimeGeometry()->CountTimeSteps() > 1)
769  {
771  timeSelector->SetInput(originalSegmentation);
772  timeSelector->SetTimeNr(timeStep);
773  timeSelector->UpdateLargestPossibleRegion();
774  CastToItkImage(timeSelector->GetOutput(), originalSegmentationInITK);
775  }
776  else // use original
777  {
778  CastToItkImage(originalSegmentation, originalSegmentationInITK);
779  }
780 
781  // Fill current preiview image in segmentation image
782  originalSegmentationInITK->FillBuffer(0);
783  itk::ImageRegionIterator<SegmentationType> itOutput(originalSegmentationInITK,
784  originalSegmentationInITK->GetLargestPossibleRegion());
785  itk::ImageRegionIterator<InputImageType> itInput(itkImage, itkImage->GetLargestPossibleRegion());
786  itOutput.GoToBegin();
787  itInput.GoToBegin();
788 
789  // calculate threhold from slider value
790  int currentTreshold = 0;
791  if (m_CurrentRGDirectionIsUpwards)
792  {
793  currentTreshold = m_UPPERTHRESHOLD - m_Controls.m_PreviewSlider->value() + 1;
794  }
795  else
796  {
797  currentTreshold = m_Controls.m_PreviewSlider->value() - m_LOWERTHRESHOLD;
798  }
799 
800  // iterate over image and set pixel in segmentation according to thresholded labeled image
801  while (!itOutput.IsAtEnd() && !itInput.IsAtEnd())
802  {
803  // Use threshold slider to determine if pixel is set to 1
804  if (itInput.Value() != 0 && itInput.Value() >= currentTreshold)
805  {
806  itOutput.Set(1);
807  }
808 
809  ++itOutput;
810  ++itInput;
811  }
812 
813  // combine current working segmentation image with our region growing result
814  originalSegmentation->SetVolume((void *)(originalSegmentationInITK->GetPixelContainer()->GetBufferPointer()),
815  timeStep);
816 
817  originalSegmentation->Modified();
819  }
820 }
821 
823 {
824  if (m_RegionGrow3DTool.IsNull())
825  return;
826 
827  // Check if seed point is already set, if not leave RunSegmentation disabled
828  // if even m_DataStorage is NULL leave node NULL
829  mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode();
830  if (node.IsNull())
831  {
832  this->m_Controls.m_pbRunSegmentation->setEnabled(false);
833  }
834  else
835  {
836  this->m_Controls.m_pbRunSegmentation->setEnabled(enable);
837  }
838 
839  // Check if a segmentation exists, if not leave segmentation dependent disabled.
840  // if even m_DataStorage is NULL leave node NULL
841  node = m_DataStorage ? m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE) : NULL;
842  if (node.IsNull())
843  {
844  this->m_Controls.m_PreviewSlider->setEnabled(false);
845  this->m_Controls.m_pbConfirmSegementation->setEnabled(false);
846  }
847  else
848  {
849  this->m_Controls.m_PreviewSlider->setEnabled(enable);
850  this->m_Controls.m_pbConfirmSegementation->setEnabled(enable);
851  }
852 
853  this->m_Controls.m_cbVolumeRendering->setEnabled(enable);
854 }
855 
856 void QmitkAdaptiveRegionGrowingToolGUI::EnableVolumeRendering(bool enable)
857 {
858  mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
859 
860  if (node.IsNull())
861  return;
862 
863  if (m_MultiWidget)
865 
866  if (enable)
867  {
868  node->SetBoolProperty("volumerendering", enable);
869  node->SetBoolProperty("volumerendering.uselod", true);
870  }
871  else
872  {
873  node->SetBoolProperty("volumerendering", enable);
874  }
875 
876  double val = this->m_Controls.m_PreviewSlider->value();
877  this->ChangeLevelWindow(val);
878 
880 }
881 
882 void QmitkAdaptiveRegionGrowingToolGUI::UpdateVolumeRenderingThreshold(int thValue)
883 {
884  typedef short PixelType;
885  typedef itk::Image<PixelType, 3> InputImageType;
886  typedef itk::BinaryThresholdImageFilter<InputImageType, InputImageType> ThresholdFilterType;
887  typedef itk::MaskImageFilter<InputImageType, InputImageType, InputImageType> MaskImageFilterType;
888 
889  mitk::DataNode::Pointer grownImageNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
890  mitk::Image::Pointer grownImage = dynamic_cast<mitk::Image *>(grownImageNode->GetData());
891 
892  if (!grownImage)
893  {
894  MITK_ERROR << "Missing data node for labeled segmentation image.";
895  return;
896  }
897 
898  InputImageType::Pointer itkGrownImage;
899  mitk::CastToItkImage(grownImage, itkGrownImage);
900 
902  thresholdFilter->SetInput(itkGrownImage);
903  thresholdFilter->SetInPlace(false);
904 
905  double sliderVal = this->m_Controls.m_PreviewSlider->value();
906  PixelType threshold = itk::NumericTraits<PixelType>::min();
907  if (m_CurrentRGDirectionIsUpwards)
908  {
909  threshold = static_cast<PixelType>(m_UPPERTHRESHOLD - sliderVal + 0.5);
910 
911  thresholdFilter->SetLowerThreshold(threshold);
912  thresholdFilter->SetUpperThreshold(itk::NumericTraits<PixelType>::max());
913  }
914  else
915  {
916  threshold = sliderVal - m_LOWERTHRESHOLD + 0.5;
917 
918  thresholdFilter->SetLowerThreshold(itk::NumericTraits<PixelType>::min());
919  thresholdFilter->SetUpperThreshold(threshold);
920  }
921  thresholdFilter->UpdateLargestPossibleRegion();
922 
924  maskFilter->SetInput(itkGrownImage);
925  maskFilter->SetInPlace(false);
926  maskFilter->SetMaskImage(thresholdFilter->GetOutput());
927  maskFilter->SetOutsideValue(0);
928  maskFilter->UpdateLargestPossibleRegion();
929 
930  mitk::Image::Pointer mitkMaskedImage;
931  mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMaskedImage);
932  mitk::DataNode::Pointer maskNode = m_DataStorage->GetNamedNode(m_NAMEFORMASKEDSEGMENTATION);
933  maskNode->SetData(mitkMaskedImage);
934 }
935 
937 {
938  m_UseVolumeRendering = on;
939 
940  this->EnableVolumeRendering(on);
941 }
942 
944 {
945  m_LOWERTHRESHOLD = lowerThreshold;
946 }
947 
949 {
950  m_UPPERTHRESHOLD = upperThreshold;
951 }
952 
954 {
955  // make the segmentation preview node invisible
956  mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE);
957  if (node.IsNotNull())
958  {
959  node->SetVisibility(false);
960  }
961 
962  // disable volume rendering preview after the segmentation node was created
963  this->EnableVolumeRendering(false);
964  m_Controls.m_cbVolumeRendering->setChecked(false);
965 }
966 
968 {
969 }
void Progress(unsigned int steps=1)
Sets the current amount of progress to current progress + steps.
mitk::ScalarType FastSinglePixelAccess(mitk::PixelType, mitk::Image::Pointer im, ImageDataItem *item, itk::Index< 3 > idx, mitk::ScalarType &val, int component=0)
virtual void Add(mitk::DataNode *node, const mitk::DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
void OnPointAdded()
Method to calculate parameter settings, when a seed point is set.
MITK_TOOL_GUI_MACRO(, QmitkPixelManipulationToolGUI,"")
Base class of all tools used by mitk::ToolManager.
Definition: mitkTool.h:92
Data management class that handles 'was created by' relations.
void UseVolumeRendering(bool on)
Method to switch the volume rendering on/off.
itk::SmartPointer< Self > Pointer
Gives locked and index-based read access for a particular image part. The class provides several set-...
void SetMultiWidget(QmitkStdMultiWidget *multiWidget)
Method to set the used multiwidget.
virtual void SetDataStorage(mitk::DataStorage *dataStorage)
Method to set the default data storage.
static BaseRenderer * GetInstance(vtkRenderWindow *renWin)
void SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, std::string surface, std::string maskedSegmentation)
Method to set the name of a data node.
static vtkRenderWindow * GetRenderWindowByName(const std::string &name)
#define MITK_INFO
Definition: mitkLogMacros.h:22
#define MITK_ERROR
Definition: mitkLogMacros.h:24
Dummy Tool for AdaptiveRegionGrowingToolGUI to get Tool functionality for AdaptiveRegionGrowing. The actual logic is implemented in QmitkAdaptiveRegionGrowingToolGUI.
double ScalarType
bool IsIndexInside(const mitk::Point3D &index) const
Test whether the point p ((continous!)index coordinates in units) is inside the bounding box...
StatisticsHolderPointer GetStatistics() const
Returns a pointer to the ImageStatisticsHolder object that holds all statistics information for the i...
Definition: mitkImage.h:646
static Pointer New()
virtual void SetData(mitk::BaseData *baseData)
Set the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
Ui::QmitkAdaptiveRegionGrowingToolGUIControls m_Controls
The created GUI from the .ui-File. This Attribute is obligatory.
void SetInputImageNode(mitk::DataNode *node)
Method to set the input image node.
void OnNewToolAssociated(mitk::Tool *)
Method to determine which tool to activate.
void ChangeLevelWindow(double newValue)
Method to change the level window.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
ChannelDescriptor GetChannelDescriptor(int id=0) const
Definition: mitkImage.h:529
ImageFilter used for processing an image with an adaptive iterator (such as itkAdaptiveThresholdItera...
static void AccessPixel(mitk::PixelType, const mitk::Image::Pointer im, mitk::Point3D p, int &val)
static ProgressBar * GetInstance()
static method to get the GUI dependent ProgressBar-instance so the methods for steps to do and progre...
void SetUpperThresholdValue(double upperThreshold)
Method to set upper threshold.
mitk::AdaptiveRegionGrowingTool::Pointer m_RegionGrow3DTool
Image::Pointer ImportItkImage(const itk::SmartPointer< ItkOutputImageType > &itkimage, const BaseGeometry *geometry=nullptr, bool update=true)
Imports an itk::Image (with a specific type) as an mitk::Image.Instantiates instance of ITKImageImpor...
QmitkLevelWindowWidget * levelWindowWidget
void SetRangeMinMax(ScalarType min, ScalarType max)
The LevelWindow class Class to store level/window values.
virtual ScalarType GetScalarValueMin(int t=0, unsigned int component=0)
Get the minimum for scalar images. Recomputation performed only when necessary.
static Pointer New()
void RunSegmentation()
Method to start the segmentation.
PixelType GetPixelType() const
Get the type of channel's elements.
DataType * GetNamedObject(const char *name) const
Convenience method to get the first data object of a given data type with a given name...
mitk::DataStorage::Pointer m_DataStorage
Data structure which stores a set of points. Superclass of mitk::Mesh.
Definition: mitkPointSet.h:79
itk::Image< double, 3 > InputImageType
#define mitkPixelTypeMultiplex3(function, ptype, param1, param2, param3)
static Pointer New()
static RenderingManager * GetInstance()
virtual ScalarType GetScalarValueMax(int t=0, unsigned int component=0)
Get the maximum for scalar images. Recomputation performed only when necessary.
Image class for storing images.
Definition: mitkImage.h:76
#define mitkPixelTypeMultiplex4(function, ptype, param1, param2, param3, param4)
Base class for GUIs belonging to mitk::Tool classes.
Definition: QmitkToolGUI.h:36
void SetLevelWindowProperty(LevelWindowProperty::Pointer levelWindowProperty)
Sets an specific LevelWindowProperty, all changes will affect the image belonging to this property...
#define AccessByItk(mitkImage, itkImageTypeFunction)
Access a MITK image by an ITK image.
static T max(T x, T y)
Definition: svm.cpp:70
virtual unsigned int GetTimeStep() const
static Pointer New()
static T min(T x, T y)
Definition: svm.cpp:67
static Pointer New()
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
void SetWidgetPlanesVisibility(bool visible, mitk::BaseRenderer *renderer=NULL)
void EnableControls(bool enable)
Method to enable/disable controls for region growing.
unsigned short PixelType
void ConfirmSegmentation()
Method to confirm the preview segmentation.
void SetAutoTopMostImage(bool autoTopMost, const DataNode *removedNode=nullptr)
(Re-)Initializes the LevelWindowManager by setting the topmost image. Use the removedNode parameter i...
void DecreaseSlider()
Method to decrease the preview slider.
#define AccessByItk_2(mitkImage, itkImageTypeFunction, arg1, arg2)
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
void SetLevelWindow(ScalarType level, ScalarType window, bool expandRangesIfNecessary=true)
void IncreaseSlider()
Method to increase the preview slider.
virtual void Remove(const mitk::DataNode *node)=0
Removes node from the DataStorage.
mitk::DataNode * GetNamedNode(const char *name) const
Convenience method to get the first node with a given name.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
Definition: mitkBaseData.h:129
void SetLowerThresholdValue(double lowerThreshold)
Method to set the lower threshold.
static Pointer New()
void RequestUpdateAll(RequestType type=REQUEST_UPDATE_ALL)
BaseGeometry Describes the geometry of a data object.
virtual void CreateConnections()
Method to create the connections for the component. This Method is obligatory even if no connections ...
Class for nodes of the DataTree.
Definition: mitkDataNode.h:66
static Pointer New()
mitk::LevelWindowManager * GetManager()
Class for defining the data type of pixels.
Definition: mitkPixelType.h:55
const TPixel & GetPixelByWorldCoordinates(mitk::Point3D position)
void WorldToIndex(const mitk::Point3D &pt_mm, mitk::Point3D &pt_units) const
Convert world coordinates (in mm) of a point to (continuous!) index coordinates.
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.