diff --git a/Modules/QtWidgets/LabelSetImage_48.png b/Modules/QtWidgets/LabelSetImage_48.png new file mode 100644 index 0000000000..b1117f4696 Binary files /dev/null and b/Modules/QtWidgets/LabelSetImage_48.png differ diff --git a/Modules/QtWidgets/resource/Qmitk.qrc b/Modules/QtWidgets/resource/Qmitk.qrc index ba779c5657..2b4501588d 100644 --- a/Modules/QtWidgets/resource/Qmitk.qrc +++ b/Modules/QtWidgets/resource/Qmitk.qrc @@ -1,14 +1,15 @@ - + Binaerbilder_48.png Images_48.png PointSet_48.png Segmentation_48.png Surface_48.png mm_pointer.png mm_scroll.png mm_zoom.png mm_contrast.png mm_pan.png + LabelSetImage_48.png diff --git a/Modules/QtWidgets/src/QmitkNodeDescriptorManager.cpp b/Modules/QtWidgets/src/QmitkNodeDescriptorManager.cpp index 2969362b5b..da0344c151 100644 --- a/Modules/QtWidgets/src/QmitkNodeDescriptorManager.cpp +++ b/Modules/QtWidgets/src/QmitkNodeDescriptorManager.cpp @@ -1,180 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include QmitkNodeDescriptorManager* QmitkNodeDescriptorManager::GetInstance() { static QmitkNodeDescriptorManager _Instance; return &_Instance; /* static std::auto_ptr instance; if(instance.get() == 0) { instance.reset(new QmitkNodeDescriptorManager()); instance->Initialize(); } return instance.get();*/ } void QmitkNodeDescriptorManager::Initialize() { // Adding "Images" mitk::NodePredicateDataType::Pointer isImage = mitk::NodePredicateDataType::New("Image"); this->AddDescriptor(new QmitkNodeDescriptor(tr("Image"), QString(":/Qmitk/Images_48.png"), isImage, this)); // Adding "Image Masks" mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isBinaryImage = mitk::NodePredicateAnd::New(isBinary, isImage); this->AddDescriptor(new QmitkNodeDescriptor(tr("ImageMask"), QString(":/Qmitk/Binaerbilder_48.png"), isBinaryImage, this)); + // Adding "LabelSet Image" + mitk::NodePredicateDataType::Pointer isLabelSetImage = mitk::NodePredicateDataType::New("LabelSetImage"); + this->AddDescriptor(new QmitkNodeDescriptor(tr("LabelSetImage"), QString(":/Qmitk/LabelSetImage_48.png"), isLabelSetImage, this)); + // Adding "PointSet" mitk::NodePredicateDataType::Pointer isPointSet = mitk::NodePredicateDataType::New("PointSet"); this->AddDescriptor(new QmitkNodeDescriptor(tr("PointSet"), QString(":/Qmitk/PointSet_48.png"), isPointSet, this)); // Adding "Surface" mitk::NodePredicateDataType::Pointer isSurface = mitk::NodePredicateDataType::New("Surface"); this->AddDescriptor(new QmitkNodeDescriptor(tr("Surface"), QString(":/Qmitk/Surface_48.png"), isSurface, this)); // Adding "NoneBinaryImages" mitk::NodePredicateNot::Pointer isNotBinary = mitk::NodePredicateNot::New(isBinary); mitk::NodePredicateAnd::Pointer isNoneBinaryImage = mitk::NodePredicateAnd::New(isImage, isNotBinary); this->AddDescriptor(new QmitkNodeDescriptor(tr("NoneBinaryImage"), QString(":/Qmitk/Images_48.png"), isNoneBinaryImage, this)); } void QmitkNodeDescriptorManager::AddDescriptor( QmitkNodeDescriptor* _Descriptor ) { _Descriptor->setParent(this); m_NodeDescriptors.push_back(_Descriptor); } void QmitkNodeDescriptorManager::RemoveDescriptor( QmitkNodeDescriptor* _Descriptor ) { int index = m_NodeDescriptors.indexOf(_Descriptor); if(index != -1) { m_NodeDescriptors.removeAt(index); _Descriptor->setParent(0); delete _Descriptor; } } QmitkNodeDescriptor* QmitkNodeDescriptorManager::GetDescriptor( const mitk::DataNode* _Node ) const { QmitkNodeDescriptor* _Descriptor = m_UnknownDataNodeDescriptor; for(QList::const_iterator it = m_NodeDescriptors.begin(); it != m_NodeDescriptors.end(); ++it) { if((*it)->CheckNode(_Node)) _Descriptor = *it; } return _Descriptor; } QmitkNodeDescriptor* QmitkNodeDescriptorManager::GetDescriptor( const QString& _ClassName ) const { QmitkNodeDescriptor* _Descriptor = 0; if( _ClassName == "Unknown" ) { return m_UnknownDataNodeDescriptor; } else { for(QList::const_iterator it = m_NodeDescriptors.begin(); it != m_NodeDescriptors.end(); ++it) { if((*it)->GetClassName() == _ClassName) _Descriptor = *it; } } return _Descriptor; } QList QmitkNodeDescriptorManager::GetActions( const mitk::DataNode* _Node ) const { QList actions = m_UnknownDataNodeDescriptor->GetBatchActions(); actions.append(m_UnknownDataNodeDescriptor->GetActions()); QmitkNodeDescriptor* lastDescriptor = m_UnknownDataNodeDescriptor; for(QList::const_iterator it = m_NodeDescriptors.begin(); it != m_NodeDescriptors.end(); ++it) { if((*it)->CheckNode(_Node)) { actions.append(lastDescriptor->GetSeparator()); lastDescriptor = *it; actions.append(lastDescriptor->GetBatchActions()); actions.append(lastDescriptor->GetActions()); } } return actions; } QList QmitkNodeDescriptorManager::GetActions( const QList &_Nodes ) const { QList actions = m_UnknownDataNodeDescriptor->GetBatchActions(); QSet nodeDescriptors; QmitkNodeDescriptor* lastDescriptor; // find all descriptors for the nodes (unique) foreach (mitk::DataNode::Pointer node, _Nodes) { lastDescriptor = this->GetDescriptor(node); nodeDescriptors.insert(lastDescriptor); } // add all actions for the found descriptors lastDescriptor = m_UnknownDataNodeDescriptor; foreach (QmitkNodeDescriptor* descr, nodeDescriptors) { actions.append(lastDescriptor->GetSeparator()); lastDescriptor = descr; actions.append(lastDescriptor->GetBatchActions()); } return actions; } QmitkNodeDescriptorManager::QmitkNodeDescriptorManager() : m_UnknownDataNodeDescriptor(new QmitkNodeDescriptor("Unknown", QString(":/Qmitk/DataTypeUnknown_48.png"), 0, this)) { this->Initialize(); } QmitkNodeDescriptorManager::~QmitkNodeDescriptorManager() { //delete m_UnknownDataNodeDescriptor; //qDeleteAll(m_NodeDescriptors); } QmitkNodeDescriptor* QmitkNodeDescriptorManager::GetUnknownDataNodeDescriptor() const { return m_UnknownDataNodeDescriptor; } diff --git a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp index e96bfe4518..ae9e1495e4 100644 --- a/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp +++ b/Modules/Segmentation/Interactions/mitkBinaryThresholdULTool.cpp @@ -1,321 +1,321 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkBinaryThresholdULTool.h" #include "mitkBinaryThresholdULTool.xpm" #include "mitkToolManager.h" #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkImageTimeSelector.h" #include #include #include "mitkMaskAndCutRoiImageFilter.h" #include "mitkPadImageFilter.h" // us #include "usModule.h" #include "usModuleResource.h" #include "usGetModuleContext.h" #include "usModuleContext.h" namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, BinaryThresholdULTool, "ThresholdingUL tool"); } mitk::BinaryThresholdULTool::BinaryThresholdULTool() :m_SensibleMinimumThresholdValue(-100), m_SensibleMaximumThresholdValue(+100), m_CurrentLowerThresholdValue(1), m_CurrentUpperThresholdValue(1) { m_ThresholdFeedbackNode = DataNode::New(); m_ThresholdFeedbackNode->SetProperty( "color", ColorProperty::New(0.0, 1.0, 0.0) ); m_ThresholdFeedbackNode->SetProperty( "name", StringProperty::New("Thresholding feedback") ); m_ThresholdFeedbackNode->SetProperty( "opacity", FloatProperty::New(0.3) ); m_ThresholdFeedbackNode->SetProperty("binary", BoolProperty::New(true)); m_ThresholdFeedbackNode->SetProperty( "helper object", BoolProperty::New(true) ); } mitk::BinaryThresholdULTool::~BinaryThresholdULTool() { } const char** mitk::BinaryThresholdULTool::GetXPM() const { return NULL; } us::ModuleResource mitk::BinaryThresholdULTool::GetIconResource() const { us::Module* module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("TwoThresholds_48x48.png"); return resource; } const char* mitk::BinaryThresholdULTool::GetName() const { return "UL Threshold"; } void mitk::BinaryThresholdULTool::Activated() { m_ToolManager->RoiDataChanged += mitk::MessageDelegate(this, &mitk::BinaryThresholdULTool::OnRoiDataChanged); m_OriginalImageNode = m_ToolManager->GetReferenceData(0); m_NodeForThresholding = m_OriginalImageNode; if ( m_NodeForThresholding.IsNotNull() ) { SetupPreviewNode(); } else { m_ToolManager->ActivateTool(-1); } } void mitk::BinaryThresholdULTool::Deactivated() { m_ToolManager->RoiDataChanged -= mitk::MessageDelegate(this, &mitk::BinaryThresholdULTool::OnRoiDataChanged); m_NodeForThresholding = NULL; m_OriginalImageNode = NULL; try { if (DataStorage* storage = m_ToolManager->GetDataStorage()) { storage->Remove( m_ThresholdFeedbackNode ); RenderingManager::GetInstance()->RequestUpdateAll(); } } catch(...) { // don't care } m_ThresholdFeedbackNode->SetData(NULL); } void mitk::BinaryThresholdULTool::SetThresholdValues(double lower, double upper) { if (m_ThresholdFeedbackNode.IsNotNull()) { m_CurrentLowerThresholdValue = lower; m_CurrentUpperThresholdValue = upper; UpdatePreview(); } } void mitk::BinaryThresholdULTool::AcceptCurrentThresholdValue() { CreateNewSegmentationFromThreshold(m_NodeForThresholding); RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdULTool::CancelThresholding() { m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdULTool::SetupPreviewNode() { if (m_NodeForThresholding.IsNotNull()) { Image::Pointer image = dynamic_cast( m_NodeForThresholding->GetData() ); Image::Pointer originalImage = dynamic_cast (m_OriginalImageNode->GetData()); if (image.IsNotNull()) { mitk::Image* workingimage = dynamic_cast(m_ToolManager->GetWorkingData(0)->GetData()); if(workingimage) m_ThresholdFeedbackNode->SetData( workingimage->Clone() ); else m_ThresholdFeedbackNode->SetData( mitk::Image::New() ); int layer(50); m_NodeForThresholding->GetIntProperty("layer", layer); m_ThresholdFeedbackNode->SetIntProperty("layer", layer+1); if (DataStorage* ds = m_ToolManager->GetDataStorage()) { if (!ds->Exists(m_ThresholdFeedbackNode)) ds->Add( m_ThresholdFeedbackNode, m_OriginalImageNode ); } if (image.GetPointer() == originalImage.GetPointer()) { m_SensibleMinimumThresholdValue = static_cast( originalImage->GetScalarValueMin() ); m_SensibleMaximumThresholdValue = static_cast( originalImage->GetScalarValueMax() ); } m_CurrentLowerThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue) / 3.0; m_CurrentUpperThresholdValue = 2.0 * m_CurrentLowerThresholdValue; IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue); ThresholdingValuesChanged.Send(m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue); } } } template static void ITKSetVolume( itk::Image* originalImage, mitk::Image* segmentation, unsigned int timeStep ) { segmentation->SetVolume( (void*) originalImage->GetPixelContainer()->GetBufferPointer(), timeStep); } void mitk::BinaryThresholdULTool::CreateNewSegmentationFromThreshold(DataNode* node) { if (node) { Image::Pointer feedBackImage = dynamic_cast( m_ThresholdFeedbackNode->GetData() ); if (feedBackImage.IsNotNull()) { // create a new image of the same dimensions and smallest possible pixel type DataNode::Pointer emptySegmentation = GetTargetSegmentationNode(); if (emptySegmentation) { // actually perform a thresholding and ask for an organ type for (unsigned int timeStep = 0; timeStep < feedBackImage->GetTimeSteps(); ++timeStep) { try { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( feedBackImage ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer feedBackImage3D = timeSelector->GetOutput(); if (feedBackImage3D->GetDimension() == 2) { AccessFixedDimensionByItk_2( feedBackImage3D, ITKSetVolume, 2, dynamic_cast(emptySegmentation->GetData()), timeStep ); } else { AccessFixedDimensionByItk_2( feedBackImage3D, ITKSetVolume, 3, dynamic_cast(emptySegmentation->GetData()), timeStep ); } } catch(...) { Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); } } //since we are maybe working on a smaller image, pad it to the size of the original image if (m_OriginalImageNode.GetPointer() != m_NodeForThresholding.GetPointer()) { mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); padFilter->SetInput(0, dynamic_cast (emptySegmentation->GetData())); padFilter->SetInput(1, dynamic_cast (m_OriginalImageNode->GetData())); padFilter->SetBinaryFilter(true); padFilter->SetUpperThreshold(1); padFilter->SetLowerThreshold(1); padFilter->Update(); emptySegmentation->SetData(padFilter->GetOutput()); } m_ToolManager->SetWorkingData( emptySegmentation ); m_ToolManager->GetWorkingData(0)->Modified(); } } } } void mitk::BinaryThresholdULTool::OnRoiDataChanged() { mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); if (node.IsNotNull()) { mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); mitk::Image::Pointer image = dynamic_cast (m_NodeForThresholding->GetData()); if (image.IsNull()) return; roiFilter->SetInput(image); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); tmpNode->SetData(roiFilter->GetOutput()); m_SensibleMinimumThresholdValue = static_cast( roiFilter->GetMinValue()); m_SensibleMaximumThresholdValue = static_cast( roiFilter->GetMaxValue()); m_NodeForThresholding = tmpNode; } else m_NodeForThresholding = m_OriginalImageNode; this->SetupPreviewNode(); this->UpdatePreview(); } template static void ITKThresholding( itk::Image* originalImage, mitk::Image* segmentation, double lower, double upper, unsigned int timeStep ) { typedef itk::Image ImageType; - typedef itk::Image SegmentationType; + typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); filter->SetInput(originalImage); filter->SetLowerThreshold(lower); filter->SetUpperThreshold(upper); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); segmentation->SetVolume( (void*) (filter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); } void mitk::BinaryThresholdULTool::UpdatePreview() { mitk::Image::Pointer thresholdImage = dynamic_cast (m_NodeForThresholding->GetData()); mitk::Image::Pointer previewImage = dynamic_cast (m_ThresholdFeedbackNode->GetData()); if(thresholdImage && previewImage) { for (unsigned int timeStep = 0; timeStep < thresholdImage->GetTimeSteps(); ++timeStep) { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( thresholdImage ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer feedBackImage3D = timeSelector->GetOutput(); AccessByItk_n(feedBackImage3D, ITKThresholding, (previewImage, m_CurrentLowerThresholdValue, m_CurrentUpperThresholdValue, timeStep)); } RenderingManager::GetInstance()->RequestUpdateAll(); } } diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool.h b/Modules/Segmentation/Interactions/mitkFastMarchingTool.h index 761545fcc5..f987cba635 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool.h +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool.h @@ -1,184 +1,184 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkFastMarchingTool_h_Included #define mitkFastMarchingTool_h_Included #include "mitkFeedbackContourTool.h" #include "mitkLegacyAdaptors.h" #include #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkToolCommand.h" #include "mitkPositionEvent.h" #include "mitkMessage.h" #include "itkImage.h" //itk filter #include "itkFastMarchingImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "itkSigmoidImageFilter.h" #include "itkCurvatureAnisotropicDiffusionImageFilter.h" namespace us { class ModuleResource; } namespace mitk { class StateMachineAction; class InteractionEvent; /** \brief FastMarching semgentation tool. The segmentation is done by setting one or more seed points on the image and adapting the time range and threshold. The pipeline is: Smoothing->GradientMagnitude->SigmoidFunction->FastMarching->Threshold The resulting binary image is seen as a segmentation of an object. For detailed documentation see ITK Software Guide section 9.3.1 Fast Marching Segmentation. */ class MITKSEGMENTATION_EXPORT FastMarchingTool : public FeedbackContourTool { mitkNewMessageMacro(Ready); public: mitkClassMacro(FastMarchingTool, FeedbackContourTool); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /* typedefs for itk pipeline */ typedef float InternalPixelType; typedef itk::Image< InternalPixelType, 2 > InternalImageType; - typedef unsigned char OutputPixelType; + typedef mitk::Tool::DefaultSegmentationDataType OutputPixelType; typedef itk::Image< OutputPixelType, 2 > OutputImageType; typedef itk::BinaryThresholdImageFilter< InternalImageType, OutputImageType > ThresholdingFilterType; typedef itk::CurvatureAnisotropicDiffusionImageFilter< InternalImageType, InternalImageType > SmoothingFilterType; typedef itk::GradientMagnitudeRecursiveGaussianImageFilter< InternalImageType, InternalImageType > GradientFilterType; typedef itk::SigmoidImageFilter< InternalImageType, InternalImageType > SigmoidFilterType; typedef itk::FastMarchingImageFilter< InternalImageType, InternalImageType > FastMarchingFilterType; typedef FastMarchingFilterType::NodeContainer NodeContainer; typedef FastMarchingFilterType::NodeType NodeType; /* icon stuff */ virtual const char** GetXPM() const override; virtual const char* GetName() const override; virtual us::ModuleResource GetCursorIconResource() const override; us::ModuleResource GetIconResource() const override; /// \brief Set parameter used in Threshold filter. void SetUpperThreshold(double); /// \brief Set parameter used in Threshold filter. void SetLowerThreshold(double); /// \brief Set parameter used in Fast Marching filter. void SetStoppingValue(double); /// \brief Set parameter used in Gradient Magnitude filter. void SetSigma(double); /// \brief Set parameter used in Fast Marching filter. void SetAlpha(double); /// \brief Set parameter used in Fast Marching filter. void SetBeta(double); /// \brief Adds the feedback image to the current working image. virtual void ConfirmSegmentation(); /// \brief Set the working time step. virtual void SetCurrentTimeStep(int t); /// \brief Clear all seed points. void ClearSeeds(); /// \brief Updates the itk pipeline and shows the result of FastMarching. void Update(); protected: FastMarchingTool(); virtual ~FastMarchingTool(); void ConnectActionsAndFunctions() override; //virtual float CanHandleEvent( StateEvent const *stateEvent) const; virtual void Activated() override; virtual void Deactivated() override; virtual void Initialize(); virtual void BuildITKPipeline(); /// \brief Add point action of StateMachine pattern virtual bool OnAddPoint ( StateMachineAction*, InteractionEvent* interactionEvent ); /// \brief Delete action of StateMachine pattern virtual bool OnDelete ( StateMachineAction*, InteractionEvent* interactionEvent ); /// \brief Reset all relevant inputs of the itk pipeline. void Reset(); mitk::ToolCommand::Pointer m_ProgressCommand; Image::Pointer m_ReferenceImage; Image::Pointer m_ReferenceImageSlice; bool m_NeedUpdate; int m_CurrentTimeStep; mitk::InteractionPositionEvent::Pointer m_PositionEvent; float m_LowerThreshold; //used in Threshold filter float m_UpperThreshold; //used in Threshold filter float m_StoppingValue; //used in Fast Marching filter float m_Sigma; //used in GradientMagnitude filter float m_Alpha; //used in Sigmoid filter float m_Beta; //used in Sigmoid filter NodeContainer::Pointer m_SeedContainer; //seed points for FastMarching InternalImageType::Pointer m_ReferenceImageSliceAsITK; //the reference image as itk::Image mitk::DataNode::Pointer m_ResultImageNode;//holds the result as a preview image mitk::DataNode::Pointer m_SeedsAsPointSetNode;//used to visualize the seed points mitk::PointSet::Pointer m_SeedsAsPointSet; ThresholdingFilterType::Pointer m_ThresholdFilter; SmoothingFilterType::Pointer m_SmoothFilter; GradientFilterType::Pointer m_GradientMagnitudeFilter; SigmoidFilterType::Pointer m_SigmoidFilter; FastMarchingFilterType::Pointer m_FastMarchingFilter; private: PlaneGeometry::Pointer m_WorkingPlane; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h index d80548d0bc..52da82660d 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h @@ -1,171 +1,171 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkFastMarchingTool3D_h_Included #define mitkFastMarchingTool3D_h_Included #include "mitkAutoSegmentationTool.h" #include "mitkLegacyAdaptors.h" #include #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkPointSetInteractor.h" #include "mitkToolCommand.h" #include "mitkMessage.h" #include "itkImage.h" //itk filter #include "itkFastMarchingImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "itkSigmoidImageFilter.h" #include "itkCurvatureAnisotropicDiffusionImageFilter.h" namespace us { class ModuleResource; } namespace mitk { /** \brief FastMarching semgentation tool. The segmentation is done by setting one or more seed points on the image and adapting the time range and threshold. The pipeline is: Smoothing->GradientMagnitude->SigmoidFunction->FastMarching->Threshold The resulting binary image is seen as a segmentation of an object. For detailed documentation see ITK Software Guide section 9.3.1 Fast Marching Segmentation. */ class MITKSEGMENTATION_EXPORT FastMarchingTool3D : public AutoSegmentationTool { mitkNewMessageMacro(Ready); public: mitkClassMacro(FastMarchingTool3D, AutoSegmentationTool) itkFactorylessNewMacro(Self) itkCloneMacro(Self) /* typedefs for itk pipeline */ typedef float InternalPixelType; typedef itk::Image< InternalPixelType, 3 > InternalImageType; - typedef unsigned char OutputPixelType; + typedef mitk::Tool::DefaultSegmentationDataType OutputPixelType; typedef itk::Image< OutputPixelType, 3 > OutputImageType; typedef itk::BinaryThresholdImageFilter< InternalImageType, OutputImageType > ThresholdingFilterType; typedef itk::CurvatureAnisotropicDiffusionImageFilter< InternalImageType, InternalImageType > SmoothingFilterType; typedef itk::GradientMagnitudeRecursiveGaussianImageFilter< InternalImageType, InternalImageType > GradientFilterType; typedef itk::SigmoidImageFilter< InternalImageType, InternalImageType > SigmoidFilterType; typedef itk::FastMarchingImageFilter< InternalImageType, InternalImageType > FastMarchingFilterType; typedef FastMarchingFilterType::NodeContainer NodeContainer; typedef FastMarchingFilterType::NodeType NodeType; bool CanHandle(BaseData* referenceData) const override; /* icon stuff */ virtual const char** GetXPM() const override; virtual const char* GetName() const override; us::ModuleResource GetIconResource() const override; /// \brief Set parameter used in Threshold filter. void SetUpperThreshold(double); /// \brief Set parameter used in Threshold filter. void SetLowerThreshold(double); /// \brief Set parameter used in Fast Marching filter. void SetStoppingValue(double); /// \brief Set parameter used in Gradient Magnitude filter. void SetSigma(double); /// \brief Set parameter used in Fast Marching filter. void SetAlpha(double); /// \brief Set parameter used in Fast Marching filter. void SetBeta(double); /// \brief Adds the feedback image to the current working image. virtual void ConfirmSegmentation(); /// \brief Set the working time step. virtual void SetCurrentTimeStep(int t); /// \brief Clear all seed points. void ClearSeeds(); /// \brief Updates the itk pipeline and shows the result of FastMarching. void Update(); protected: FastMarchingTool3D(); virtual ~FastMarchingTool3D(); virtual void Activated() override; virtual void Deactivated() override; virtual void Initialize(); /// \brief Add point action of StateMachine pattern virtual void OnAddPoint (); /// \brief Delete action of StateMachine pattern virtual void OnDelete (); /// \brief Reset all relevant inputs of the itk pipeline. void Reset(); mitk::ToolCommand::Pointer m_ProgressCommand; Image::Pointer m_ReferenceImage; bool m_NeedUpdate; int m_CurrentTimeStep; float m_LowerThreshold; //used in Threshold filter float m_UpperThreshold; //used in Threshold filter float m_StoppingValue; //used in Fast Marching filter float m_Sigma; //used in GradientMagnitude filter float m_Alpha; //used in Sigmoid filter float m_Beta; //used in Sigmoid filter NodeContainer::Pointer m_SeedContainer; //seed points for FastMarching InternalImageType::Pointer m_ReferenceImageAsITK; //the reference image as itk::Image mitk::DataNode::Pointer m_ResultImageNode;//holds the result as a preview image mitk::DataNode::Pointer m_SeedsAsPointSetNode;//used to visualize the seed points mitk::PointSet::Pointer m_SeedsAsPointSet; mitk::PointSetInteractor::Pointer m_SeedPointInteractor; unsigned int m_PointSetAddObserverTag; unsigned int m_PointSetRemoveObserverTag; ThresholdingFilterType::Pointer m_ThresholdFilter; SmoothingFilterType::Pointer m_SmoothFilter; GradientFilterType::Pointer m_GradientMagnitudeFilter; SigmoidFilterType::Pointer m_SigmoidFilter; FastMarchingFilterType::Pointer m_FastMarchingFilter; }; } // namespace #endif diff --git a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp index aabebb886d..1083ef4282 100644 --- a/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp +++ b/Modules/Segmentation/Interactions/mitkOtsuTool3D.cpp @@ -1,303 +1,303 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // MITK #include "mitkOtsuTool3D.h" #include "mitkToolManager.h" #include "mitkRenderingManager.h" #include #include #include #include #include #include #include "mitkOtsuSegmentationFilter.h" #include "mitkImage.h" #include "mitkImageAccessByItk.h" // ITK #include #include #include #include "mitkRegionGrow3DTool.xpm" // us #include #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, OtsuTool3D, "Otsu Segmentation"); } mitk::OtsuTool3D::OtsuTool3D() { } mitk::OtsuTool3D::~OtsuTool3D() { } void mitk::OtsuTool3D::Activated() { if (m_ToolManager) { m_OriginalImage = dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData()); m_BinaryPreviewNode = mitk::DataNode::New(); m_BinaryPreviewNode->SetName("Binary_Preview"); m_BinaryPreviewNode->SetProperty( "color", ColorProperty::New(0.0, 1.0, 0.0) ); m_BinaryPreviewNode->SetProperty( "opacity", FloatProperty::New(0.3) ); //m_BinaryPreviewNode->SetBoolProperty("helper object", true); //m_BinaryPreviewNode->SetProperty("binary", mitk::BoolProperty::New(true)); m_ToolManager->GetDataStorage()->Add( this->m_BinaryPreviewNode ); m_MultiLabelResultNode = mitk::DataNode::New(); m_MultiLabelResultNode->SetName("Otsu_Preview"); //m_MultiLabelResultNode->SetBoolProperty("helper object", true); m_MultiLabelResultNode->SetVisibility(true); m_MaskedImagePreviewNode = mitk::DataNode::New(); m_MaskedImagePreviewNode->SetName("Volume_Preview"); //m_MultiLabelResultNode->SetBoolProperty("helper object", true); m_MaskedImagePreviewNode->SetVisibility(false); m_ToolManager->GetDataStorage()->Add( this->m_MultiLabelResultNode ); } } void mitk::OtsuTool3D::Deactivated() { m_ToolManager->GetDataStorage()->Remove( this->m_MultiLabelResultNode ); m_MultiLabelResultNode = NULL; m_ToolManager->GetDataStorage()->Remove( this->m_BinaryPreviewNode ); m_BinaryPreviewNode = NULL; m_ToolManager->GetDataStorage()->Remove( this->m_MaskedImagePreviewNode); m_MaskedImagePreviewNode = NULL; } const char** mitk::OtsuTool3D::GetXPM() const { return NULL; } us::ModuleResource mitk::OtsuTool3D::GetIconResource() const { us::Module* module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("Otsu_48x48.png"); return resource; } void mitk::OtsuTool3D::RunSegmentation(int regions, bool useValley, int numberOfBins) { //this->m_OtsuSegmentationDialog->setCursor(Qt::WaitCursor); int numberOfThresholds = regions - 1; unsigned int timestep = mitk::RenderingManager::GetInstance()->GetTimeNavigationController()->GetTime()->GetPos(); mitk::Image::Pointer image3D = Get3DImage(m_OriginalImage, timestep); mitk::OtsuSegmentationFilter::Pointer otsuFilter = mitk::OtsuSegmentationFilter::New(); otsuFilter->SetNumberOfThresholds( numberOfThresholds ); otsuFilter->SetValleyEmphasis( useValley ); otsuFilter->SetNumberOfBins( numberOfBins ); otsuFilter->SetInput( image3D ); try { otsuFilter->Update(); } catch( ... ) { mitkThrow() << "itkOtsuFilter error (image dimension must be in {2, 3} and image must not be RGB)"; } m_ToolManager->GetDataStorage()->Remove( this->m_MultiLabelResultNode ); m_MultiLabelResultNode = NULL; m_MultiLabelResultNode = mitk::DataNode::New(); m_MultiLabelResultNode->SetName("Otsu_Preview"); m_MultiLabelResultNode->SetVisibility(true); m_ToolManager->GetDataStorage()->Add( this->m_MultiLabelResultNode ); m_MultiLabelResultNode->SetOpacity(1.0); this->m_MultiLabelResultNode->SetData( otsuFilter->GetOutput() ); m_MultiLabelResultNode->SetProperty("binary", mitk::BoolProperty::New(false)); mitk::RenderingModeProperty::Pointer renderingMode = mitk::RenderingModeProperty::New(); renderingMode->SetValue( mitk::RenderingModeProperty::LOOKUPTABLE_LEVELWINDOW_COLOR ); m_MultiLabelResultNode->SetProperty("Image Rendering.Mode", renderingMode); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); mitk::LookupTableProperty::Pointer prop = mitk::LookupTableProperty::New(lut); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetHueRange(1.0, 0.0); lookupTable->SetSaturationRange(1.0, 1.0); lookupTable->SetValueRange(1.0, 1.0); lookupTable->SetTableRange(-1.0, 1.0); lookupTable->Build(); lut->SetVtkLookupTable(lookupTable); prop->SetLookupTable(lut); m_MultiLabelResultNode->SetProperty("LookupTable",prop); mitk::LevelWindowProperty::Pointer levWinProp = mitk::LevelWindowProperty::New(); mitk::LevelWindow levelwindow; levelwindow.SetRangeMinMax(0, numberOfThresholds + 1); levWinProp->SetLevelWindow( levelwindow ); m_MultiLabelResultNode->SetProperty( "levelwindow", levWinProp ); //m_BinaryPreviewNode->SetVisibility(false); // m_MultiLabelResultNode->SetVisibility(true); //this->m_OtsuSegmentationDialog->setCursor(Qt::ArrowCursor); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::OtsuTool3D::ConfirmSegmentation() { GetTargetSegmentationNode()->SetData(dynamic_cast(m_BinaryPreviewNode->GetData())); m_ToolManager->ActivateTool(-1); } void mitk::OtsuTool3D::UpdateBinaryPreview(std::vector regionIDs) { m_MultiLabelResultNode->SetVisibility(false); mitk::Image::Pointer multiLabelSegmentation = dynamic_cast(m_MultiLabelResultNode->GetData()); AccessByItk_1( multiLabelSegmentation, CalculatePreview, regionIDs); } template< typename TPixel, unsigned int VImageDimension> void mitk::OtsuTool3D::CalculatePreview(itk::Image< TPixel, VImageDimension>* itkImage, std::vector regionIDs) { typedef itk::Image< TPixel, VImageDimension > InputImageType; - typedef itk::Image< unsigned char, VImageDimension > OutputImageType; + typedef itk::Image< mitk::Tool::DefaultSegmentationDataType, VImageDimension > OutputImageType; typedef itk::BinaryThresholdImageFilter< InputImageType, OutputImageType > FilterType; typename FilterType::Pointer filter = FilterType::New(); //InputImageType::Pointer itkImage; typename OutputImageType::Pointer itkBinaryTempImage1; typename OutputImageType::Pointer itkBinaryTempImage2; typename OutputImageType::Pointer itkBinaryResultImage; //mitk::Image::Pointer multiLabelSegmentation = dynamic_cast(m_MultiLabelResultNode->GetData()); //mitk::CastToItkImage(multiLabelSegmentation, itkImage); filter->SetInput(itkImage); filter->SetLowerThreshold(regionIDs[0]); filter->SetUpperThreshold(regionIDs[0]); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); itkBinaryTempImage2 = filter->GetOutput(); typename itk::OrImageFilter::Pointer orFilter = itk::OrImageFilter::New(); // if more than one region id is used compute the union of all given binary regions for (std::vector::iterator it = regionIDs.begin() ; it != regionIDs.end(); ++it) { filter->SetLowerThreshold(*it); filter->SetUpperThreshold(*it); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); itkBinaryTempImage1 = filter->GetOutput(); orFilter->SetInput1(itkBinaryTempImage1); orFilter->SetInput2(itkBinaryTempImage2); orFilter->UpdateLargestPossibleRegion(); itkBinaryResultImage = orFilter->GetOutput(); itkBinaryTempImage2 = itkBinaryResultImage; } //---------------------------------------------------------------------------------------------------- mitk::Image::Pointer binarySegmentation; mitk::CastToMitkImage( itkBinaryResultImage, binarySegmentation); m_BinaryPreviewNode->SetData(binarySegmentation); m_BinaryPreviewNode->SetVisibility(true); m_BinaryPreviewNode->SetProperty("outline binary", mitk::BoolProperty::New(false)); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } //void mitk::OtsuTool3D::UpdateBinaryPreview(int regionID) //{ // m_MultiLabelResultNode->SetVisibility(false); // //pixel with regionID -> binary image // const unsigned short dim = 3; // typedef unsigned char PixelType; // // typedef itk::Image< PixelType, dim > InputImageType; // typedef itk::Image< PixelType, dim > OutputImageType; // // typedef itk::BinaryThresholdImageFilter< InputImageType, OutputImageType > FilterType; // // FilterType::Pointer filter = FilterType::New(); // // InputImageType::Pointer itkImage; // // mitk::Image::Pointer multiLabelSegmentation = dynamic_cast(m_MultiLabelResultNode->GetData()); // mitk::CastToItkImage(multiLabelSegmentation, itkImage); // // filter->SetInput(itkImage); // filter->SetLowerThreshold(regionID); // filter->SetUpperThreshold(regionID); // filter->SetInsideValue(1); // filter->SetOutsideValue(0); // filter->Update(); // mitk::Image::Pointer binarySegmentation; // mitk::CastToMitkImage( filter->GetOutput(), binarySegmentation); // m_BinaryPreviewNode->SetData(binarySegmentation); // m_BinaryPreviewNode->SetVisibility(true); // m_BinaryPreviewNode->SetProperty("outline binary", mitk::BoolProperty::New(false)); // // mitk::RenderingManager::GetInstance()->RequestUpdateAll(); //} const char* mitk::OtsuTool3D::GetName() const { return "Otsu"; } void mitk::OtsuTool3D::UpdateVolumePreview(bool volumeRendering) { if (volumeRendering) { m_MaskedImagePreviewNode->SetBoolProperty("volumerendering", true); m_MaskedImagePreviewNode->SetBoolProperty("volumerendering.uselod", true); } else { m_MaskedImagePreviewNode->SetBoolProperty("volumerendering", false); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::OtsuTool3D::ShowMultiLabelResultNode(bool show) { m_MultiLabelResultNode->SetVisibility(show); m_BinaryPreviewNode->SetVisibility(!show); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } int mitk::OtsuTool3D::GetNumberOfBins() { ScalarType min = m_OriginalImage.GetPointer()->GetStatistics()->GetScalarValueMin(); ScalarType max = m_OriginalImage.GetPointer()->GetStatistics()->GetScalarValueMaxNoRecompute(); return static_cast(max-min) + 1; } diff --git a/Modules/Segmentation/Interactions/mitkRegionGrow3DTool.cpp b/Modules/Segmentation/Interactions/mitkRegionGrow3DTool.cpp index e1a3cbb629..818b02df29 100644 --- a/Modules/Segmentation/Interactions/mitkRegionGrow3DTool.cpp +++ b/Modules/Segmentation/Interactions/mitkRegionGrow3DTool.cpp @@ -1,439 +1,439 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkRegionGrow3DTool.h" #include "mitkToolManager.h" #include "mitkRenderingManager.h" #include "mitkLevelWindowProperty.h" #include "mitkPointSetInteractor.h" #include "mitkGlobalInteraction.h" #include "mitkITKImageImport.h" #include "itkImage.h" #include "itkBinaryThresholdImageFilter.h" #include "itkConnectedAdaptiveThresholdImageFilter.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkMaskAndCutRoiImageFilter.h" #include "mitkPadImageFilter.h" #include "mitkRegionGrow3DTool.xpm" namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, RegionGrow3DTool, "RegionGrower 3D"); } mitk::RegionGrow3DTool::RegionGrow3DTool(): Tool("PressMoveRelease"), m_LowerThreshold(-5000), m_UpperThreshold(5000), m_CurrentRGDirectionIsUpwards(false) { CONNECT_FUNCTION( "Release", OnMouseReleased); m_FeedbackNode = DataNode::New(); m_FeedbackNode->SetProperty( "color", ColorProperty::New(1.0, 0.0, 0.0) ); m_FeedbackNode->SetProperty( "texture interpolation", BoolProperty::New(false) ); m_FeedbackNode->SetProperty( "layer", IntProperty::New( 100 ) ); m_FeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(100, 1) ) ); m_FeedbackNode->SetProperty( "name", StringProperty::New("failsafe region grow feedback") ); m_FeedbackNode->SetProperty( "opacity", FloatProperty::New(0.3) ); m_FeedbackNode->SetProperty( "helper object", BoolProperty::New(true) ); m_FeedbackNode->SetVisibility(false); m_PointSetNode = mitk::DataNode::New(); m_PointSetNode->SetName("regiongrow3d pointset"); m_PointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true)); m_PointSetNode->SetProperty("layer", mitk::IntProperty::New(2)); mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); m_PointSetNode->SetData(pointSet); } mitk::RegionGrow3DTool::~RegionGrow3DTool() { } bool mitk::RegionGrow3DTool::OnMouseReleased( StateMachineAction*, InteractionEvent* /*interactionEvent*/ ) { mitk::PointSetInteractor::Pointer interactor = dynamic_cast (m_PointSetNode->GetInteractor()); if (interactor.IsNotNull()) { mitk::PointSet::Pointer pointSet = dynamic_cast (m_PointSetNode->GetData()); if (pointSet.IsNotNull()) { if (pointSet->GetSize() == 1) { //check if we have a valid picture this->RunSegmentation(); SeedButtonToggled.Send(false); } } } return true; } void mitk::RegionGrow3DTool::Activated() { if (m_ToolManager) { m_ToolManager->RoiDataChanged += mitk::MessageDelegate(this, &mitk::RegionGrow3DTool::UpdatePreview); m_OriginalImageNode = m_ToolManager->GetReferenceData(0); m_NodeToProceed = m_OriginalImageNode; if (m_NodeToProceed.IsNotNull()) { SetupPreviewNodeFor(m_NodeToProceed); mitk::Image::Pointer image = dynamic_cast (m_OriginalImageNode->GetData()); if (image.IsNotNull()) { m_RoiMin = image->GetScalarValueMin(); m_RoiMax = image->GetScalarValueMax(); } } else m_ToolManager->ActivateTool(-1); } } void mitk::RegionGrow3DTool::Deactivated() { m_ToolManager->RoiDataChanged -= mitk::MessageDelegate(this, &mitk::RegionGrow3DTool::UpdatePreview); if (mitk::DataStorage* ds = m_ToolManager->GetDataStorage()) { ds->Remove(m_PointSetNode); ds->Remove(m_FeedbackNode); } m_FeedbackNode->SetData(NULL); m_FeedbackNode->SetLevelWindow(NULL); m_FeedbackNode->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } const char* mitk::RegionGrow3DTool::GetName() const { return "RegionGrower 3D"; } const char** mitk::RegionGrow3DTool::GetXPM() const { return mitkRegionGrow3DTool_xpm; } void mitk::RegionGrow3DTool::SetSeedPoint(bool toggled) { if (!m_ToolManager->GetDataStorage()->Exists(m_PointSetNode)) //no pointSet present m_ToolManager->GetDataStorage()->Add(m_PointSetNode, m_OriginalImageNode); //add Interactor if there is none and add it to GlobalInteraction if (toggled == true) // button is down { mitk::PointSetInteractor::Pointer interactor = dynamic_cast (m_PointSetNode->GetInteractor()); if (interactor.IsNull()) { //create a new interactor and add it to node interactor = mitk::PointSetInteractor::New("singlepointinteractorwithoutshiftclick", m_PointSetNode, 1); } mitk::GlobalInteraction::GetInstance()->AddInteractor(interactor); } else { mitk::PointSetInteractor::Pointer interactor = dynamic_cast (m_PointSetNode->GetInteractor()); if (interactor.IsNotNull()) { m_PointSetNode->SetInteractor(NULL); mitk::GlobalInteraction::GetInstance()->RemoveInteractor(interactor); } } } void mitk::RegionGrow3DTool::RunSegmentation() { //safety if no pointSet or pointSet empty mitk::PointSet::Pointer seedPointSet = dynamic_cast (m_PointSetNode->GetData()); if (seedPointSet.IsNull()) { return; } if (!(seedPointSet->GetSize() > 0)) { return; } mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet()->GetPoints()->Begin().Value(); mitk::Image::Pointer image = dynamic_cast (m_NodeToProceed->GetData()); if (image.IsNotNull()) { m_LowerThreshold = static_cast (m_RoiMin); m_UpperThreshold = static_cast (m_RoiMax); AccessByItk_2(image, StartRegionGrowing, image->GetGeometry(), seedPoint); } } template void mitk::RegionGrow3DTool::StartRegionGrowing(itk::Image* itkImage, mitk::BaseGeometry* imageGeometry, mitk::PointSet::PointType seedPoint) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; typedef itk::ConnectedAdaptiveThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); if ( !imageGeometry->IsInside(seedPoint) ) { return; } IndexType seedIndex; imageGeometry->WorldToIndex( seedPoint, seedIndex);// convert world coordinates to image indices //int seedValue = itkImage->GetPixel(seedIndex); regionGrower->SetInput( itkImage ); regionGrower->AddSeed( seedIndex ); regionGrower->SetLower( m_LowerThreshold ); regionGrower->SetUpper( m_UpperThreshold ); regionGrower->SetGrowingDirectionIsUpwards( m_CurrentRGDirectionIsUpwards ); try { regionGrower->Update(); } catch( ... ) { MITK_ERROR << "Something went wrong!" << endl; return; } m_SeedpointValue = regionGrower->GetSeedpointValue(); //initialize slider if(m_CurrentRGDirectionIsUpwards) { UpperThresholdValueChanged.Send(m_UpperThreshold); LowerThresholdValueChanged.Send(m_SeedpointValue); } else { UpperThresholdValueChanged.Send(m_SeedpointValue); LowerThresholdValueChanged.Send(m_LowerThreshold); } m_DetectedLeakagePoint = regionGrower->GetLeakagePoint(); mitk::Image::Pointer resultImage = mitk::ImportItkImage(regionGrower->GetOutput())->Clone(); m_FeedbackNode->SetData( resultImage ); m_FeedbackNode->SetVisibility(true); InitializeLevelWindow(); } void mitk::RegionGrow3DTool::InitializeLevelWindow() { mitk::LevelWindow tempLevelWindow; m_FeedbackNode->GetLevelWindow(tempLevelWindow, NULL, "levelWindow"); mitk::ScalarType* level = new mitk::ScalarType(0.5); mitk::ScalarType* window = new mitk::ScalarType(1); int upper; if (m_CurrentRGDirectionIsUpwards) { upper = m_UpperThreshold - m_SeedpointValue; } else { upper = m_SeedpointValue - m_LowerThreshold; } tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper)); tempLevelWindow.SetLevelWindow(*level, *window); m_FeedbackNode->SetLevelWindow(tempLevelWindow, NULL, "levelWindow"); //get the suggested threshold from the detected leakage-point and adjust the slider if (m_CurrentRGDirectionIsUpwards) { SliderValueChanged.Send(m_SeedpointValue + m_DetectedLeakagePoint -1); } else { SliderValueChanged.Send(m_SeedpointValue - m_DetectedLeakagePoint +1); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::RegionGrow3DTool::ChangeLevelWindow(int value) { if (m_FeedbackNode.IsNull()) return; mitk::LevelWindow tempLevelWindow; m_FeedbackNode->GetLevelWindow(tempLevelWindow, NULL, "levelWindow"); //get the levelWindow associated with the preview mitk::ScalarType level;// = this->m_UPPERTHRESHOLD - newValue + 0.5; mitk::ScalarType* window = new mitk::ScalarType(1); //adjust the levelwindow according to the position of the slider (newvalue) if (m_CurrentRGDirectionIsUpwards) { level = m_UpperThreshold - value + 0.5; tempLevelWindow.SetLevelWindow(level, *window); } else { level = value - m_LowerThreshold +0.5; tempLevelWindow.SetLevelWindow(level, *window); } m_FeedbackNode->SetLevelWindow(tempLevelWindow, NULL, "levelWindow"); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::RegionGrow3DTool::ConfirmSegmentation( std::string name, mitk::Color color) { mitk::DataNode::Pointer new_node = mitk::DataNode::New(); new_node->SetColor(color); new_node->SetName(name); new_node->SetProperty("binary", mitk::BoolProperty::New("true")); mitk::Image* image = dynamic_cast (m_FeedbackNode->GetData()); mitk::LevelWindow tempLevelWindow; m_FeedbackNode->GetLevelWindow( tempLevelWindow, NULL, "levelWindow"); int upperThresholdLabeledImage = (short int) tempLevelWindow.GetRangeMax(); int lowerThresholdLabeledImage = (short int) tempLevelWindow.GetLowerWindowBound() + 1; typedef itk::Image InputImageType; - typedef itk::Image SegmentationType; + typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); InputImageType::Pointer itkImage; mitk::CastToItkImage(image, itkImage); filter->SetInput(itkImage); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->SetUpperThreshold(upperThresholdLabeledImage); filter->SetLowerThreshold(lowerThresholdLabeledImage); filter->Update(); mitk::Image::Pointer new_image = mitk::Image::New(); mitk::CastToMitkImage(filter->GetOutput(), new_image); //pad to original size if (m_OriginalImageNode.GetPointer() != m_NodeToProceed.GetPointer()) { mitk::PadImageFilter::Pointer padFilter = mitk::PadImageFilter::New(); padFilter->SetInput(0, new_image); padFilter->SetInput(1, dynamic_cast (m_OriginalImageNode->GetData())); padFilter->SetBinaryFilter(true); padFilter->SetUpperThreshold(1); padFilter->SetLowerThreshold(1); padFilter->Update(); new_image = padFilter->GetOutput(); } new_node->SetData(new_image); m_ToolManager->GetDataStorage()->Add(new_node); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } void mitk::RegionGrow3DTool::CancelSegmentation() { m_ToolManager->ActivateTool(-1); } void mitk::RegionGrow3DTool::SetupPreviewNodeFor( DataNode* nodeToProceed) { if (nodeToProceed) { Image::Pointer image = dynamic_cast( nodeToProceed->GetData() ); if (image.IsNotNull()) { m_FeedbackNode->SetData( image ); int layer(50); nodeToProceed->GetIntProperty("layer", layer); m_FeedbackNode->SetIntProperty("layer", layer+1); m_FeedbackNode->SetLevelWindow(NULL); if (DataStorage* storage = m_ToolManager->GetDataStorage()) { if (storage->Exists(m_FeedbackNode)) storage->Remove(m_FeedbackNode); storage->Add( m_FeedbackNode, nodeToProceed ); } } } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::RegionGrow3DTool::UpdatePreview() { typedef itk::Image ItkImageType; typedef itk::Image ItkMaskType; mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); if (node.IsNull()) { this->SetupPreviewNodeFor(m_OriginalImageNode); m_NodeToProceed = m_OriginalImageNode; mitk::Image::Pointer image = dynamic_cast (m_OriginalImageNode->GetData()); if (image.IsNotNull()) { m_RoiMin = image->GetScalarValueMin(); m_RoiMax = image->GetScalarValueMax(); } return; } mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); roiFilter->SetInput(dynamic_cast (m_NodeToProceed->GetData())); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); mitk::DataNode::Pointer new_node = mitk::DataNode::New(); mitk::Image::Pointer tmpImage = roiFilter->GetOutput(); new_node->SetData(tmpImage); m_RoiMax = roiFilter->GetMaxValue(); m_RoiMin = roiFilter->GetMinValue(); this->SetupPreviewNodeFor(new_node); m_NodeToProceed = new_node; //this->RunSegmentation(); } void mitk::RegionGrow3DTool::SetCurrentRGDirectionIsUpwards(bool flag) { m_CurrentRGDirectionIsUpwards = flag; } diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp index 51cb0f5803..24adad3290 100644 --- a/Modules/Segmentation/Interactions/mitkTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTool.cpp @@ -1,255 +1,275 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTool.h" #include "mitkProperties.h" +#include "mitkDataNodeFactory.h" +#include "mitkImageReadAccessor.h" #include "mitkImageWriteAccessor.h" +#include "mitkLabelSetImage.h" #include "mitkLevelWindowProperty.h" +#include "mitkLookupTableProperty.h" +#include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" -#include "mitkImageReadAccessor.h" // us -#include #include +#include +// itk #include mitk::Tool::Tool(const char* type) : m_PredicateImages(NodePredicateDataType::New("Image")) // for reference images , m_PredicateDim3(NodePredicateDimension::New(3, 1)) , m_PredicateDim4(NodePredicateDimension::New(4, 1)) , m_PredicateDimension( mitk::NodePredicateOr::New(m_PredicateDim3, m_PredicateDim4) ) , m_PredicateImage3D( NodePredicateAnd::New(m_PredicateImages, m_PredicateDimension) ) , m_PredicateBinary(NodePredicateProperty::New("binary", BoolProperty::New(true))) , m_PredicateNotBinary( NodePredicateNot::New(m_PredicateBinary) ) , m_PredicateSegmentation(NodePredicateProperty::New("segmentation", BoolProperty::New(true))) , m_PredicateNotSegmentation( NodePredicateNot::New(m_PredicateSegmentation) ) , m_PredicateHelper(NodePredicateProperty::New("helper object", BoolProperty::New(true))) , m_PredicateNotHelper( NodePredicateNot::New(m_PredicateHelper) ) , m_PredicateImageColorful( NodePredicateAnd::New(m_PredicateNotBinary, m_PredicateNotSegmentation) ) , m_PredicateImageColorfulNotHelper( NodePredicateAnd::New(m_PredicateImageColorful, m_PredicateNotHelper) ) , m_PredicateReference( NodePredicateAnd::New(m_PredicateImage3D, m_PredicateImageColorfulNotHelper) ) , m_IsSegmentationPredicate(NodePredicateAnd::New(NodePredicateOr::New(m_PredicateBinary, m_PredicateSegmentation), m_PredicateNotHelper)) , m_InteractorType( type ) { } mitk::Tool::~Tool() { } bool mitk::Tool::CanHandle(BaseData* referenceData) const { return true; } void mitk::Tool::InitializeStateMachine() { if (m_InteractorType.empty()) return; m_InteractorType += ".xml"; try { LoadStateMachine( m_InteractorType, us::GetModuleContext()->GetModule() ); SetEventConfig( "SegmentationToolsConfig.xml", us::GetModuleContext()->GetModule() ); } catch( const std::exception& e ) { MITK_ERROR << "Could not load statemachine pattern " << m_InteractorType << " with exception: " << e.what(); } } void mitk::Tool::Notify( InteractionEvent* interactionEvent, bool isHandled ) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if ( !isHandled ) { this->HandleEvent(interactionEvent, NULL); } } void mitk::Tool::ConnectActionsAndFunctions() { } bool mitk::Tool::FilterEvents(InteractionEvent* , DataNode* ) { return true; } const char* mitk::Tool::GetGroup() const { return "default"; } void mitk::Tool::SetToolManager(ToolManager* manager) { m_ToolManager = manager; } void mitk::Tool::Activated() { } void mitk::Tool::Deactivated() { // ToDo: reactivate this feature! //StateMachine::ResetStatemachineToStartState(); // forget about the past } itk::Object::Pointer mitk::Tool::GetGUI(const std::string& toolkitPrefix, const std::string& toolkitPostfix) { itk::Object::Pointer object; std::string classname = this->GetNameOfClass(); std::string guiClassname = toolkitPrefix + classname + toolkitPostfix; std::list allGUIs = itk::ObjectFactoryBase::CreateAllInstance(guiClassname.c_str()); for( std::list::iterator iter = allGUIs.begin(); iter != allGUIs.end(); ++iter ) { if (object.IsNull()) { object = dynamic_cast( iter->GetPointer() ); } else { MITK_ERROR << "There is more than one GUI for " << classname << " (several factories claim ability to produce a " << guiClassname << " ) " << std::endl; return NULL; // people should see and fix this error } } return object; } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetReferenceDataPreference() const { return m_PredicateReference.GetPointer(); } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetWorkingDataPreference() const { return m_IsSegmentationPredicate.GetPointer(); } + mitk::DataNode::Pointer mitk::Tool::CreateEmptySegmentationNode( Image* original, const std::string& organName, const mitk::Color& color ) { // we NEED a reference image for size etc. if (!original) return NULL; // actually create a new empty segmentation PixelType pixelType(mitk::MakeScalarPixelType() ); - Image::Pointer segmentation = Image::New(); + LabelSetImage::Pointer segmentation = LabelSetImage::New(); if (original->GetDimension() == 2) { const unsigned int dimensions[] = { original->GetDimension(0), original->GetDimension(1), 1 }; segmentation->Initialize(pixelType, 3, dimensions); + segmentation->AddLayer(); } else { - segmentation->Initialize(pixelType, original->GetDimension(), original->GetDimensions()); + segmentation->Initialize(original); } - unsigned int byteSize = sizeof(DefaultSegmentationDataType); + mitk::Label::Pointer label = mitk::Label::New(); + label->SetName(organName); + label->SetColor(color); + label->SetValue(1); + segmentation->GetActiveLabelSet()->AddLabel(label); + segmentation->GetActiveLabelSet()->SetActiveLabel(1); + + unsigned int byteSize = sizeof(mitk::Label::PixelType); if(segmentation->GetDimension() < 4) { for (unsigned int dim = 0; dim < segmentation->GetDimension(); ++dim) { byteSize *= segmentation->GetDimension(dim); } - mitk::ImageWriteAccessor writeAccess(segmentation, segmentation->GetVolumeData(0)); + mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(0)); memset( writeAccess.GetData(), 0, byteSize ); } else - {//if we have a time-resolved image we need to set memory to 0 for each time step + { + //if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= segmentation->GetDimension(dim); } for( unsigned int volumeNumber = 0; volumeNumber < segmentation->GetDimension(3); volumeNumber++) { - mitk::ImageWriteAccessor writeAccess(segmentation, segmentation->GetVolumeData(volumeNumber)); + mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(volumeNumber)); memset( writeAccess.GetData(), 0, byteSize ); } } if (original->GetTimeGeometry() ) { TimeGeometry::Pointer originalGeometry = original->GetTimeGeometry()->Clone(); segmentation->SetTimeGeometry( originalGeometry ); } else { Tool::ErrorMessage("Original image does not have a 'Time sliced geometry'! Cannot create a segmentation."); return NULL; } return CreateSegmentationNode( segmentation, organName, color ); } mitk::DataNode::Pointer mitk::Tool::CreateSegmentationNode( Image* image, const std::string& organName, const mitk::Color& color ) { if (!image) return NULL; // decorate the datatreenode with some properties DataNode::Pointer segmentationNode = DataNode::New(); segmentationNode->SetData( image ); // name segmentationNode->SetProperty( "name", StringProperty::New( organName ) ); // visualization properties segmentationNode->SetProperty( "binary", BoolProperty::New(true) ); - segmentationNode->SetProperty( "color", ColorProperty::New(color) ); +// segmentationNode->SetProperty( "color", ColorProperty::New(color) ); + mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); + lut->SetType(mitk::LookupTable::MULTILABEL); + mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New(); + lutProp->SetLookupTable(lut); + segmentationNode->SetProperty("LookupTable", lutProp); segmentationNode->SetProperty( "texture interpolation", BoolProperty::New(false) ); segmentationNode->SetProperty( "layer", IntProperty::New(10) ); segmentationNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(0.5, 1) ) ); segmentationNode->SetProperty( "opacity", FloatProperty::New(0.3) ); segmentationNode->SetProperty( "segmentation", BoolProperty::New(true) ); segmentationNode->SetProperty( "reslice interpolation", VtkResliceInterpolationProperty::New() ); // otherwise -> segmentation appears in 2 slices sometimes (only visual effect, not different data) // For MITK-3M3 release, the volume of all segmentations should be shown segmentationNode->SetProperty( "showVolume", BoolProperty::New( true ) ); return segmentationNode; } us::ModuleResource mitk::Tool::GetIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } us::ModuleResource mitk::Tool::GetCursorIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } diff --git a/Modules/Segmentation/Interactions/mitkTool.h b/Modules/Segmentation/Interactions/mitkTool.h index aa8d4c8c60..f323a264eb 100644 --- a/Modules/Segmentation/Interactions/mitkTool.h +++ b/Modules/Segmentation/Interactions/mitkTool.h @@ -1,254 +1,255 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkTool_h_Included #define mitkTool_h_Included #include "mitkCommon.h" #include #include "mitkStateMachine.h" #include "mitkToolEvents.h" #include "itkObjectFactoryBase.h" #include "itkVersion.h" #include "mitkToolFactoryMacro.h" #include "mitkMessage.h" #include "mitkDataNode.h" #include "mitkNodePredicateProperty.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateNot.h" #include #include #include #include "mitkInteractionEventObserver.h" #include "mitkEventStateMachine.h" +#include namespace us { class ModuleResource; } namespace mitk { class ToolManager; /** \brief Base class of all tools used by mitk::ToolManager. \sa ToolManager \sa SegTool2D \ingroup Interaction \ingroup ToolManagerEtAl There is a separate page describing the \ref QmitkInteractiveSegmentationTechnicalPage. Every tool is a mitk::StateMachine, which can follow any transition pattern that it likes. One important thing to know is, that every derived tool should always call SuperClass::Deactivated() in its own implementation of Deactivated, because mitk::Tool resets the StateMachine in this method. Only if you are very sure that you covered all possible things that might happen to your own tool, you should consider not to reset the StateMachine from time to time. To learn about the MITK implementation of state machines in general, have a look at \ref InteractionPage. To derive a non-abstract tool, you inherit from mitk::Tool (or some other base class further down the inheritance tree), and in your own parameterless constructor (that is called from the itkFactorylessNewMacro that you use) you pass a StateMachine pattern name to the superclass. Names for valid patterns can be found in StateMachine.xml (which might be enhanced by you). You have to implement at least GetXPM() and GetName() to provide some identification. Each Tool knows its ToolManager, which can provide the data that the tool should work on. \warning Only to be instantiated by mitk::ToolManager (because SetToolManager has to be called). All other uses are unsupported. $Author$ */ class MITKSEGMENTATION_EXPORT Tool : public EventStateMachine , public InteractionEventObserver { public: - typedef unsigned char DefaultSegmentationDataType; + typedef mitk::Label::PixelType DefaultSegmentationDataType; /** * \brief To let GUI process new events (e.g. qApp->processEvents() ) */ Message<> GUIProcessEventsMessage; /** * \brief To send error messages (to be shown by some GUI) */ Message1 ErrorMessage; /** * \brief To send whether the tool is busy (to be shown by some GUI) */ Message1 CurrentlyBusy; /** * \brief To send general messages (to be shown by some GUI) */ Message1 GeneralMessage; mitkClassMacro(Tool, EventStateMachine); // no New(), there should only be subclasses /** \brief Returns an icon in the XPM format. This icon has to fit into some kind of button in most applications, so make it smaller than 25x25 pixels. XPM is e.g. supported by The Gimp. But if you open any XPM file in your text editor, you will see that you could also "draw" it with an editor. */ virtual const char** GetXPM() const = 0; /** * \brief Returns the path of an icon. * * This icon is preferred to the XPM icon. */ virtual std::string GetIconPath() const { return ""; } /** * \brief Returns the path of a cursor icon. * */ virtual us::ModuleResource GetCursorIconResource() const; /** * @brief Returns the tool button icon of the tool wrapped by a usModuleResource * @return a valid ModuleResource or an invalid if this function * is not reimplemented */ virtual us::ModuleResource GetIconResource() const; /** \brief Returns the name of this tool. Make it short! This name has to fit into some kind of button in most applications, so take some time to think of a good name! */ virtual const char* GetName() const = 0; /** \brief Name of a group. You can group several tools by assigning a group name. Graphical tool selectors might use this information to group tools. (What other reason could there be?) */ virtual const char* GetGroup() const; virtual void InitializeStateMachine(); /** * \brief Interface for GUI creation. * * This is the basic interface for creation of a GUI object belonging to one tool. * * Tools that support a GUI (e.g. for display/editing of parameters) should follow some rules: * * - A Tool and its GUI are two separate classes * - There may be several instances of a GUI at the same time. * - mitk::Tool is toolkit (Qt, wxWidgets, etc.) independent, the GUI part is of course dependent * - The GUI part inherits both from itk::Object and some GUI toolkit class * - The GUI class name HAS to be constructed like "toolkitPrefix" tool->GetClassName() + "toolkitPostfix", e.g. MyTool -> wxMyToolGUI * - For each supported toolkit there is a base class for tool GUIs, which contains some convenience methods * - Tools notify the GUI about changes using ITK events. The GUI must observe interesting events. * - The GUI base class may convert all ITK events to the GUI toolkit's favoured messaging system (Qt -> signals) * - Calling methods of a tool by its GUI is done directly. * In some cases GUIs don't want to be notified by the tool when they cause a change in a tool. * There is a macro CALL_WITHOUT_NOTICE(method()), which will temporarily disable all notifications during a method call. */ virtual itk::Object::Pointer GetGUI(const std::string& toolkitPrefix, const std::string& toolkitPostfix); virtual NodePredicateBase::ConstPointer GetReferenceDataPreference() const; virtual NodePredicateBase::ConstPointer GetWorkingDataPreference() const; DataNode::Pointer CreateEmptySegmentationNode( Image* original, const std::string& organName, const mitk::Color& color ); DataNode::Pointer CreateSegmentationNode( Image* image, const std::string& organName, const mitk::Color& color ); virtual bool CanHandle(BaseData* referenceData) const; protected: friend class ToolManager; virtual void SetToolManager(ToolManager*); void ConnectActionsAndFunctions() override; /** \brief Called when the tool gets activated (registered to mitk::GlobalInteraction). Derived tools should call their parents implementation. */ virtual void Activated(); /** \brief Called when the tool gets deactivated (unregistered from mitk::GlobalInteraction). Derived tools should call their parents implementation. */ virtual void Deactivated(); Tool(); // purposely hidden Tool( const char*); // purposely hidden virtual ~Tool(); virtual void Notify( InteractionEvent* interactionEvent,bool isHandled ) override; bool FilterEvents(InteractionEvent* , DataNode* ) override; ToolManager* m_ToolManager; private: // for reference data NodePredicateDataType::Pointer m_PredicateImages; NodePredicateDimension::Pointer m_PredicateDim3; NodePredicateDimension::Pointer m_PredicateDim4; NodePredicateOr::Pointer m_PredicateDimension; NodePredicateAnd::Pointer m_PredicateImage3D; NodePredicateProperty::Pointer m_PredicateBinary; NodePredicateNot::Pointer m_PredicateNotBinary; NodePredicateProperty::Pointer m_PredicateSegmentation; NodePredicateNot::Pointer m_PredicateNotSegmentation; NodePredicateProperty::Pointer m_PredicateHelper; NodePredicateNot::Pointer m_PredicateNotHelper; NodePredicateAnd::Pointer m_PredicateImageColorful; NodePredicateAnd::Pointer m_PredicateImageColorfulNotHelper; NodePredicateAnd::Pointer m_PredicateReference; // for working data NodePredicateAnd::Pointer m_IsSegmentationPredicate; std::string m_InteractorType; }; } // namespace #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp index 8411094a17..60d9a12802 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkAdaptiveRegionGrowingToolGUI.cpp @@ -1,855 +1,855 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkAdaptiveRegionGrowingToolGUI.h" #include "QmitkStdMultiWidget.h" #include #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkITKImageImport.h" #include "mitkImageAccessByItk.h" #include "mitkTransferFunctionProperty.h" #include "mitkImageTimeSelector.h" #include "mitkImageStatisticsHolder.h" #include #include #include #include #include "itkOrImageFilter.h" #include "mitkImageCast.h" #include "QmitkConfirmSegmentationDialog.h" #include "mitkPixelTypeMultiplex.h" #include "mitkImagePixelReadAccessor.h" MITK_TOOL_GUI_MACRO( , QmitkAdaptiveRegionGrowingToolGUI, "") QmitkAdaptiveRegionGrowingToolGUI::QmitkAdaptiveRegionGrowingToolGUI(QWidget* parent) : QmitkToolGUI(), m_MultiWidget(NULL), m_UseVolumeRendering(false), m_UpdateSuggestedThreshold(true), m_SuggestedThValue(0.0), m_DataStorage(NULL) { this->setParent(parent); m_Controls.setupUi(this); m_Controls.m_ThresholdSlider->setDecimals(1); m_Controls.m_ThresholdSlider->setSpinBoxAlignment(Qt::AlignVCenter); m_Controls.m_PreviewSlider->setEnabled(false); m_Controls.m_PreviewSlider->setSingleStep(0.5); //Not yet available //m_Controls.m_PreviewSlider->InvertedAppearance(true); this->CreateConnections(); this->SetDataNodeNames("labeledRGSegmentation","RGResult","RGFeedbackSurface"); connect( this, SIGNAL(NewToolAssociated(mitk::Tool*)), this, SLOT(OnNewToolAssociated(mitk::Tool*)) ); } QmitkAdaptiveRegionGrowingToolGUI::~QmitkAdaptiveRegionGrowingToolGUI() { //Removing the observer of the PointSet node if (m_RegionGrow3DTool->GetPointSetNode().IsNotNull()) { m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetAddObserverTag); m_RegionGrow3DTool->GetPointSetNode()->GetData()->RemoveObserver(m_PointSetMoveObserverTag); } this->RemoveHelperNodes(); } void QmitkAdaptiveRegionGrowingToolGUI::OnNewToolAssociated(mitk::Tool* tool) { m_RegionGrow3DTool = dynamic_cast (tool); if(m_RegionGrow3DTool.IsNotNull()) { SetInputImageNode( this->m_RegionGrow3DTool->GetReferenceData() ); this->m_DataStorage = this->m_RegionGrow3DTool->GetDataStorage(); this->EnableControls(true); //Watch for point added or modified itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded); m_PointSetAddObserverTag = m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver( mitk::PointSetAddEvent(), pointAddedCommand); m_PointSetMoveObserverTag = m_RegionGrow3DTool->GetPointSetNode()->GetData()->AddObserver( mitk::PointSetMoveEvent(), pointAddedCommand); } else { this->EnableControls(false); } } void QmitkAdaptiveRegionGrowingToolGUI::RemoveHelperNodes() { mitk::DataNode::Pointer imageNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if( imageNode.IsNotNull() ) { m_DataStorage->Remove(imageNode); } } void QmitkAdaptiveRegionGrowingToolGUI::CreateConnections() { //Connecting GUI components connect( (QObject*) (m_Controls.m_pbRunSegmentation), SIGNAL(clicked()), this, SLOT(RunSegmentation())); connect( m_Controls.m_PreviewSlider, SIGNAL(valueChanged(double)), this, SLOT(ChangeLevelWindow(double))); connect( (QObject*) (m_Controls.m_pbConfirmSegementation), SIGNAL(clicked()), this, SLOT(ConfirmSegmentation())); connect( (QObject*) (m_Controls.m_cbVolumeRendering), SIGNAL(toggled(bool)), this, SLOT(UseVolumeRendering(bool) )); connect( m_Controls.m_ThresholdSlider, SIGNAL(maximumValueChanged(double)), this, SLOT(SetUpperThresholdValue(double))); connect( m_Controls.m_ThresholdSlider, SIGNAL(minimumValueChanged(double)), this, SLOT(SetLowerThresholdValue(double))); } void QmitkAdaptiveRegionGrowingToolGUI::SetDataNodeNames(std::string labledSegmentation, std::string binaryImage, std::string surface) { m_NAMEFORLABLEDSEGMENTATIONIMAGE = labledSegmentation; m_NAMEFORBINARYIMAGE = binaryImage; m_NAMEFORSURFACE = surface; } void QmitkAdaptiveRegionGrowingToolGUI::SetDataStorage(mitk::DataStorage* dataStorage) { m_DataStorage = dataStorage; } void QmitkAdaptiveRegionGrowingToolGUI::SetMultiWidget(QmitkStdMultiWidget* multiWidget) { m_MultiWidget = multiWidget; } void QmitkAdaptiveRegionGrowingToolGUI::SetInputImageNode(mitk::DataNode* node) { m_InputImageNode = node; mitk::Image* inputImage = dynamic_cast(m_InputImageNode->GetData()); if (inputImage) { mitk::ScalarType max = inputImage->GetStatistics()->GetScalarValueMax(); mitk::ScalarType min = inputImage->GetStatistics()->GetScalarValueMin(); m_Controls.m_ThresholdSlider->setMaximum(max); m_Controls.m_ThresholdSlider->setMinimum(min); // Just for initialization m_Controls.m_ThresholdSlider->setMaximumValue(max); m_Controls.m_ThresholdSlider->setMinimumValue(min); } } template static void AccessPixel(mitk::PixelType /*ptype*/, const mitk::Image::Pointer im, mitk::Point3D p, int & val) { mitk::ImagePixelReadAccessor access(im); val = access.GetPixelByWorldCoordinates(p); } void QmitkAdaptiveRegionGrowingToolGUI::OnPointAdded() { if (m_RegionGrow3DTool.IsNull()) return; mitk::DataNode* node = m_RegionGrow3DTool->GetPointSetNode(); if (node != NULL) { mitk::PointSet::Pointer pointSet = dynamic_cast(node->GetData()); if (pointSet.IsNull()) { QMessageBox::critical(NULL, "QmitkAdaptiveRegionGrowingToolGUI", "PointSetNode does not contain a pointset"); return; } m_Controls.m_lblSetSeedpoint->setText(""); mitk::Image* image = dynamic_cast(m_InputImageNode->GetData()); mitk::Point3D seedPoint = pointSet->GetPointSet(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1") )->GetTimeStep())->GetPoints()->ElementAt(0); if (image->GetGeometry()->IsInside(seedPoint)) mitkPixelTypeMultiplex3(AccessPixel,image->GetChannelDescriptor().GetPixelType(),image,seedPoint,m_SeedpointValue) else return; /* In this case the seedpoint is placed e.g. in the lung or bronchialtree * The lowerFactor sets the windowsize depending on the regiongrowing direction */ m_CurrentRGDirectionIsUpwards = true; if (m_SeedpointValue < -500) { m_CurrentRGDirectionIsUpwards = false; } // Initializing the region by the area around the seedpoint m_SeedPointValueMean = 0; itk::Index<3> currentIndex, runningIndex; mitk::ScalarType pixelValues[125]; unsigned int pos (0); image->GetGeometry(0)->WorldToIndex(seedPoint, currentIndex); runningIndex = currentIndex; for(int i = runningIndex[0]-2; i <= runningIndex[0]+2; i++) { for(int j = runningIndex[1]-2; j <= runningIndex[1]+2; j++) { for(int k = runningIndex[2]-2; k <= runningIndex[2]+2; k++) { currentIndex[0] = i; currentIndex[1] = j; currentIndex[2] = k; if(image->GetGeometry()->IsIndexInside(currentIndex)) { int component = 0; m_InputImageNode->GetIntProperty("Image.Displayed Component", component); pixelValues[pos] = image->GetPixelValueByIndex(currentIndex, 0, component); pos++; } else { pixelValues[pos] = -10000000; pos++; } } } } //Now calculation mean of the pixelValues unsigned int numberOfValues(0); for (auto & pixelValue : pixelValues) { if(pixelValue > -10000000) { m_SeedPointValueMean += pixelValue; numberOfValues++; } } m_SeedPointValueMean = m_SeedPointValueMean/numberOfValues; /* * Here the upper- and lower threshold is calculated: * The windowSize is 20% of the maximum range of the intensity values existing in the current image * If the RG direction is upwards the lower TH is meanSeedValue-0.15*windowSize and upper TH is meanSeedValue+0.85*windowsSize * if the RG direction is downwards the lower TH is meanSeedValue-0.85*windowSize and upper TH is meanSeedValue+0.15*windowsSize */ mitk::ScalarType min = image->GetStatistics()->GetScalarValueMin(); mitk::ScalarType max = image->GetStatistics()->GetScalarValueMax(); mitk::ScalarType windowSize = max - min; windowSize = 0.15*windowSize; if (m_CurrentRGDirectionIsUpwards) { m_LOWERTHRESHOLD = m_SeedPointValueMean; if (m_SeedpointValue < m_SeedPointValueMean) m_LOWERTHRESHOLD = m_SeedpointValue; m_UPPERTHRESHOLD = m_SeedpointValue + windowSize; if (m_UPPERTHRESHOLD > max) m_UPPERTHRESHOLD = max; m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD); m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD); } else { m_UPPERTHRESHOLD = m_SeedPointValueMean; if (m_SeedpointValue > m_SeedPointValueMean) m_UPPERTHRESHOLD = m_SeedpointValue; m_LOWERTHRESHOLD = m_SeedpointValue - windowSize; if (m_LOWERTHRESHOLD < min) m_LOWERTHRESHOLD = min; m_Controls.m_ThresholdSlider->setMinimumValue(m_LOWERTHRESHOLD); m_Controls.m_ThresholdSlider->setMaximumValue(m_UPPERTHRESHOLD); } } } void QmitkAdaptiveRegionGrowingToolGUI::RunSegmentation() { if (m_InputImageNode.IsNull()) { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Please specify the image in Datamanager!"); return; } mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode(); if (node.IsNull()) { QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Please insert a seed point inside the image.\n\nFirst press the \"Define Seed Point\" button,\nthen click left mouse button inside the image."); return; } //safety if no pointSet or pointSet empty mitk::PointSet::Pointer seedPointSet = dynamic_cast (node->GetData()); if (seedPointSet.IsNull()) { m_Controls.m_pbRunSegmentation->setEnabled(true); QMessageBox::information( NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } int timeStep = mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1") )->GetTimeStep(); if (!(seedPointSet->GetSize(timeStep))) { m_Controls.m_pbRunSegmentation->setEnabled(true); QMessageBox::information( NULL, "Adaptive Region Growing functionality", "The seed point is empty! Please choose a new seed point."); return; } QApplication::setOverrideCursor( QCursor(Qt::WaitCursor) ); mitk::PointSet::PointType seedPoint = seedPointSet->GetPointSet(timeStep)->GetPoints()->Begin().Value(); mitk::Image::Pointer orgImage = dynamic_cast (m_InputImageNode->GetData()); if (orgImage.IsNotNull()) { if (orgImage->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(orgImage); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); mitk::Image* timedImage = timeSelector->GetOutput(); AccessByItk_2( timedImage , StartRegionGrowing, timedImage->GetGeometry(), seedPoint); } else if (orgImage->GetDimension() == 3) { //QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); //set the cursor to waiting AccessByItk_2(orgImage, StartRegionGrowing, orgImage->GetGeometry(), seedPoint); //QApplication::restoreOverrideCursor();//reset cursor } else { QApplication::restoreOverrideCursor();//reset cursor QMessageBox::information( NULL, "Adaptive Region Growing functionality", "Only images of dimension 3 or 4 can be processed!"); return; } } EnableControls(true); // Segmentation ran successfully, so enable all controls. node->SetVisibility(true); QApplication::restoreOverrideCursor();//reset cursor } template void QmitkAdaptiveRegionGrowingToolGUI::StartRegionGrowing(itk::Image* itkImage, mitk::BaseGeometry* imageGeometry, mitk::PointSet::PointType seedPoint) { typedef itk::Image InputImageType; typedef typename InputImageType::IndexType IndexType; typedef itk::ConnectedAdaptiveThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); typedef itk::MinimumMaximumImageCalculator MinMaxValueFilterType; if ( !imageGeometry->IsInside(seedPoint) ) { QApplication::restoreOverrideCursor();//reset cursor to be able to click ok with the regular mouse cursor QMessageBox::information( NULL, "Segmentation functionality", "The seed point is outside of the image! Please choose a position inside the image!"); return; } IndexType seedIndex; imageGeometry->WorldToIndex( seedPoint, seedIndex);// convert world coordinates to image indices if (m_SeedpointValue>m_UPPERTHRESHOLD || m_SeedpointValueSetGrowingDirectionIsUpwards( m_CurrentRGDirectionIsUpwards ); regionGrower->SetInput( itkImage ); regionGrower->AddSeed( seedIndex ); //In some cases we have to subtract 1 for the lower threshold and add 1 to the upper. //Otherwise no region growing is done. Maybe a bug in the ConnectiveAdaptiveThresholdFilter regionGrower->SetLower( m_LOWERTHRESHOLD-1 ); regionGrower->SetUpper( m_UPPERTHRESHOLD+1); try { regionGrower->Update(); } catch(itk::ExceptionObject &exc) { QMessageBox errorInfo; errorInfo.setWindowTitle("Adaptive RG Segmentation Functionality"); errorInfo.setIcon(QMessageBox::Critical); errorInfo.setText("An error occurred during region growing!"); errorInfo.setDetailedText(exc.what()); errorInfo.exec(); return; // can't work } catch( ... ) { QMessageBox::critical( NULL, "Adaptive RG Segmentation Functionality", "An error occurred during region growing!"); return; } mitk::Image::Pointer resultImage = mitk::ImportItkImage(regionGrower->GetOutput())->Clone(); //initialize slider m_Controls.m_PreviewSlider->setMinimum(m_LOWERTHRESHOLD); mitk::ScalarType max = m_LOWERTHRESHOLD+resultImage->GetStatistics()->GetScalarValueMax(); if (max < m_UPPERTHRESHOLD) m_Controls.m_PreviewSlider->setMaximum(max); else m_Controls.m_PreviewSlider->setMaximum(m_UPPERTHRESHOLD); this->m_DetectedLeakagePoint = regionGrower->GetLeakagePoint(); if(m_CurrentRGDirectionIsUpwards) { m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean-1); } else { m_Controls.m_PreviewSlider->setValue(m_SeedPointValueMean+1); } this->m_SliderInitialized = true; //create new node and then delete the old one if there is one mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData( resultImage ); // set some properties newNode->SetProperty("name", mitk::StringProperty::New(m_NAMEFORLABLEDSEGMENTATIONIMAGE)); newNode->SetProperty("helper object", mitk::BoolProperty::New(true)); newNode->SetProperty("color", mitk::ColorProperty::New(0.0,1.0,0.0)); newNode->SetProperty("layer", mitk::IntProperty::New(1)); newNode->SetProperty("opacity", mitk::FloatProperty::New(0.7)); //delete the old image, if there was one: mitk::DataNode::Pointer binaryNode = m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE); m_DataStorage->Remove(binaryNode); // now add result to data tree m_DataStorage->Add( newNode, m_InputImageNode ); this->InitializeLevelWindow(); if(m_UseVolumeRendering) this->EnableVolumeRendering(true); m_UpdateSuggestedThreshold = true;// reset first stored threshold value //Setting progress to finished mitk::ProgressBar::GetInstance()->Progress(357); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAdaptiveRegionGrowingToolGUI::InitializeLevelWindow() { //get the preview from the datatree mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); mitk::ScalarType* level = new mitk::ScalarType(0.0); mitk::ScalarType* window = new mitk::ScalarType(1.0); int upper; if (m_CurrentRGDirectionIsUpwards) { upper = m_UPPERTHRESHOLD - m_SeedpointValue; } else { upper = m_SeedpointValue - m_LOWERTHRESHOLD; } tempLevelWindow.SetRangeMinMax(mitk::ScalarType(0), mitk::ScalarType(upper)); //get the suggested threshold from the detected leakage-point and adjust the slider if (m_CurrentRGDirectionIsUpwards) { this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue); *level = m_UPPERTHRESHOLD - (m_SeedpointValue) + 0.5; } else { this->m_Controls.m_PreviewSlider->setValue(m_SeedpointValue); *level = (m_SeedpointValue) - m_LOWERTHRESHOLD + 0.5; } tempLevelWindow.SetLevelWindow(*level, *window); newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow"); //update the widgets mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_SliderInitialized = true; //inquiry need to fix bug#1828 static int lastSliderPosition = 0; if ((this->m_SeedpointValue + this->m_DetectedLeakagePoint - 1) == lastSliderPosition) { this->ChangeLevelWindow(lastSliderPosition); } lastSliderPosition = this->m_SeedpointValue + this->m_DetectedLeakagePoint-1; if(m_MultiWidget) { this->m_MultiWidget->levelWindowWidget->GetManager()->SetAutoTopMostImage(false); this->m_MultiWidget->levelWindowWidget->GetManager()->SetLevelWindowProperty(static_cast(newNode->GetProperty("levelwindow"))); } if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int) (*level + 0.5));//lower threshold for labeled image } void QmitkAdaptiveRegionGrowingToolGUI::ChangeLevelWindow(double newValue) { if (m_SliderInitialized) { //do nothing, if no preview exists mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; mitk::LevelWindow tempLevelWindow; newNode->GetLevelWindow(tempLevelWindow, NULL, "levelwindow"); //get the levelWindow associated with the preview mitk::ScalarType level;// = this->m_UPPERTHRESHOLD - newValue + 0.5; mitk::ScalarType* window = new mitk::ScalarType(1); //adjust the levelwindow according to the position of the slider (newvalue) if (m_CurrentRGDirectionIsUpwards) { level = m_UPPERTHRESHOLD - newValue + 0.5; tempLevelWindow.SetLevelWindow(level, *window); } else { level = newValue - m_LOWERTHRESHOLD +0.5; tempLevelWindow.SetLevelWindow(level, *window); } newNode->SetLevelWindow(tempLevelWindow, NULL, "levelwindow"); if (m_UseVolumeRendering) this->UpdateVolumeRenderingThreshold((int) (level - 0.5));//lower threshold for labeled image newNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkAdaptiveRegionGrowingToolGUI::DecreaseSlider() { //moves the slider one step to the left, when the "-"-button is pressed if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->minimum()) { int newValue = this->m_Controls.m_PreviewSlider->value() - 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_PreviewSlider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingToolGUI::IncreaseSlider() { //moves the slider one step to the right, when the "+"-button is pressed if (this->m_Controls.m_PreviewSlider->value() != this->m_Controls.m_PreviewSlider->maximum()) { int newValue = this->m_Controls.m_PreviewSlider->value() + 1; this->ChangeLevelWindow(newValue); this->m_Controls.m_PreviewSlider->setValue(newValue); } } void QmitkAdaptiveRegionGrowingToolGUI::ConfirmSegmentation() { //get image node if(m_InputImageNode.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "Please specify the image in Datamanager!"); return; } //get image data mitk::Image::Pointer orgImage = dynamic_cast (m_InputImageNode->GetData()); if(orgImage.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "No Image found!"); return; } //get labeled segmentation mitk::Image::Pointer labeledSeg = (mitk::Image*)m_DataStorage->GetNamedObject(m_NAMEFORLABLEDSEGMENTATIONIMAGE); if(labeledSeg.IsNull()) { QMessageBox::critical( NULL, "Adaptive region growing functionality", "No Segmentation Preview found!"); return; } mitk::DataNode::Pointer newNode = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if (newNode.IsNull()) return; QmitkConfirmSegmentationDialog dialog; QString segName = QString::fromStdString(m_RegionGrow3DTool->GetCurrentSegmentationName()); dialog.SetSegmentationName(segName); int result = dialog.exec(); switch(result) { case QmitkConfirmSegmentationDialog::CREATE_NEW_SEGMENTATION: m_RegionGrow3DTool->SetOverwriteExistingSegmentation(false); break; case QmitkConfirmSegmentationDialog::OVERWRITE_SEGMENTATION: m_RegionGrow3DTool->SetOverwriteExistingSegmentation(true); break; case QmitkConfirmSegmentationDialog::CANCEL_SEGMENTATION: return; } mitk::Image* img = dynamic_cast(newNode->GetData()); AccessByItk(img, ITKThresholding); // disable volume rendering preview after the segmentation node was created this->EnableVolumeRendering(false); newNode->SetVisibility(false); m_Controls.m_cbVolumeRendering->setChecked(false); //TODO disable slider etc... } template void QmitkAdaptiveRegionGrowingToolGUI::ITKThresholding(itk::Image* itkImage) { mitk::Image::Pointer originalSegmentation = dynamic_cast(this->m_RegionGrow3DTool-> GetTargetSegmentationNode()->GetData()); int timeStep = mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1") )->GetTimeStep(); if (originalSegmentation) { typedef itk::Image InputImageType; - typedef itk::Image SegmentationType; + typedef itk::Image SegmentationType; //select single 3D volume if we have more than one time step typename SegmentationType::Pointer originalSegmentationInITK = SegmentationType::New(); if(originalSegmentation->GetTimeGeometry()->CountTimeSteps() > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput( originalSegmentation ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); CastToItkImage( timeSelector->GetOutput(), originalSegmentationInITK ); } else //use original { CastToItkImage( originalSegmentation, originalSegmentationInITK ); } //Fill current preiview image in segmentation image originalSegmentationInITK->FillBuffer(0); itk::ImageRegionIterator itOutput( originalSegmentationInITK, originalSegmentationInITK->GetLargestPossibleRegion() ); itk::ImageRegionIterator itInput( itkImage, itkImage->GetLargestPossibleRegion() ); itOutput.GoToBegin(); itInput.GoToBegin(); //calculate threhold from slider value int currentTreshold = 0; if (m_CurrentRGDirectionIsUpwards) { currentTreshold = m_UPPERTHRESHOLD - m_Controls.m_PreviewSlider->value() + 1; } else { currentTreshold = m_Controls.m_PreviewSlider->value() - m_LOWERTHRESHOLD; } //iterate over image and set pixel in segmentation according to thresholded labeled image while( !itOutput.IsAtEnd() && !itInput.IsAtEnd() ) { //Use threshold slider to determine if pixel is set to 1 if( itInput.Value() != 0 && itInput.Value() >= currentTreshold ) { itOutput.Set( 1 ); } ++itOutput; ++itInput; } //combine current working segmentation image with our region growing result originalSegmentation->SetVolume( (void*)(originalSegmentationInITK->GetPixelContainer()->GetBufferPointer()), timeStep); originalSegmentation->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkAdaptiveRegionGrowingToolGUI::EnableControls(bool enable) { if (m_RegionGrow3DTool.IsNull()) return; // Check if seed point is already set, if not leave RunSegmentation disabled //if even m_DataStorage is NULL leave node NULL mitk::DataNode::Pointer node = m_RegionGrow3DTool->GetPointSetNode(); if (node.IsNull()) { this->m_Controls.m_pbRunSegmentation->setEnabled(false); } else { this->m_Controls.m_pbRunSegmentation->setEnabled(enable); } // Check if a segmentation exists, if not leave segmentation dependent disabled. //if even m_DataStorage is NULL leave node NULL node = m_DataStorage?m_DataStorage->GetNamedNode(m_NAMEFORLABLEDSEGMENTATIONIMAGE):NULL; if (node.IsNull()) { this->m_Controls.m_PreviewSlider->setEnabled(false); this->m_Controls.m_pbConfirmSegementation->setEnabled(false); } else { this->m_Controls.m_PreviewSlider->setEnabled(enable); this->m_Controls.m_pbConfirmSegementation->setEnabled(enable); } this->m_Controls.m_cbVolumeRendering->setEnabled(enable); } void QmitkAdaptiveRegionGrowingToolGUI::EnableVolumeRendering(bool enable) { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if(node.IsNull()) return; if(m_MultiWidget) m_MultiWidget->SetWidgetPlanesVisibility(!enable); if (enable) { node->SetBoolProperty("volumerendering", enable); node->SetBoolProperty("volumerendering.uselod", true); } else { node->SetBoolProperty("volumerendering", enable); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkAdaptiveRegionGrowingToolGUI::UpdateVolumeRenderingThreshold(int thValue) { mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); mitk::TransferFunction::Pointer tf = mitk::TransferFunction::New(); if (m_UpdateSuggestedThreshold) { m_SuggestedThValue = thValue; m_UpdateSuggestedThreshold = false; } // grayvalue->opacity { vtkPiecewiseFunction *f = tf->GetScalarOpacityFunction(); f->RemoveAllPoints(); f->AddPoint(0, 0); f->AddPoint(thValue+0.5, 0); f->AddPoint(thValue+1.5, 1); f->AddPoint(1000, 1); f->ClampingOn(); f->Modified(); } // grayvalue->color { float a = 255.0; vtkColorTransferFunction *ctf = tf->GetColorTransferFunction(); ctf->RemoveAllPoints(); //ctf->AddRGBPoint(-1000, 0.0, 0.0, 0.0); ctf->AddRGBPoint(m_SuggestedThValue+1, 203/a, 104/a, 102/a); ctf->AddRGBPoint(m_SuggestedThValue, 255/a, 0/a, 0/a); ctf->ClampingOn(); ctf->Modified(); } // GradientOpacityFunction { vtkPiecewiseFunction *gof = tf->GetGradientOpacityFunction(); gof->RemoveAllPoints(); gof->AddPoint(-10000, 1); gof->AddPoint(10000, 1); gof->ClampingOn(); gof->Modified(); } mitk::TransferFunctionProperty::Pointer tfp = mitk::TransferFunctionProperty::New(); tfp->SetValue(tf); node->SetProperty("TransferFunction", tfp); } void QmitkAdaptiveRegionGrowingToolGUI::UseVolumeRendering(bool on) { m_UseVolumeRendering = on; this->EnableVolumeRendering(on); } void QmitkAdaptiveRegionGrowingToolGUI::SetLowerThresholdValue( double lowerThreshold ) { m_LOWERTHRESHOLD = lowerThreshold; } void QmitkAdaptiveRegionGrowingToolGUI::SetUpperThresholdValue( double upperThreshold) { m_UPPERTHRESHOLD = upperThreshold; } void QmitkAdaptiveRegionGrowingToolGUI::Deactivated() { // make the segmentation preview node invisible mitk::DataNode::Pointer node = m_DataStorage->GetNamedNode( m_NAMEFORLABLEDSEGMENTATIONIMAGE); if( node.IsNotNull() ) { node->SetVisibility(false); } // disable volume rendering preview after the segmentation node was created this->EnableVolumeRendering(false); m_Controls.m_cbVolumeRendering->setChecked(false); } void QmitkAdaptiveRegionGrowingToolGUI::Activated() { } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp index a6d4af341e..8b75ca8758 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.cpp @@ -1,158 +1,161 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkSurfaceToImageWidget.h" #include #include #include #include #include #include #include +#include #include static const char* const HelpText = "Select an image and a surface above"; QmitkSurfaceToImageWidget::QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) : QmitkSegmentationUtilityWidget(timeNavigationController, parent) { m_Controls.setupUi(this); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); m_Controls.dataSelectionWidget->AddDataStorageComboBox(QmitkDataSelectionWidget::SurfacePredicate); m_Controls.dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); connect (m_Controls.btnSurface2Image, SIGNAL(pressed()), this, SLOT(OnSurface2ImagePressed())); connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) { this->OnSelectionChanged( 0, m_Controls.dataSelectionWidget->GetSelection(0)); } } QmitkSurfaceToImageWidget::~QmitkSurfaceToImageWidget() { } void QmitkSurfaceToImageWidget::EnableButtons(bool enable) { m_Controls.btnSurface2Image->setEnabled(enable); } -void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) +void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int /*index*/, const mitk::DataNode* /*selection*/) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer surfaceNode = dataSelectionWidget->GetSelection(1); if (imageNode.IsNull() || surfaceNode.IsNull() ) { dataSelectionWidget->SetHelpText(HelpText); this->EnableButtons(false); } else { mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); if( image->GetTimeSteps() != surface->GetTimeSteps() ) { dataSelectionWidget->SetHelpText("Image and surface are of different size"); this->EnableButtons(false); } else { dataSelectionWidget->SetHelpText(""); this->EnableButtons(); } } } void QmitkSurfaceToImageWidget::OnSurface2ImagePressed() { this->EnableButtons(false); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); if( image.IsNull() || surface.IsNull()) { MITK_ERROR << "Selection does not contain an image and/or a surface"; QMessageBox::information( this, "Surface To Image", "Selection does not contain an image and/or a surface", QMessageBox::Ok ); this->EnableButtons(); return; } mitk::Image::Pointer resultImage(nullptr); resultImage = this->ConvertSurfaceToImage( image, surface ); if( resultImage.IsNull() ) { MITK_ERROR << "Convert Surface to binary image failed"; QMessageBox::information( this, "Surface To Image", "Convert Surface to binary image failed", QMessageBox::Ok ); this->EnableButtons(); return; } //create name for result node std::string nameOfResultImage = dataSelectionWidget->GetSelection(0)->GetName(); nameOfResultImage.append("_"); nameOfResultImage.append(dataSelectionWidget->GetSelection(1)->GetName()); //create data node and add to data storage mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); resultNode->SetData( resultImage ); resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); - resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); +// resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); dataSelectionWidget->GetDataStorage()->Add(resultNode, dataSelectionWidget->GetSelection(0)); this->EnableButtons(); } -mitk::Image::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) +mitk::LabelSetImage::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) { mitk::ProgressBar::GetInstance()->AddStepsToDo(2); mitk::ProgressBar::GetInstance()->Progress(); mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(surface); surfaceToImageFilter->SetImage(image); try { surfaceToImageFilter->Update(); } catch(itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return nullptr; } mitk::ProgressBar::GetInstance()->Progress(); mitk::Image::Pointer resultImage = surfaceToImageFilter->GetOutput(); + mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); + multilabelImage->InitializeByLabeledImage(resultImage); - return resultImage; + return multilabelImage; } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h index f68206cb8d..71cae691aa 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/SurfaceToImage/QmitkSurfaceToImageWidget.h @@ -1,67 +1,68 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkSurfaceToImageWidget_h #define QmitkSurfaceToImageWidget_h #include "../QmitkSegmentationUtilityWidget.h" #include namespace mitk { class Surface; class Image; + class LabelSetImage; } /*! \brief QmitkSurfaceToImageWidget The Tool converts a surface to a binary image. The Method requires a surface and an image, which header information defines the output image. The resulting binary image has the same dimension, size, and Geometry3D as the input image. */ class QmitkSurfaceToImageWidget : public QmitkSegmentationUtilityWidget { Q_OBJECT public: /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ explicit QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); /** @brief Defaul destructor. */ ~QmitkSurfaceToImageWidget(); private slots: /** @brief This slot is called if the selection in the workbench is changed. */ void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); /** @brief This slot is called if user activates the button to convert a surface into a binary image. */ void OnSurface2ImagePressed(); private: /** @brief Enable buttons if data selction is valid. */ void EnableButtons(bool enable = true); /** @brief Convert a surface into an binary image. */ - itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, itk::SmartPointer surface ); + itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, itk::SmartPointer surface ); Ui::QmitkSurfaceToImageWidgetControls m_Controls; }; #endif