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