diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool.cpp b/Modules/Segmentation/Interactions/mitkFastMarchingTool.cpp index 62c4226f14..13fdb1b82e 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool.cpp +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool.cpp @@ -1,433 +1,465 @@ /*=================================================================== 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 "mitkFastMarchingTool.h" #include "mitkToolManager.h" - #include "mitkBaseRenderer.h" #include "mitkRenderingManager.h" #include "mitkInteractionConst.h" #include "itkOrImageFilter.h" #include "mitkImageTimeSelector.h" - // us #include "mitkModule.h" #include "mitkModuleResource.h" #include namespace mitk { MITK_TOOL_MACRO(Segmentation_EXPORT, FastMarchingTool, "FastMarching2D tool"); } mitk::FastMarchingTool::FastMarchingTool() :FeedbackContourTool("PressMoveReleaseAndPointSetting"), m_NeedUpdate(true), m_CurrentTimeStep(0), m_LowerThreshold(0), m_UpperThreshold(200), m_StoppingValue(100), m_Sigma(1.0), m_Alpha(-0.5), -m_Beta(3.0) +m_Beta(3.0), +m_PositionEvent(0) { CONNECT_ACTION( AcADDPOINTRMB, OnAddPoint ); CONNECT_ACTION( AcADDPOINT, OnAddPoint ); CONNECT_ACTION( AcREMOVEPOINT, OnDelete ); - m_ReferenceImageSliceAsITK = 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_SeedContainer = NodeContainer::New(); - m_SeedContainer->Initialize(); - m_FastMarchingFilter->SetTrialPoints( m_SeedContainer ); - - //set up pipeline - m_SmoothFilter->SetInput( m_ReferenceImageSliceAsITK ); - m_GradientMagnitudeFilter->SetInput( m_SmoothFilter->GetOutput() ); - m_SigmoidFilter->SetInput( m_GradientMagnitudeFilter->GetOutput() ); - m_FastMarchingFilter->SetInput( m_SigmoidFilter->GetOutput() ); - m_ThresholdFilter->SetInput( m_FastMarchingFilter->GetOutput() ); + //this->BuildITKPipeline(); } mitk::FastMarchingTool::~FastMarchingTool() { + if (this->m_SmoothFilter.IsNotNull()) + this->m_SmoothFilter->RemoveAllObservers(); + + if (this->m_SigmoidFilter.IsNotNull()) + this->m_SigmoidFilter->RemoveAllObservers(); + + if (this->m_GradientMagnitudeFilter.IsNotNull()) + this->m_GradientMagnitudeFilter->RemoveAllObservers(); + + if (this->m_FastMarchingFilter.IsNotNull()) + this->m_FastMarchingFilter->RemoveAllObservers(); } float mitk::FastMarchingTool::CanHandleEvent( StateEvent const *stateEvent) const { float returnValue = Superclass::CanHandleEvent(stateEvent); //we can handle delete if(stateEvent->GetId() == 12 ) { returnValue = 1.0; } return returnValue; } const char** mitk::FastMarchingTool::GetXPM() const { return NULL;//mitkFastMarchingTool_xpm; } mitk::ModuleResource mitk::FastMarchingTool::GetIconResource() const { Module* module = GetModuleContext()->GetModule(); ModuleResource resource = module->GetResource("FastMarching_48x48.png"); return resource; } mitk::ModuleResource mitk::FastMarchingTool::GetCursorIconResource() const { Module* module = GetModuleContext()->GetModule(); ModuleResource resource = module->GetResource("FastMarching_Cursor_32x32.png"); return resource; } const char* mitk::FastMarchingTool::GetName() const { return "FastMarching2D"; } -void mitk::FastMarchingTool::SetUpperThreshold(double value) +void mitk::FastMarchingTool::BuildITKPipeline() { - m_UpperThreshold = value / 10.0; + m_ReferenceImageSliceAsITK = InternalImageType::New(); + + m_ReferenceImageSlice = GetAffectedReferenceSlice( m_PositionEvent ); + CastToItkImage(m_ReferenceImageSlice, m_ReferenceImageSliceAsITK); + + m_ProgressCommand = mitk::ToolCommand::New(); + + m_SmoothFilter = SmoothingFilterType::New(); + m_SmoothFilter->SetInput( m_ReferenceImageSliceAsITK ); + m_SmoothFilter->SetTimeStep( 0.05 ); + m_SmoothFilter->SetNumberOfIterations( 2 ); + m_SmoothFilter->SetConductanceParameter( 9.0 ); + + m_GradientMagnitudeFilter = GradientFilterType::New(); + m_GradientMagnitudeFilter->SetSigma( m_Sigma ); + + m_SigmoidFilter = SigmoidFilterType::New(); + 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->SetStoppingValue( m_StoppingValue ); + + m_ThresholdFilter = ThresholdingFilterType::New(); + m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold ); m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold ); - m_NeedUpdate = true; + m_ThresholdFilter->SetOutsideValue( 0 ); + m_ThresholdFilter->SetInsideValue( 1.0 ); + + m_SeedContainer = NodeContainer::New(); + m_SeedContainer->Initialize(); + m_FastMarchingFilter->SetTrialPoints( m_SeedContainer ); + + if (this->m_SmoothFilter.IsNotNull()) + this->m_SmoothFilter->RemoveAllObservers(); + + if (this->m_SigmoidFilter.IsNotNull()) + this->m_SigmoidFilter->RemoveAllObservers(); + + if (this->m_GradientMagnitudeFilter.IsNotNull()) + this->m_GradientMagnitudeFilter->RemoveAllObservers(); + + if (this->m_FastMarchingFilter.IsNotNull()) + this->m_FastMarchingFilter->RemoveAllObservers(); + + m_SmoothFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); + m_GradientMagnitudeFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); + m_SigmoidFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); + m_FastMarchingFilter->AddObserver( itk::ProgressEvent(), m_ProgressCommand); + + m_SmoothFilter->SetInput( m_ReferenceImageSliceAsITK ); + 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_ReferenceImageSliceAsITK = InternalImageType::New(); +} + +void mitk::FastMarchingTool::SetUpperThreshold(double value) +{ + if (m_UpperThreshold != value) + { + m_UpperThreshold = value / 10.0; + m_ThresholdFilter->SetUpperThreshold( m_UpperThreshold ); + m_NeedUpdate = true; + } } void mitk::FastMarchingTool::SetLowerThreshold(double value) { - m_LowerThreshold = value / 10.0; - m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold ); - m_NeedUpdate = true; + if (m_LowerThreshold != value) + { + m_LowerThreshold = value / 10.0; + m_ThresholdFilter->SetLowerThreshold( m_LowerThreshold ); + m_NeedUpdate = true; + } } void mitk::FastMarchingTool::SetBeta(double value) { if (m_Beta != value) { - m_Beta = value; - m_SigmoidFilter->SetBeta( m_Beta ); - m_NeedUpdate = true; + m_Beta = value; + m_SigmoidFilter->SetBeta( m_Beta ); + m_NeedUpdate = true; } } void mitk::FastMarchingTool::SetSigma(double value) { if (m_Sigma != value) { - m_Sigma = value; - m_GradientMagnitudeFilter->SetSigma( m_Sigma ); - m_NeedUpdate = true; + m_Sigma = value; + m_GradientMagnitudeFilter->SetSigma( m_Sigma ); + m_NeedUpdate = true; } } void mitk::FastMarchingTool::SetAlpha(double value) { if (m_Alpha != value) { m_Alpha = value; m_SigmoidFilter->SetAlpha( m_Alpha ); m_NeedUpdate = true; } } void mitk::FastMarchingTool::SetStoppingValue(double value) { if (m_StoppingValue != value) { m_StoppingValue = value; m_FastMarchingFilter->SetStoppingValue( m_StoppingValue ); m_NeedUpdate = true; } } void mitk::FastMarchingTool::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("Seeds_Preview"); m_SeedsAsPointSetNode->SetBoolProperty("helper object", true); m_SeedsAsPointSetNode->SetColor(0.0, 1.0, 0.0); m_SeedsAsPointSetNode->SetVisibility(true); m_ToolManager->GetDataStorage()->Add( this->m_SeedsAsPointSetNode, m_ToolManager->GetReferenceData(0)); this->Initialize(); } void mitk::FastMarchingTool::Deactivated() { Superclass::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 = NULL; mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::FastMarchingTool::Initialize() { m_ReferenceImage = dynamic_cast(m_ToolManager->GetReferenceData(0)->GetData()); if(m_ReferenceImage->GetTimeSlicedGeometry()->GetTimeSteps() > 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::FastMarchingTool::ConfirmSegmentation() { // combine preview image with current working segmentation if (dynamic_cast(m_ResultImageNode->GetData())) { //logical or combination of preview and segmentation slice OutputImageType::Pointer workingImageSliceInITK = OutputImageType::New(); mitk::Image::Pointer workingImageSlice; mitk::Image::Pointer workingImage = dynamic_cast(this->m_ToolManager->GetWorkingData(0)->GetData()); if(workingImage->GetTimeSlicedGeometry()->GetTimeSteps() > 1) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput( workingImage ); timeSelector->SetTimeNr( m_CurrentTimeStep ); timeSelector->UpdateLargestPossibleRegion(); // todo: make GetAffectedWorkingSlice dependant of current time step workingImageSlice = GetAffectedWorkingSlice( m_PositionEvent ); CastToItkImage( workingImageSlice, workingImageSliceInITK ); } else { workingImageSlice = GetAffectedWorkingSlice( m_PositionEvent ); CastToItkImage( workingImageSlice, workingImageSliceInITK ); } typedef itk::OrImageFilter OrImageFilterType; OrImageFilterType::Pointer orFilter = OrImageFilterType::New(); orFilter->SetInput(0, m_ThresholdFilter->GetOutput()); orFilter->SetInput(1, workingImageSliceInITK); orFilter->Update(); mitk::Image::Pointer segmentationResult = mitk::Image::New(); mitk::CastToMitkImage(orFilter->GetOutput(), segmentationResult); segmentationResult->GetGeometry()->SetOrigin(workingImageSlice->GetGeometry()->GetOrigin()); segmentationResult->GetGeometry()->SetIndexToWorldTransform(workingImageSlice->GetGeometry()->GetIndexToWorldTransform()); //write to segmentation volume and hide preview image // again, current time step is not considered this->WriteBackSegmentationResult(m_PositionEvent, segmentationResult ); this->m_ResultImageNode->SetVisibility(false); + this->ClearSeeds(); -// workingImage->Modified(); } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } bool mitk::FastMarchingTool::OnAddPoint(Action* action, const StateEvent* stateEvent) { // Add a new seed point for FastMarching algorithm const PositionEvent* p = dynamic_cast(stateEvent->GetEvent()); if (!p) return false; - m_PositionEvent = new PositionEvent(p->GetSender(), p->GetType(), p->GetButton(), p->GetButtonState(), p->GetKey(), p->GetDisplayPosition(), p->GetWorldPosition()); + if (m_PositionEvent != NULL) + delete m_PositionEvent; + m_PositionEvent = new PositionEvent(p->GetSender(), p->GetType(), p->GetButton(), p->GetButtonState(), p->GetKey(), p->GetDisplayPosition(), p->GetWorldPosition() ); - //if click happpened in another renderwindow or slice then reset pipeline and preview + //if click was on another renderwindow or slice then reset pipeline and preview if( (m_LastEventSender != m_PositionEvent->GetSender()) || (m_LastEventSlice != m_PositionEvent->GetSender()->GetSlice()) ) { - m_ReferenceImageSlice = GetAffectedReferenceSlice( m_PositionEvent ); - CastToItkImage(m_ReferenceImageSlice, m_ReferenceImageSliceAsITK); - m_SmoothFilter->SetInput( m_ReferenceImageSliceAsITK ); + this->BuildITKPipeline(); } m_LastEventSender = m_PositionEvent->GetSender(); m_LastEventSlice = m_LastEventSender->GetSlice(); mitk::Point3D clickInIndex; m_ReferenceImageSlice->GetGeometry()->WorldToIndex(m_PositionEvent->GetWorldPosition(), clickInIndex); itk::Index<2> seedPosition; seedPosition[0] = clickInIndex[0]; seedPosition[1] = clickInIndex[1]; 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(); m_SeedsAsPointSet->InsertPoint(m_SeedsAsPointSet->GetSize(), m_PositionEvent->GetWorldPosition()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_NeedUpdate = true; this->Update(); return true; } bool mitk::FastMarchingTool::OnDelete(Action* action, const StateEvent* stateEvent) { // delete last seed point if(!(this->m_SeedContainer->empty())) { //delete last element of seeds container this->m_SeedContainer->pop_back(); m_FastMarchingFilter->Modified(); //delete last point in pointset - somehow ugly m_SeedsAsPointSet->GetPointSet()->GetPoints()->DeleteIndex(m_SeedsAsPointSet->GetSize() - 1); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_NeedUpdate = true; this->Update(); } return true; } void mitk::FastMarchingTool::Update() { // update FastMarching pipeline and show result if (m_NeedUpdate) { m_ProgressCommand->AddStepsToDo(20); CurrentlyBusy.Send(true); try { m_ThresholdFilter->Update(); } catch( itk::ExceptionObject & excep ) { MITK_ERROR << "Exception caught: " << excep.GetDescription(); m_ProgressCommand->SetRemainingProgress(100); CurrentlyBusy.Send(false); std::string msg = excep.GetDescription(); ErrorMessage.Send(msg); return; } m_ProgressCommand->SetRemainingProgress(100); CurrentlyBusy.Send(false); //make output visible mitk::Image::Pointer result = mitk::Image::New(); CastToMitkImage( m_ThresholdFilter->GetOutput(), result); result->GetGeometry()->SetOrigin(m_ReferenceImageSlice->GetGeometry()->GetOrigin() ); result->GetGeometry()->SetIndexToWorldTransform(m_ReferenceImageSlice->GetGeometry()->GetIndexToWorldTransform() ); m_ResultImageNode->SetData(result); m_ResultImageNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::FastMarchingTool::ClearSeeds() { // clear seeds for FastMarching as well as the PointSet for visualization this->m_SeedContainer->Initialize(); this->m_SeedsAsPointSet->Clear(); m_FastMarchingFilter->Modified(); this->m_NeedUpdate = true; } void mitk::FastMarchingTool::Reset() { //clear all seeds and preview empty result this->ClearSeeds(); m_ResultImageNode->SetVisibility(false); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void mitk::FastMarchingTool::SetCurrentTimeStep(int t) { if( m_CurrentTimeStep != t ) { m_CurrentTimeStep = t; this->Initialize(); } } diff --git a/Modules/Segmentation/Interactions/mitkFastMarchingTool.h b/Modules/Segmentation/Interactions/mitkFastMarchingTool.h index f4141c47a7..e824a55fd1 100644 --- a/Modules/Segmentation/Interactions/mitkFastMarchingTool.h +++ b/Modules/Segmentation/Interactions/mitkFastMarchingTool.h @@ -1,168 +1,170 @@ /*=================================================================== 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 "SegmentationExports.h" #include "mitkDataNode.h" #include "mitkPointSet.h" #include "mitkToolCommand.h" #include "mitkPositionEvent.h" #include "itkImage.h" //itk filter #include "itkFastMarchingImageFilter.h" #include "itkBinaryThresholdImageFilter.h" #include "itkGradientMagnitudeRecursiveGaussianImageFilter.h" #include "itkSigmoidImageFilter.h" #include "itkCurvatureAnisotropicDiffusionImageFilter.h" 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 Segmentation_EXPORT FastMarchingTool : public FeedbackContourTool { public: mitkClassMacro(FastMarchingTool, FeedbackContourTool); itkNewMacro(FastMarchingTool); /* typedefs for itk pipeline */ typedef float InternalPixelType; typedef itk::Image< InternalPixelType, 2 > InternalImageType; typedef unsigned char 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; virtual const char* GetName() const; virtual ModuleResource GetCursorIconResource() const; ModuleResource GetIconResource() const; /// \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(); virtual float CanHandleEvent( StateEvent const *stateEvent) const; virtual void Activated(); virtual void Deactivated(); virtual void Initialize(); + virtual void BuildITKPipeline(); + /// \brief Add point action of StateMachine pattern virtual bool OnAddPoint (Action*, const StateEvent*); /// \brief Delete action of StateMachine pattern virtual bool OnDelete (Action*, const StateEvent*); /// \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::PositionEvent* 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; }; } // namespace #endif diff --git a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.cpp b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.cpp index 68789b3a72..1911a86e84 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.cpp +++ b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.cpp @@ -1,320 +1,323 @@ /*=================================================================== 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 "QmitkFastMarchingToolGUI.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include #include #include #include #include #include "mitkStepper.h" #include "mitkBaseRenderer.h" MITK_TOOL_GUI_MACRO(SegmentationUI_EXPORT, QmitkFastMarchingToolGUI, "") QmitkFastMarchingToolGUI::QmitkFastMarchingToolGUI() :QmitkToolGUI(), m_TimeIsConnected(false) { 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->setDecimals(2); 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->setDecimals(2); 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->setDecimals(2); 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"); widgetLayout->addWidget(m_btClearSeeds); connect( m_btClearSeeds, SIGNAL(clicked()), this, SLOT(OnClearSeeds()) ); m_btConfirm = new QPushButton("Accept"); m_btConfirm->setToolTip("Incorporate current result in your working session."); widgetLayout->addWidget(m_btConfirm); connect( m_btConfirm, SIGNAL(clicked()), this, SLOT(OnConfirmSegmentation()) ); connect( this, SIGNAL(NewToolAssociated(mitk::Tool*)), this, SLOT(OnNewToolAssociated(mitk::Tool*)) ); } QmitkFastMarchingToolGUI::~QmitkFastMarchingToolGUI() { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy -= mitk::MessageDelegate1( this, &QmitkFastMarchingToolGUI::BusyStateChanged ); } } void QmitkFastMarchingToolGUI::OnNewToolAssociated(mitk::Tool* tool) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy -= mitk::MessageDelegate1( this, &QmitkFastMarchingToolGUI::BusyStateChanged ); } m_FastMarchingTool = dynamic_cast( tool ); if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->CurrentlyBusy += mitk::MessageDelegate1( this, &QmitkFastMarchingToolGUI::BusyStateChanged ); - // set tool´s default values - 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()); - //listen to timestep change events mitk::BaseRenderer::Pointer renderer; renderer = mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1") ); if (renderer.IsNotNull() && !m_TimeIsConnected) { new QmitkStepperAdapter(this, renderer->GetSliceNavigationController()->GetTime(), "stepper"); // connect(m_TimeStepper, SIGNAL(Refetch()), this, SLOT(Refetch())); m_TimeIsConnected = true; } } } +void QmitkFastMarchingToolGUI::Update() +{ + 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(); +} + void QmitkFastMarchingToolGUI::OnThresholdChanged(double lower, double upper) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetLowerThreshold( lower ); m_FastMarchingTool->SetUpperThreshold( upper ); - m_FastMarchingTool->Update(); + this->Update(); } } void QmitkFastMarchingToolGUI::OnBetaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetBeta( value ); - m_FastMarchingTool->Update(); + this->Update(); } } void QmitkFastMarchingToolGUI::OnSigmaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetSigma( value ); - m_FastMarchingTool->Update(); + this->Update(); } } void QmitkFastMarchingToolGUI::OnAlphaChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetAlpha( value ); - m_FastMarchingTool->Update(); + this->Update(); } } void QmitkFastMarchingToolGUI::OnStoppingValueChanged(double value) { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->SetStoppingValue( value ); - m_FastMarchingTool->Update(); + this->Update(); } } void QmitkFastMarchingToolGUI::OnConfirmSegmentation() { if (m_FastMarchingTool.IsNotNull()) { m_FastMarchingTool->ConfirmSegmentation(); } } void QmitkFastMarchingToolGUI::SetStepper(mitk::Stepper *stepper) { this->m_TimeStepper = stepper; } void QmitkFastMarchingToolGUI::Refetch() { //event from image navigator recieved - timestep has changed m_FastMarchingTool->SetCurrentTimeStep(m_TimeStepper->GetPos()); } void QmitkFastMarchingToolGUI::OnClearSeeds() { //event from image navigator recieved - timestep has changed m_FastMarchingTool->ClearSeeds(); - m_FastMarchingTool->Update(); + this->Update(); } void QmitkFastMarchingToolGUI::BusyStateChanged(bool value) { if (value) QApplication::setOverrideCursor( QCursor(Qt::BusyCursor) ); else QApplication::restoreOverrideCursor(); } diff --git a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.h b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.h index a30731f782..9d7f9a79a4 100644 --- a/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.h +++ b/Modules/SegmentationUI/Qmitk/QmitkFastMarchingToolGUI.h @@ -1,81 +1,83 @@ /*=================================================================== 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 QmitkFastMarchingToolGUI_h_Included #define QmitkFastMarchingToolGUI_h_Included #include "QmitkToolGUI.h" #include "SegmentationUIExports.h" #include "mitkFastMarchingTool.h" class ctkSliderWidget; class ctkRangeWidget; class QPushButton; #include "QmitkStepperAdapter.h" /** \ingroup org_mitk_gui_qt_interactivesegmentation_internal \brief GUI for mitk::FastMarchingTool. \sa mitk::FastMarchingTool */ class SegmentationUI_EXPORT QmitkFastMarchingToolGUI : public QmitkToolGUI { Q_OBJECT public: mitkClassMacro(QmitkFastMarchingToolGUI, QmitkToolGUI); itkNewMacro(QmitkFastMarchingToolGUI); 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: QmitkFastMarchingToolGUI(); virtual ~QmitkFastMarchingToolGUI(); + void Update(); + void BusyStateChanged(bool); ctkRangeWidget* m_slwThreshold; ctkSliderWidget* m_slStoppingValue; ctkSliderWidget* m_slSigma; ctkSliderWidget* m_slAlpha; ctkSliderWidget* m_slBeta; QPushButton* m_btConfirm; QPushButton* m_btClearSeeds; mitk::FastMarchingTool::Pointer m_FastMarchingTool; bool m_TimeIsConnected; mitk::Stepper::Pointer m_TimeStepper; }; #endif