14 #include <qmessagebox.h> 25 #include "itkMaskImageFilter.h" 26 #include "itkNumericTraits.h" 27 #include <itkBinaryThresholdImageFilter.h> 29 #include <itkImageIterator.h> 30 #include <itkMinimumMaximumImageCalculator.h> 33 #include "itkOrImageFilter.h" 46 m_UseVolumeRendering(false),
47 m_UpdateSuggestedThreshold(true),
48 m_SuggestedThValue(0.0)
50 this->setParent(parent);
52 m_Controls.setupUi(
this);
54 m_Controls.m_ThresholdSlider->setDecimals(1);
55 m_Controls.m_ThresholdSlider->setSpinBoxAlignment(Qt::AlignVCenter);
57 m_Controls.m_PreviewSlider->setEnabled(
false);
58 m_Controls.m_PreviewSlider->setSingleStep(0.5);
63 m_Controls.m_cbVolumeRendering->setVisible(
false);
65 this->CreateConnections();
66 this->SetDataNodeNames(
"labeledRGSegmentation",
"RGResult",
"RGFeedbackSurface",
"maskedSegmentation");
68 connect(
this, SIGNAL(NewToolAssociated(
mitk::Tool *)),
this, SLOT(OnNewToolAssociated(
mitk::Tool *)));
76 m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetAddObserverTag);
77 m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetMoveObserverTag);
79 this->RemoveHelperNodes();
92 itk::SimpleMemberCommand<QmitkAdaptiveRegionGrowingToolGUI>::Pointer pointAddedCommand =
93 itk::SimpleMemberCommand<QmitkAdaptiveRegionGrowingToolGUI>::New();
95 m_PointSetAddObserverTag =
96 m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand);
97 m_PointSetMoveObserverTag =
98 m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver(mitk::PointSetMoveEvent(), pointAddedCommand);
106 void QmitkAdaptiveRegionGrowingToolGUI::RemoveHelperNodes()
109 if (imageNode.IsNotNull())
115 if (maskedSegmentationNode.IsNotNull())
134 std::string binaryImage,
136 std::string maskedSegmentation)
138 m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation;
139 m_NAMEFORBINARYIMAGE = binaryImage;
140 m_NAMEFORSURFACE = surface;
141 m_NAMEFORMASKEDSEGMENTATION = maskedSegmentation;
157 m_Controls.m_ThresholdSlider->setMaximum(max);
158 m_Controls.m_ThresholdSlider->setMinimum(min);
160 m_Controls.m_ThresholdSlider->setMaximumValue(max);
161 m_Controls.m_ThresholdSlider->setMinimumValue(min);
165 template <
typename TPixel>
183 if (pointSet.IsNull())
185 QMessageBox::critical(
nullptr,
"QmitkAdaptiveRegionGrowingToolGUI",
"PointSetNode does not contain a pointset");
207 m_CurrentRGDirectionIsUpwards =
true;
208 if (m_SeedpointValue < -500)
210 m_CurrentRGDirectionIsUpwards =
false;
214 m_SeedPointValueMean = 0;
221 runningIndex = currentIndex;
223 for (
int i = runningIndex[0] - 2; i <= runningIndex[0] + 2; i++)
225 for (
int j = runningIndex[1] - 2; j <= runningIndex[1] + 2; j++)
227 for (
int k = runningIndex[2] - 2;
k <= runningIndex[2] + 2;
k++)
257 unsigned int numberOfValues(0);
258 for (
auto &pixelValue : pixelValues)
262 m_SeedPointValueMean += pixelValue;
266 m_SeedPointValueMean = m_SeedPointValueMean / numberOfValues;
269 if (numberOfValues > 1)
271 for (
auto &pixelValue : pixelValues)
275 var += (pixelValue - m_SeedPointValueMean) * (pixelValue - m_SeedPointValueMean);
278 var /= numberOfValues - 1;
294 windowSize = 0.15 * windowSize;
296 if (m_CurrentRGDirectionIsUpwards)
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);
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);
323 QMessageBox::information(
nullptr,
"Adaptive Region Growing functionality",
"Please specify the image in Datamanager!");
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.");
340 if (seedPointSet.IsNull())
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.");
351 if (!(seedPointSet->GetSize(timeStep)))
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.");
359 QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
365 if (orgImage.IsNotNull())
367 if (orgImage->GetDimension() == 4)
370 timeSelector->SetInput(orgImage);
371 timeSelector->SetTimeNr(timeStep);
372 timeSelector->UpdateLargestPossibleRegion();
373 mitk::Image *timedImage = timeSelector->GetOutput();
376 else if (orgImage->GetDimension() == 3)
384 QApplication::restoreOverrideCursor();
385 QMessageBox::information(
386 nullptr,
"Adaptive Region Growing functionality",
"Only images of dimension 3 or 4 can be processed!");
391 node->SetVisibility(
true);
392 QApplication::restoreOverrideCursor();
395 template <
typename TPixel,
unsigned int VImageDimension>
396 void QmitkAdaptiveRegionGrowingToolGUI::StartRegionGrowing(itk::Image<TPixel, VImageDimension> *itkImage,
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;
407 if (!imageGeometry->
IsInside(seedPoint))
409 QApplication::restoreOverrideCursor();
410 QMessageBox::information(
nullptr,
411 "Segmentation functionality",
412 "The seed point is outside of the image! Please choose a position inside the image!");
419 if (m_SeedpointValue > m_UPPERTHRESHOLD || m_SeedpointValue < m_LOWERTHRESHOLD)
421 QApplication::restoreOverrideCursor();
422 QMessageBox::information(
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;
432 regionGrower->SetGrowingDirectionIsUpwards(m_CurrentRGDirectionIsUpwards);
433 regionGrower->SetInput(itkImage);
434 regionGrower->AddSeed(seedIndex);
437 regionGrower->SetLower(m_LOWERTHRESHOLD - 1);
438 regionGrower->SetUpper(m_UPPERTHRESHOLD + 1);
442 regionGrower->Update();
444 catch (itk::ExceptionObject &exc)
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());
456 QMessageBox::critical(
nullptr,
"Adaptive RG Segmentation Functionality",
"An error occurred during region growing!");
462 m_Controls.m_PreviewSlider->setMinimum(m_LOWERTHRESHOLD);
464 mitk::ScalarType max = m_SeedpointValue + resultImage->GetStatistics()->GetScalarValueMax();
465 if (max < m_UPPERTHRESHOLD)
468 m_Controls.m_PreviewSlider->setMaximum(m_UPPERTHRESHOLD);
470 this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint();
472 if (m_CurrentRGDirectionIsUpwards)
474 m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean - 1);
478 m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean + 1);
480 this->m_SliderInitialized =
true;
484 newNode->SetData(resultImage);
500 typename InputImageType::Pointer inputImageItk;
501 mitk::CastToItkImage<InputImageType>(resultImage, inputImageItk);
503 typename ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
504 thresholdFilter->SetInput(inputImageItk);
505 thresholdFilter->SetInsideValue(1);
506 thresholdFilter->SetOutsideValue(0);
508 double sliderVal = this->
m_Controls.m_PreviewSlider->value();
509 if (m_CurrentRGDirectionIsUpwards)
511 thresholdFilter->SetLowerThreshold(sliderVal);
517 thresholdFilter->SetUpperThreshold(sliderVal);
519 thresholdFilter->SetInPlace(
false);
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();
529 mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMask);
531 maskedNode->SetData(mitkMask);
547 this->InitializeLevelWindow();
549 if (m_UseVolumeRendering)
550 this->EnableVolumeRendering(
true);
552 m_UpdateSuggestedThreshold =
true;
558 void QmitkAdaptiveRegionGrowingToolGUI::InitializeLevelWindow()
564 newNode->GetLevelWindow(tempLevelWindow,
nullptr,
"levelwindow");
570 if (m_CurrentRGDirectionIsUpwards)
572 upper = m_UPPERTHRESHOLD - m_SeedpointValue;
576 upper = m_SeedpointValue - m_LOWERTHRESHOLD;
583 if (m_CurrentRGDirectionIsUpwards)
585 this->
m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
586 *level = m_UPPERTHRESHOLD - (m_SeedpointValue) + 0.5;
590 this->
m_Controls.m_PreviewSlider->setValue(m_SeedpointValue);
591 *level = (m_SeedpointValue)-m_LOWERTHRESHOLD + 0.5;
595 newNode->SetLevelWindow(tempLevelWindow,
nullptr,
"levelwindow");
599 m_SliderInitialized =
true;
602 static int lastSliderPosition = 0;
603 if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition)
607 lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1;
609 if (m_UseVolumeRendering)
610 this->UpdateVolumeRenderingThreshold((
int)(*level + 0.5));
615 if (m_SliderInitialized)
619 if (newNode.IsNull())
624 newNode->GetLevelWindow(tempLevelWindow,
nullptr,
"levelwindow");
630 if (m_CurrentRGDirectionIsUpwards)
632 level = m_UPPERTHRESHOLD - newValue + 0.5;
637 level = newValue - m_LOWERTHRESHOLD + 0.5;
641 newNode->SetLevelWindow(tempLevelWindow,
nullptr,
"levelwindow");
643 if (m_UseVolumeRendering)
644 this->UpdateVolumeRenderingThreshold((
int)(level - 0.5));
646 newNode->SetVisibility(
true);
656 int newValue = this->
m_Controls.m_PreviewSlider->value() - 1;
658 this->
m_Controls.m_PreviewSlider->setValue(newValue);
667 int newValue = this->
m_Controls.m_PreviewSlider->value() + 1;
669 this->
m_Controls.m_PreviewSlider->setValue(newValue);
678 QMessageBox::critical(
nullptr,
"Adaptive region growing functionality",
"Please specify the image in Datamanager!");
683 if (orgImage.IsNull())
685 QMessageBox::critical(
nullptr,
"Adaptive region growing functionality",
"No Image found!");
691 if (labeledSeg.IsNull())
693 QMessageBox::critical(
nullptr,
"Adaptive region growing functionality",
"No Segmentation Preview found!");
698 if (newNode.IsNull())
702 QString segName = QString::fromStdString(
m_RegionGrow3DTool->GetCurrentSegmentationName());
705 int result = dialog.exec();
723 this->EnableVolumeRendering(
false);
724 newNode->SetVisibility(
false);
725 m_Controls.m_cbVolumeRendering->setChecked(
false);
734 template <
typename TPixel,
unsigned int VImageDimension>
735 void QmitkAdaptiveRegionGrowingToolGUI::ITKThresholding(itk::Image<TPixel, VImageDimension> *itkImage)
743 if (originalSegmentation)
746 typedef itk::Image<mitk::Tool::DefaultSegmentationDataType, VImageDimension> SegmentationType;
749 typename SegmentationType::Pointer originalSegmentationInITK = SegmentationType::New();
750 if (originalSegmentation->GetTimeGeometry()->CountTimeSteps() > 1)
753 timeSelector->SetInput(originalSegmentation);
754 timeSelector->SetTimeNr(timeStep);
755 timeSelector->UpdateLargestPossibleRegion();
756 CastToItkImage(timeSelector->GetOutput(), originalSegmentationInITK);
764 originalSegmentationInITK->FillBuffer(0);
765 itk::ImageRegionIterator<SegmentationType> itOutput(originalSegmentationInITK,
766 originalSegmentationInITK->GetLargestPossibleRegion());
767 itk::ImageRegionIterator<InputImageType> itInput(itkImage, itkImage->GetLargestPossibleRegion());
768 itOutput.GoToBegin();
772 int currentTreshold = 0;
773 if (m_CurrentRGDirectionIsUpwards)
775 currentTreshold = m_UPPERTHRESHOLD -
m_Controls.m_PreviewSlider->value() + 1;
779 currentTreshold =
m_Controls.m_PreviewSlider->value() - m_LOWERTHRESHOLD;
783 while (!itOutput.IsAtEnd() && !itInput.IsAtEnd())
786 if (itInput.Value() != 0 && itInput.Value() >=
static_cast<typename itk::ImageRegionIterator<InputImageType>::PixelType
>(currentTreshold))
796 originalSegmentation->SetVolume((
void *)(originalSegmentationInITK->GetPixelContainer()->GetBufferPointer()),
799 originalSegmentation->Modified();
814 this->
m_Controls.m_pbRunSegmentation->setEnabled(
false);
818 this->
m_Controls.m_pbRunSegmentation->setEnabled(enable);
826 this->
m_Controls.m_PreviewSlider->setEnabled(
false);
827 this->
m_Controls.m_pbConfirmSegementation->setEnabled(
false);
831 this->
m_Controls.m_PreviewSlider->setEnabled(enable);
832 this->
m_Controls.m_pbConfirmSegementation->setEnabled(enable);
835 this->
m_Controls.m_cbVolumeRendering->setEnabled(enable);
838 void QmitkAdaptiveRegionGrowingToolGUI::EnableVolumeRendering(
bool enable)
847 node->SetBoolProperty(
"volumerendering", enable);
848 node->SetBoolProperty(
"volumerendering.uselod",
true);
852 node->SetBoolProperty(
"volumerendering", enable);
855 double val = this->
m_Controls.m_PreviewSlider->value();
861 void QmitkAdaptiveRegionGrowingToolGUI::UpdateVolumeRenderingThreshold(
int)
863 typedef short PixelType;
865 typedef itk::BinaryThresholdImageFilter<InputImageType, InputImageType> ThresholdFilterType;
866 typedef itk::MaskImageFilter<InputImageType, InputImageType, InputImageType> MaskImageFilterType;
873 MITK_ERROR <<
"Missing data node for labeled segmentation image.";
877 InputImageType::Pointer itkGrownImage;
880 ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
881 thresholdFilter->SetInput(itkGrownImage);
882 thresholdFilter->SetInPlace(
false);
884 double sliderVal = this->
m_Controls.m_PreviewSlider->value();
886 if (m_CurrentRGDirectionIsUpwards)
888 threshold =
static_cast<PixelType
>(m_UPPERTHRESHOLD - sliderVal + 0.5);
890 thresholdFilter->SetLowerThreshold(threshold);
895 threshold = sliderVal - m_LOWERTHRESHOLD + 0.5;
898 thresholdFilter->SetUpperThreshold(threshold);
900 thresholdFilter->UpdateLargestPossibleRegion();
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();
910 mitk::CastToMitkImage<InputImageType>(maskFilter->GetOutput(), mitkMaskedImage);
912 maskNode->
SetData(mitkMaskedImage);
917 m_UseVolumeRendering = on;
919 this->EnableVolumeRendering(on);
924 m_LOWERTHRESHOLD = lowerThreshold;
929 m_UPPERTHRESHOLD = upperThreshold;
936 if (node.IsNotNull())
938 node->SetVisibility(
false);
942 this->EnableVolumeRendering(
false);
943 m_Controls.m_cbVolumeRendering->setChecked(
false);
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)
Data management class that handles 'was created by' relations.
Gives locked and index-based read access for a particular image part. The class provides several set-...
static BaseRenderer * GetInstance(vtkRenderWindow *renWin)
void SetSegmentationName(QString name)
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...
bool IsIndexInside(const mitk::Point3D &index) const
Test whether the point p ((continous!)index coordinates in units) is inside the bounding box...
bool IsInside(const mitk::Point3D &p) const
Test whether the point p (world coordinates in mm) is inside the bounding box.
virtual void SetData(mitk::BaseData *baseData)
Set the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
::mitk::Image InputImageType
StatisticsHolderPointer GetStatistics() const
Returns a pointer to the ImageStatisticsHolder object that holds all statistics information for the i...
ImageFilter used for processing an image with an adaptive iterator (such as itkAdaptiveThresholdItera...
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...
ChannelDescriptor GetChannelDescriptor(int id=0) const
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.
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's elements.
mitk::DataStorage::Pointer m_DataStorage
Data structure which stores a set of points. Superclass of mitk::Mesh.
#define mitkPixelTypeMultiplex3(function, ptype, param1, param2, param3)
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.
#define mitkPixelTypeMultiplex4(function, ptype, param1, param2, param3, param4)
#define AccessByItk(mitkImage, itkImageTypeFunction)
Access a MITK image by an ITK image.
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.
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
void MITKCORE_EXPORT CastToItkImage(const mitk::Image *mitkImage, itk::SmartPointer< ItkOutputImageType > &itkOutputImage)
Cast an mitk::Image to an itk::Image with a specific type.
#define AccessByItk_2(mitkImage, itkImageTypeFunction, arg1, arg2)
void SetLevelWindow(ScalarType level, ScalarType window, bool expandRangesIfNecessary=true)
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
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.
Class for nodes of the DataTree.
Class for defining the data type of pixels.
const TPixel & GetPixelByWorldCoordinates(mitk::Point3D position)