diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp index 4e5191b32f..3e55bffb9d 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.cpp @@ -1,460 +1,336 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkFastMarchingTool3D.h" #include "mitkToolManager.h" #include "mitkBaseRenderer.h" #include "mitkInteractionConst.h" #include "mitkRenderingManager.h" -#include "itkOrImageFilter.h" -#include "mitkImageCast.h" -#include "mitkImageTimeSelector.h" +#include "mitkImageAccessByItk.h" + +// itk filter +#include "itkBinaryThresholdImageFilter.h" +#include "itkCurvatureAnisotropicDiffusionImageFilter.h" +#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" +#include "itkSigmoidImageFilter.h" // us #include #include #include #include namespace mitk { MITK_TOOL_MACRO(MITKSEGMENTATION_EXPORT, FastMarchingTool3D, "FastMarching3D tool"); } mitk::FastMarchingTool3D::FastMarchingTool3D() - : /*FeedbackContourTool*/ AutoSegmentationTool(), - m_NeedUpdate(true), - m_CurrentTimeStep(0), + : AutoSegmentationWithPreviewTool(), m_LowerThreshold(0), m_UpperThreshold(200), m_StoppingValue(100), m_Sigma(1.0), m_Alpha(-0.5), m_Beta(3.0), m_PointSetAddObserverTag(0), m_PointSetRemoveObserverTag(0) { } mitk::FastMarchingTool3D::~FastMarchingTool3D() { } -bool mitk::FastMarchingTool3D::CanHandle(BaseData *referenceData) const +bool mitk::FastMarchingTool3D::CanHandle(const BaseData* referenceData, const BaseData* workingData) const { + if(!Superclass::CanHandle(referenceData, workingData)) + return false; + if (referenceData == nullptr) return false; - auto *image = dynamic_cast(referenceData); + auto *image = dynamic_cast(referenceData); if (image == nullptr) return false; if (image->GetDimension() < 3) return false; return true; } const char **mitk::FastMarchingTool3D::GetXPM() const { return nullptr; // mitkFastMarchingTool3D_xpm; } us::ModuleResource mitk::FastMarchingTool3D::GetIconResource() const { us::Module *module = us::GetModuleContext()->GetModule(); us::ModuleResource resource = module->GetResource("FastMarching_48x48.png"); return resource; } const char *mitk::FastMarchingTool3D::GetName() const { return "Fast Marching 3D"; } void mitk::FastMarchingTool3D::SetUpperThreshold(double value) { m_UpperThreshold = value / 10.0; - m_ThresholdFilter->SetUpperThreshold(m_UpperThreshold); - m_NeedUpdate = true; } void mitk::FastMarchingTool3D::SetLowerThreshold(double value) { m_LowerThreshold = value / 10.0; - m_ThresholdFilter->SetLowerThreshold(m_LowerThreshold); - m_NeedUpdate = true; } void mitk::FastMarchingTool3D::SetBeta(double value) { if (m_Beta != value) { m_Beta = value; - m_SigmoidFilter->SetBeta(m_Beta); - m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::SetSigma(double value) { if (m_Sigma != value) { if (value > 0.0) { m_Sigma = value; - m_GradientMagnitudeFilter->SetSigma(m_Sigma); - m_NeedUpdate = true; } } } void mitk::FastMarchingTool3D::SetAlpha(double value) { if (m_Alpha != value) { m_Alpha = value; - m_SigmoidFilter->SetAlpha(m_Alpha); - m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::SetStoppingValue(double value) { if (m_StoppingValue != value) { m_StoppingValue = value; - m_FastMarchingFilter->SetStoppingValue(m_StoppingValue); - m_NeedUpdate = true; } } void mitk::FastMarchingTool3D::Activated() { Superclass::Activated(); - m_ResultImageNode = mitk::DataNode::New(); - m_ResultImageNode->SetName("FastMarching_Preview"); - m_ResultImageNode->SetBoolProperty("helper object", true); - m_ResultImageNode->SetColor(0.0, 1.0, 0.0); - m_ResultImageNode->SetVisibility(true); - m_ToolManager->GetDataStorage()->Add(this->m_ResultImageNode, m_ToolManager->GetReferenceData(0)); - m_SeedsAsPointSet = mitk::PointSet::New(); m_SeedsAsPointSetNode = mitk::DataNode::New(); m_SeedsAsPointSetNode->SetData(m_SeedsAsPointSet); m_SeedsAsPointSetNode->SetName("3D_FastMarching_PointSet"); m_SeedsAsPointSetNode->SetBoolProperty("helper object", true); m_SeedsAsPointSetNode->SetColor(0.0, 1.0, 0.0); m_SeedsAsPointSetNode->SetVisibility(true); // Create PointSetData Interactor m_SeedPointInteractor = mitk::PointSetDataInteractor::New(); // Load the according state machine for regular point set interaction m_SeedPointInteractor->LoadStateMachine("PointSet.xml"); // Set the configuration file that defines the triggers for the transitions m_SeedPointInteractor->SetEventConfig("PointSetConfig.xml"); // set the DataNode (which already is added to the DataStorage m_SeedPointInteractor->SetDataNode(m_SeedsAsPointSetNode); - m_ReferenceImageAsITK = InternalImageType::New(); - - m_ProgressCommand = mitk::ToolCommand::New(); - - m_ThresholdFilter = ThresholdingFilterType::New(); - m_ThresholdFilter->SetLowerThreshold(m_LowerThreshold); - m_ThresholdFilter->SetUpperThreshold(m_UpperThreshold); - m_ThresholdFilter->SetOutsideValue(0); - m_ThresholdFilter->SetInsideValue(1.0); - - m_SmoothFilter = SmoothingFilterType::New(); - m_SmoothFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); - m_SmoothFilter->SetTimeStep(0.05); - m_SmoothFilter->SetNumberOfIterations(2); - m_SmoothFilter->SetConductanceParameter(9.0); - - m_GradientMagnitudeFilter = GradientFilterType::New(); - m_GradientMagnitudeFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); - m_GradientMagnitudeFilter->SetSigma(m_Sigma); - - m_SigmoidFilter = SigmoidFilterType::New(); - m_SigmoidFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); - m_SigmoidFilter->SetAlpha(m_Alpha); - m_SigmoidFilter->SetBeta(m_Beta); - m_SigmoidFilter->SetOutputMinimum(0.0); - m_SigmoidFilter->SetOutputMaximum(1.0); - - m_FastMarchingFilter = FastMarchingFilterType::New(); - m_FastMarchingFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); - m_FastMarchingFilter->SetStoppingValue(m_StoppingValue); + m_ToolManager->GetDataStorage()->Add(m_SeedsAsPointSetNode, m_ToolManager->GetWorkingData(0)); m_SeedContainer = NodeContainer::New(); m_SeedContainer->Initialize(); - m_FastMarchingFilter->SetTrialPoints(m_SeedContainer); - - // set up pipeline - m_SmoothFilter->SetInput(m_ReferenceImageAsITK); - m_GradientMagnitudeFilter->SetInput(m_SmoothFilter->GetOutput()); - m_SigmoidFilter->SetInput(m_GradientMagnitudeFilter->GetOutput()); - m_FastMarchingFilter->SetInput(m_SigmoidFilter->GetOutput()); - m_ThresholdFilter->SetInput(m_FastMarchingFilter->GetOutput()); - - m_ToolManager->GetDataStorage()->Add(m_SeedsAsPointSetNode, m_ToolManager->GetWorkingData(0)); itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnAddPoint); m_PointSetAddObserverTag = m_SeedsAsPointSet->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand); itk::SimpleMemberCommand::Pointer pointRemovedCommand = itk::SimpleMemberCommand::New(); pointRemovedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnDelete); m_PointSetRemoveObserverTag = m_SeedsAsPointSet->AddObserver(mitk::PointSetRemoveEvent(), pointRemovedCommand); - - this->Initialize(); } void mitk::FastMarchingTool3D::Deactivated() { - m_ToolManager->GetDataStorage()->Remove(this->m_ResultImageNode); - m_ToolManager->GetDataStorage()->Remove(this->m_SeedsAsPointSetNode); this->ClearSeeds(); - this->m_SmoothFilter->RemoveAllObservers(); - this->m_SigmoidFilter->RemoveAllObservers(); - this->m_GradientMagnitudeFilter->RemoveAllObservers(); - this->m_FastMarchingFilter->RemoveAllObservers(); - m_ResultImageNode = nullptr; - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - unsigned int numberOfPoints = m_SeedsAsPointSet->GetSize(); - for (unsigned int i = 0; i < numberOfPoints; ++i) - { - mitk::Point3D point = m_SeedsAsPointSet->GetPoint(i); - auto *doOp = new mitk::PointOperation(mitk::OpREMOVE, point, 0); - m_SeedsAsPointSet->ExecuteOperation(doOp); - } // Deactivate Interaction m_SeedPointInteractor->SetDataNode(nullptr); - m_ToolManager->GetDataStorage()->Remove(m_SeedsAsPointSetNode); + m_ToolManager->GetDataStorage()->Remove(this->m_SeedsAsPointSetNode); m_SeedsAsPointSetNode = nullptr; m_SeedsAsPointSet->RemoveObserver(m_PointSetAddObserverTag); m_SeedsAsPointSet->RemoveObserver(m_PointSetRemoveObserverTag); + m_SeedsAsPointSet = nullptr; Superclass::Deactivated(); } -void mitk::FastMarchingTool3D::Initialize() -{ - m_ReferenceImage = dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData()); - if (m_ReferenceImage->GetTimeGeometry()->CountTimeSteps() > 1) - { - mitk::ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); - timeSelector->SetInput(m_ReferenceImage); - timeSelector->SetTimeNr(m_CurrentTimeStep); - timeSelector->UpdateLargestPossibleRegion(); - m_ReferenceImage = timeSelector->GetOutput(); - } - CastToItkImage(m_ReferenceImage, m_ReferenceImageAsITK); - m_SmoothFilter->SetInput(m_ReferenceImageAsITK); - m_NeedUpdate = true; -} - -void mitk::FastMarchingTool3D::ConfirmSegmentation() -{ - // combine preview image with current working segmentation - if (dynamic_cast(m_ResultImageNode->GetData())) - { - // logical or combination of preview and segmentation slice - OutputImageType::Pointer segmentationImageInITK = OutputImageType::New(); - - mitk::Image::Pointer workingImage = dynamic_cast(GetTargetSegmentationNode()->GetData()); - if (workingImage->GetTimeGeometry()->CountTimeSteps() > 1) - { - mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); - timeSelector->SetInput(workingImage); - timeSelector->SetTimeNr(m_CurrentTimeStep); - timeSelector->UpdateLargestPossibleRegion(); - CastToItkImage(timeSelector->GetOutput(), segmentationImageInITK); - } - else - { - CastToItkImage(workingImage, segmentationImageInITK); - } - - typedef itk::OrImageFilter OrImageFilterType; - OrImageFilterType::Pointer orFilter = OrImageFilterType::New(); - - orFilter->SetInput(0, m_ThresholdFilter->GetOutput()); - orFilter->SetInput(1, segmentationImageInITK); - orFilter->Update(); - - // set image volume in current time step from itk image - workingImage->SetVolume((void *)(m_ThresholdFilter->GetOutput()->GetPixelContainer()->GetBufferPointer()), - m_CurrentTimeStep); - this->m_ResultImageNode->SetVisibility(false); - this->ClearSeeds(); - workingImage->Modified(); - } - - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - m_ToolManager->ActivateTool(-1); -} - void mitk::FastMarchingTool3D::OnAddPoint() { // Add a new seed point for FastMarching algorithm mitk::Point3D clickInIndex; - m_ReferenceImage->GetGeometry()->WorldToIndex(m_SeedsAsPointSet->GetPoint(m_SeedsAsPointSet->GetSize() - 1), + this->GetReferenceData()->GetGeometry()->WorldToIndex(m_SeedsAsPointSet->GetPoint(m_SeedsAsPointSet->GetSize() - 1), clickInIndex); itk::Index<3> seedPosition; seedPosition[0] = clickInIndex[0]; seedPosition[1] = clickInIndex[1]; seedPosition[2] = clickInIndex[2]; NodeType node; const double seedValue = 0.0; node.SetValue(seedValue); node.SetIndex(seedPosition); this->m_SeedContainer->InsertElement(this->m_SeedContainer->Size(), node); - m_FastMarchingFilter->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - m_NeedUpdate = true; - - this->Update(); - - m_ReadyMessage.Send(); + this->UpdatePreview(); } void mitk::FastMarchingTool3D::OnDelete() { // delete last seed point if (!(this->m_SeedContainer->empty())) { // delete last element of seeds container this->m_SeedContainer->pop_back(); - m_FastMarchingFilter->Modified(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - m_NeedUpdate = true; - - this->Update(); - } -} - -void mitk::FastMarchingTool3D::Update() -{ - const unsigned int progress_steps = 200; - - if (m_NeedUpdate) - { - m_ProgressCommand->AddStepsToDo(progress_steps); - - // remove interaction with poinset while updating - m_SeedPointInteractor->SetDataNode(nullptr); - CurrentlyBusy.Send(true); - try - { - m_ThresholdFilter->Update(); - } - catch (itk::ExceptionObject &excep) - { - MITK_ERROR << "Exception caught: " << excep.GetDescription(); - - m_ProgressCommand->SetProgress(progress_steps); - CurrentlyBusy.Send(false); - - std::string msg = excep.GetDescription(); - ErrorMessage.Send(msg); - - return; - } - m_ProgressCommand->SetProgress(progress_steps); - CurrentlyBusy.Send(false); - - // make output visible - mitk::Image::Pointer result = mitk::Image::New(); - CastToMitkImage(m_ThresholdFilter->GetOutput(), result); - result->GetGeometry()->SetOrigin(m_ReferenceImage->GetGeometry()->GetOrigin()); - result->GetGeometry()->SetIndexToWorldTransform(m_ReferenceImage->GetGeometry()->GetIndexToWorldTransform()); - m_ResultImageNode->SetData(result); - m_ResultImageNode->SetVisibility(true); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - - // add interaction with poinset again - m_SeedPointInteractor->SetDataNode(m_SeedsAsPointSetNode); + this->UpdatePreview(); } } void mitk::FastMarchingTool3D::ClearSeeds() { // clear seeds for FastMarching as well as the PointSet for visualization if (this->m_SeedContainer.IsNotNull()) this->m_SeedContainer->Initialize(); if (this->m_SeedsAsPointSet.IsNotNull()) { // remove observers from current pointset m_SeedsAsPointSet->RemoveObserver(m_PointSetAddObserverTag); m_SeedsAsPointSet->RemoveObserver(m_PointSetRemoveObserverTag); // renew pointset this->m_SeedsAsPointSet = mitk::PointSet::New(); this->m_SeedsAsPointSetNode->SetData(this->m_SeedsAsPointSet); m_SeedsAsPointSetNode->SetName("Seeds_Preview"); m_SeedsAsPointSetNode->SetBoolProperty("helper object", true); m_SeedsAsPointSetNode->SetColor(0.0, 1.0, 0.0); m_SeedsAsPointSetNode->SetVisibility(true); // add callback function for adding and removing points itk::SimpleMemberCommand::Pointer pointAddedCommand = itk::SimpleMemberCommand::New(); pointAddedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnAddPoint); m_PointSetAddObserverTag = m_SeedsAsPointSet->AddObserver(mitk::PointSetAddEvent(), pointAddedCommand); itk::SimpleMemberCommand::Pointer pointRemovedCommand = itk::SimpleMemberCommand::New(); pointRemovedCommand->SetCallbackFunction(this, &mitk::FastMarchingTool3D::OnDelete); m_PointSetRemoveObserverTag = m_SeedsAsPointSet->AddObserver(mitk::PointSetRemoveEvent(), pointRemovedCommand); } +} - if (this->m_FastMarchingFilter.IsNotNull()) - m_FastMarchingFilter->Modified(); +template +void mitk::FastMarchingTool3D::DoITKFastMarching(const itk::Image* inputImage, + mitk::Image* segmentation, unsigned int timeStep) +{ + typedef itk::Image InputImageType; + + /* typedefs for itk pipeline */ + + typedef mitk::Tool::DefaultSegmentationDataType OutputPixelType; + typedef itk::Image OutputImageType; + + typedef itk::CurvatureAnisotropicDiffusionImageFilter SmoothingFilterType; + typedef itk::GradientMagnitudeRecursiveGaussianImageFilter GradientFilterType; + typedef itk::SigmoidImageFilter SigmoidFilterType; + typedef itk::BinaryThresholdImageFilter ThresholdingFilterType; + + auto smoothFilter = SmoothingFilterType::New(); + smoothFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); + smoothFilter->SetTimeStep(0.05); + smoothFilter->SetNumberOfIterations(2); + smoothFilter->SetConductanceParameter(9.0); + + auto gradientMagnitudeFilter = GradientFilterType::New(); + gradientMagnitudeFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); + gradientMagnitudeFilter->SetSigma(m_Sigma); + + auto sigmoidFilter = SigmoidFilterType::New(); + sigmoidFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); + sigmoidFilter->SetAlpha(m_Alpha); + sigmoidFilter->SetBeta(m_Beta); + sigmoidFilter->SetOutputMinimum(0.0); + sigmoidFilter->SetOutputMaximum(1.0); + + auto fastMarchingFilter = FastMarchingFilterType::New(); + fastMarchingFilter->AddObserver(itk::ProgressEvent(), m_ProgressCommand); + fastMarchingFilter->SetStoppingValue(m_StoppingValue); + fastMarchingFilter->SetTrialPoints(m_SeedContainer); + + auto thresholdFilter = ThresholdingFilterType::New(); + thresholdFilter->SetLowerThreshold(m_LowerThreshold); + thresholdFilter->SetUpperThreshold(m_UpperThreshold); + thresholdFilter->SetOutsideValue(0); + thresholdFilter->SetInsideValue(1.0); - this->m_NeedUpdate = true; + // set up pipeline + smoothFilter->SetInput(inputImage); + gradientMagnitudeFilter->SetInput(smoothFilter->GetOutput()); + sigmoidFilter->SetInput(gradientMagnitudeFilter->GetOutput()); + fastMarchingFilter->SetInput(sigmoidFilter->GetOutput()); + thresholdFilter->SetInput(fastMarchingFilter->GetOutput()); + thresholdFilter->Update(); + + segmentation->SetVolume((void*)(thresholdFilter->GetOutput()->GetPixelContainer()->GetBufferPointer()), timeStep); } -void mitk::FastMarchingTool3D::Reset() +void mitk::FastMarchingTool3D::UpdatePrepare() { - // clear all seeds and preview empty result - this->ClearSeeds(); - - m_ResultImageNode->SetVisibility(false); + // remove interaction with poinset while updating + if (m_SeedPointInteractor.IsNotNull()) + m_SeedPointInteractor->SetDataNode(nullptr); +} - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +void mitk::FastMarchingTool3D::UpdateCleanUp() +{ + // add interaction with poinset again + if (m_SeedPointInteractor.IsNotNull()) + m_SeedPointInteractor->SetDataNode(m_SeedsAsPointSetNode); } -void mitk::FastMarchingTool3D::SetCurrentTimeStep(int t) +void mitk::FastMarchingTool3D::DoUpdatePreview(const Image* inputAtTimeStep, Image* previewImage, TimeStepType timeStep) { - if (m_CurrentTimeStep != t) - { - m_CurrentTimeStep = t; + bool isOldBinary = nullptr == dynamic_cast(previewImage); - this->Initialize(); + if (nullptr != inputAtTimeStep && nullptr != previewImage && m_SeedContainer.IsNotNull() && !m_SeedContainer->empty()) + { + AccessFixedDimensionByItk_n(inputAtTimeStep, DoITKFastMarching, 3, (previewImage, timeStep)); } } diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h index eeefc20b4f..652e0d550b 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool3D.h @@ -1,164 +1,124 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkFastMarchingTool3D_h_Included #define mitkFastMarchingTool3D_h_Included -#include "mitkAutoSegmentationTool.h" +#include "mitkAutoSegmentationWithPreviewTool.h" #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkPointSetDataInteractor.h" #include "mitkToolCommand.h" -#include - -#include "mitkMessage.h" #include "itkImage.h" - -// itk filter -#include "itkBinaryThresholdImageFilter.h" -#include "itkCurvatureAnisotropicDiffusionImageFilter.h" #include "itkFastMarchingImageFilter.h" -#include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" -#include "itkSigmoidImageFilter.h" + +#include 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 + class MITKSEGMENTATION_EXPORT FastMarchingTool3D : public AutoSegmentationWithPreviewTool { - mitkNewMessageMacro(Ready); - public: - mitkClassMacro(FastMarchingTool3D, AutoSegmentationTool); + mitkClassMacro(FastMarchingTool3D, AutoSegmentationWithPreviewTool); itkFactorylessNewMacro(Self); itkCloneMacro(Self); - /* typedefs for itk pipeline */ - typedef float InternalPixelType; - typedef itk::Image InternalImageType; - typedef mitk::Tool::DefaultSegmentationDataType OutputPixelType; - typedef itk::Image OutputImageType; - - typedef itk::BinaryThresholdImageFilter ThresholdingFilterType; - typedef itk::CurvatureAnisotropicDiffusionImageFilter SmoothingFilterType; - typedef itk::GradientMagnitudeRecursiveGaussianImageFilter GradientFilterType; - typedef itk::SigmoidImageFilter SigmoidFilterType; - typedef itk::FastMarchingImageFilter FastMarchingFilterType; - typedef FastMarchingFilterType::NodeContainer NodeContainer; - typedef FastMarchingFilterType::NodeType NodeType; - - bool CanHandle(BaseData *referenceData) const override; + bool CanHandle(const BaseData* referenceData, const BaseData* workingData) const override; /* icon stuff */ const char **GetXPM() const override; const char *GetName() const override; us::ModuleResource GetIconResource() const override; + void Activated() override; + void Deactivated() 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(); ~FastMarchingTool3D() override; - void Activated() override; - 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; + void UpdatePrepare() override; + void UpdateCleanUp() override; + void DoUpdatePreview(const Image* inputAtTimeStep, Image* previewImage, TimeStepType timeStep) override; - int m_CurrentTimeStep; + template + void DoITKFastMarching(const itk::Image* inputImage, + mitk::Image* segmentation, unsigned int timeStep); 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 + typedef float InternalPixelType; + typedef itk::Image InternalImageType; + typedef itk::FastMarchingImageFilter FastMarchingFilterType; + typedef FastMarchingFilterType::NodeContainer NodeContainer; + typedef FastMarchingFilterType::NodeType NodeType; - mitk::DataNode::Pointer m_ResultImageNode; // holds the result as a preview image + NodeContainer::Pointer m_SeedContainer; // seed points for FastMarching mitk::DataNode::Pointer m_SeedsAsPointSetNode; // used to visualize the seed points mitk::PointSet::Pointer m_SeedsAsPointSet; mitk::PointSetDataInteractor::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/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.cpp index 855a67e49c..973f3ce26e 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.cpp @@ -1,370 +1,361 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "QmitkFastMarchingTool3DGUI.h" #include "QmitkConfirmSegmentationDialog.h" #include "mitkBaseRenderer.h" #include "mitkStepper.h" #include #include #include #include #include #include #include #include +#include MITK_TOOL_GUI_MACRO(MITKSEGMENTATIONUI_EXPORT, QmitkFastMarchingTool3DGUI, "") -QmitkFastMarchingTool3DGUI::QmitkFastMarchingTool3DGUI() : QmitkToolGUI(), m_TimeIsConnected(false) +QmitkFastMarchingTool3DGUI::QmitkFastMarchingTool3DGUI() : QmitkToolGUI() { this->setContentsMargins(0, 0, 0, 0); // create the visible widgets QVBoxLayout *widgetLayout = new QVBoxLayout(this); widgetLayout->setContentsMargins(0, 0, 0, 0); QFont fntHelp; fntHelp.setBold(true); QLabel *lblHelp = new QLabel(this); lblHelp->setText("Press shift-click to add seeds repeatedly."); lblHelp->setFont(fntHelp); widgetLayout->addWidget(lblHelp); // Sigma controls { QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setSpacing(2); QLabel *lbl = new QLabel(this); lbl->setText("Sigma: "); hlayout->addWidget(lbl); QSpacerItem *sp2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hlayout->addItem(sp2); widgetLayout->addItem(hlayout); } m_slSigma = new ctkSliderWidget(this); m_slSigma->setMinimum(0.1); m_slSigma->setMaximum(5.0); m_slSigma->setPageStep(0.1); m_slSigma->setSingleStep(0.01); m_slSigma->setValue(1.0); m_slSigma->setTracking(false); m_slSigma->setToolTip("The \"sigma\" parameter in the Gradient Magnitude filter."); connect(m_slSigma, SIGNAL(valueChanged(double)), this, SLOT(OnSigmaChanged(double))); widgetLayout->addWidget(m_slSigma); // Alpha controls { QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setSpacing(2); QLabel *lbl = new QLabel(this); lbl->setText("Alpha: "); hlayout->addWidget(lbl); QSpacerItem *sp2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hlayout->addItem(sp2); widgetLayout->addItem(hlayout); } m_slAlpha = new ctkSliderWidget(this); m_slAlpha->setMinimum(-10); m_slAlpha->setMaximum(0); m_slAlpha->setPageStep(0.1); m_slAlpha->setSingleStep(0.01); m_slAlpha->setValue(-2.5); m_slAlpha->setTracking(false); m_slAlpha->setToolTip("The \"alpha\" parameter in the Sigmoid mapping filter."); connect(m_slAlpha, SIGNAL(valueChanged(double)), this, SLOT(OnAlphaChanged(double))); widgetLayout->addWidget(m_slAlpha); // Beta controls { QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setSpacing(2); QLabel *lbl = new QLabel(this); lbl->setText("Beta: "); hlayout->addWidget(lbl); QSpacerItem *sp2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hlayout->addItem(sp2); widgetLayout->addLayout(hlayout); } m_slBeta = new ctkSliderWidget(this); m_slBeta->setMinimum(0); m_slBeta->setMaximum(100); m_slBeta->setPageStep(0.1); m_slBeta->setSingleStep(0.01); m_slBeta->setValue(3.5); m_slBeta->setTracking(false); m_slBeta->setToolTip("The \"beta\" parameter in the Sigmoid mapping filter."); connect(m_slBeta, SIGNAL(valueChanged(double)), this, SLOT(OnBetaChanged(double))); widgetLayout->addWidget(m_slBeta); // stopping value controls { QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setSpacing(2); QLabel *lbl = new QLabel(this); lbl->setText("Stopping value: "); hlayout->addWidget(lbl); QSpacerItem *sp2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hlayout->addItem(sp2); widgetLayout->addLayout(hlayout); } m_slStoppingValue = new ctkSliderWidget(this); m_slStoppingValue->setMinimum(0); m_slStoppingValue->setMaximum(10000); m_slStoppingValue->setPageStep(10); m_slStoppingValue->setSingleStep(1); m_slStoppingValue->setValue(2000); m_slStoppingValue->setDecimals(0); m_slStoppingValue->setTracking(false); m_slStoppingValue->setToolTip("The \"stopping value\" parameter in the fast marching 3D algorithm"); connect(m_slStoppingValue, SIGNAL(valueChanged(double)), this, SLOT(OnStoppingValueChanged(double))); widgetLayout->addWidget(m_slStoppingValue); // threshold controls { QHBoxLayout *hlayout = new QHBoxLayout(); hlayout->setSpacing(2); QLabel *lbl = new QLabel(this); lbl->setText("Threshold: "); hlayout->addWidget(lbl); QSpacerItem *sp2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum); hlayout->addItem(sp2); widgetLayout->addLayout(hlayout); } m_slwThreshold = new ctkRangeWidget(this); m_slwThreshold->setMinimum(-100); m_slwThreshold->setMaximum(5000); m_slwThreshold->setMinimumValue(-100); m_slwThreshold->setMaximumValue(2000); m_slwThreshold->setDecimals(0); m_slwThreshold->setTracking(false); m_slwThreshold->setToolTip("The lower and upper thresholds for the final thresholding"); connect(m_slwThreshold, SIGNAL(valuesChanged(double, double)), this, SLOT(OnThresholdChanged(double, double))); widgetLayout->addWidget(m_slwThreshold); m_btClearSeeds = new QPushButton("Clear"); m_btClearSeeds->setToolTip("Clear current result and start over again"); m_btClearSeeds->setEnabled(false); widgetLayout->addWidget(m_btClearSeeds); connect(m_btClearSeeds, SIGNAL(clicked()), this, SLOT(OnClearSeeds())); m_btConfirm = new QPushButton("Confirm Segmentation"); m_btConfirm->setToolTip("Incorporate current result in your working session."); m_btConfirm->setEnabled(false); widgetLayout->addWidget(m_btConfirm); connect(m_btConfirm, SIGNAL(clicked()), this, SLOT(OnConfirmSegmentation())); + m_CheckProcessAll = new QCheckBox("Process all time steps", this); + m_CheckProcessAll->setChecked(false); + m_CheckProcessAll->setToolTip("Process/overwrite all time steps of the dynamic segmentation and not just the currently visible time step."); + widgetLayout->addWidget(m_CheckProcessAll); + + m_CheckCreateNew = new QCheckBox("Create as new segmentation", this); + m_CheckCreateNew->setChecked(false); + m_CheckCreateNew->setToolTip("Add the confirmed segmentation as a new segmentation instead of overwriting the currently selected."); + widgetLayout->addWidget(m_CheckCreateNew); + connect(this, SIGNAL(NewToolAssociated(mitk::Tool *)), this, SLOT(OnNewToolAssociated(mitk::Tool *))); m_slSigma->setDecimals(2); m_slBeta->setDecimals(2); m_slAlpha->setDecimals(2); this->EnableWidgets(false); } QmitkFastMarchingTool3DGUI::~QmitkFastMarchingTool3DGUI() { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy -= mitk::MessageDelegate1(this, &QmitkFastMarchingTool3DGUI::BusyStateChanged); - m_FastMarchingTool->RemoveReadyListener( - mitk::MessageDelegate(this, &QmitkFastMarchingTool3DGUI::OnFastMarchingToolReady)); } } void QmitkFastMarchingTool3DGUI::OnNewToolAssociated(mitk::Tool *tool) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy -= mitk::MessageDelegate1(this, &QmitkFastMarchingTool3DGUI::BusyStateChanged); - m_FastMarchingTool->RemoveReadyListener( - mitk::MessageDelegate(this, &QmitkFastMarchingTool3DGUI::OnFastMarchingToolReady)); } m_FastMarchingTool = dynamic_cast(tool); if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy += mitk::MessageDelegate1(this, &QmitkFastMarchingTool3DGUI::BusyStateChanged); - m_FastMarchingTool->AddReadyListener( - mitk::MessageDelegate(this, &QmitkFastMarchingTool3DGUI::OnFastMarchingToolReady)); - // listen to timestep change events - mitk::BaseRenderer::Pointer renderer; - renderer = mitk::BaseRenderer::GetInstance(mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget0")); - if (renderer.IsNotNull() && !m_TimeIsConnected) - { - new QmitkStepperAdapter(this, renderer->GetSliceNavigationController()->GetTime(), "stepper"); - // connect(m_TimeStepper, SIGNAL(Refetch()), this, SLOT(Refetch())); - m_TimeIsConnected = true; - } + m_FastMarchingTool->SetLowerThreshold(this->m_slwThreshold->minimumValue()); + m_FastMarchingTool->SetUpperThreshold(this->m_slwThreshold->maximumValue()); + m_FastMarchingTool->SetStoppingValue(this->m_slStoppingValue->value()); + m_FastMarchingTool->SetSigma(this->m_slSigma->value()); + m_FastMarchingTool->SetAlpha(this->m_slAlpha->value()); + m_FastMarchingTool->SetBeta(this->m_slBeta->value()); + m_FastMarchingTool->SetOverwriteExistingSegmentation(true); + m_FastMarchingTool->ClearSeeds(); + m_CheckProcessAll->setVisible(m_FastMarchingTool->GetTargetSegmentationNode()->GetData()->GetTimeSteps() > 1); } } void QmitkFastMarchingTool3DGUI::Update() { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetLowerThreshold(this->m_slwThreshold->minimumValue()); m_FastMarchingTool->SetUpperThreshold(this->m_slwThreshold->maximumValue()); m_FastMarchingTool->SetStoppingValue(this->m_slStoppingValue->value()); m_FastMarchingTool->SetSigma(this->m_slSigma->value()); m_FastMarchingTool->SetAlpha(this->m_slAlpha->value()); m_FastMarchingTool->SetBeta(this->m_slBeta->value()); - m_FastMarchingTool->Update(); + m_FastMarchingTool->UpdatePreview(); } } void QmitkFastMarchingTool3DGUI::OnThresholdChanged(double lower, double upper) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetLowerThreshold(lower); m_FastMarchingTool->SetUpperThreshold(upper); this->Update(); } } void QmitkFastMarchingTool3DGUI::OnBetaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetBeta(value); this->Update(); } } void QmitkFastMarchingTool3DGUI::OnSigmaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetSigma(value); this->Update(); } } void QmitkFastMarchingTool3DGUI::OnAlphaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetAlpha(value); this->Update(); } } void QmitkFastMarchingTool3DGUI::OnStoppingValueChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetStoppingValue(value); this->Update(); } } void QmitkFastMarchingTool3DGUI::OnConfirmSegmentation() { - QmitkConfirmSegmentationDialog dialog; - QString segName = QString::fromStdString(m_FastMarchingTool->GetCurrentSegmentationName()); - - dialog.SetSegmentationName(segName); - int result = dialog.exec(); - - switch (result) + if (m_FastMarchingTool.IsNotNull()) { - case QmitkConfirmSegmentationDialog::CREATE_NEW_SEGMENTATION: + if (m_CheckCreateNew->isChecked()) + { m_FastMarchingTool->SetOverwriteExistingSegmentation(false); - break; - case QmitkConfirmSegmentationDialog::OVERWRITE_SEGMENTATION: + } + else + { m_FastMarchingTool->SetOverwriteExistingSegmentation(true); - break; - case QmitkConfirmSegmentationDialog::CANCEL_SEGMENTATION: - return; - } - if (m_FastMarchingTool.IsNotNull()) - { + } + + m_FastMarchingTool->SetCreateAllTimeSteps(m_CheckProcessAll->isChecked()); + m_btConfirm->setEnabled(false); m_FastMarchingTool->ConfirmSegmentation(); } } -void QmitkFastMarchingTool3DGUI::SetStepper(mitk::Stepper *stepper) -{ - this->m_TimeStepper = stepper; -} - -void QmitkFastMarchingTool3DGUI::Refetch() -{ - // event from image navigator recieved - timestep has changed - m_FastMarchingTool->SetCurrentTimeStep(m_TimeStepper->GetPos()); -} - void QmitkFastMarchingTool3DGUI::OnClearSeeds() { // event from image navigator recieved - timestep has changed m_FastMarchingTool->ClearSeeds(); m_btClearSeeds->setEnabled(false); m_btConfirm->setEnabled(false); this->EnableWidgets(false); this->Update(); } void QmitkFastMarchingTool3DGUI::BusyStateChanged(bool value) { if (value) + { QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + this->EnableWidgets(false); + } else + { QApplication::restoreOverrideCursor(); -} - -void QmitkFastMarchingTool3DGUI::OnFastMarchingToolReady() -{ - this->EnableWidgets(true); - this->m_btClearSeeds->setEnabled(true); - this->m_btConfirm->setEnabled(true); + this->EnableWidgets(true); + } } void QmitkFastMarchingTool3DGUI::EnableWidgets(bool enable) { - m_slSigma->setEnabled(enable); - m_slAlpha->setEnabled(enable); - m_slBeta->setEnabled(enable); - m_slStoppingValue->setEnabled(enable); - m_slwThreshold->setEnabled(enable); + this->m_slSigma->setEnabled(enable); + this->m_slAlpha->setEnabled(enable); + this->m_slBeta->setEnabled(enable); + this->m_slStoppingValue->setEnabled(enable); + this->m_slwThreshold->setEnabled(enable); + this->m_btClearSeeds->setEnabled(enable); + this->m_btConfirm->setEnabled(enable); + this->m_CheckCreateNew->setEnabled(enable); + this->m_CheckProcessAll->setEnabled(enable); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.h b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.h index 67c8204881..a02b18de12 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingTool3DGUI.h @@ -1,84 +1,79 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkFastMarchingTool3DGUI_h_Included #define QmitkFastMarchingTool3DGUI_h_Included #include "QmitkToolGUI.h" #include "mitkFastMarchingTool3D.h" #include class ctkSliderWidget; class ctkRangeWidget; class QPushButton; - -#include "QmitkStepperAdapter.h" +class QCheckBox; /** \ingroup org_mitk_gui_qt_interactivesegmentation_internal \brief GUI for mitk::FastMarchingTool. \sa mitk::FastMarchingTool */ class MITKSEGMENTATIONUI_EXPORT QmitkFastMarchingTool3DGUI : public QmitkToolGUI { Q_OBJECT public: mitkClassMacro(QmitkFastMarchingTool3DGUI, QmitkToolGUI); itkFactorylessNewMacro(Self); itkCloneMacro(Self); void OnThresholdChanged(int current); protected slots: void OnNewToolAssociated(mitk::Tool *); void OnThresholdChanged(double, double); void OnAlphaChanged(double); void OnBetaChanged(double); void OnSigmaChanged(double); void OnStoppingValueChanged(double); void OnConfirmSegmentation(); - void Refetch(); - void SetStepper(mitk::Stepper *); void OnClearSeeds(); protected: QmitkFastMarchingTool3DGUI(); ~QmitkFastMarchingTool3DGUI() override; void BusyStateChanged(bool) override; void Update(); ctkRangeWidget *m_slwThreshold; ctkSliderWidget *m_slStoppingValue; ctkSliderWidget *m_slSigma; ctkSliderWidget *m_slAlpha; ctkSliderWidget *m_slBeta; QPushButton *m_btConfirm; QPushButton *m_btClearSeeds; - mitk::FastMarchingTool3D::Pointer m_FastMarchingTool; - - bool m_TimeIsConnected; - mitk::Stepper::Pointer m_TimeStepper; + QCheckBox* m_CheckProcessAll = nullptr; + QCheckBox* m_CheckCreateNew = nullptr; - void OnFastMarchingToolReady(); + mitk::FastMarchingTool3D::Pointer m_FastMarchingTool; private: void EnableWidgets(bool); }; #endif