diff --git a/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.cpp b/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.cpp index 415e038983..d4d2a028e7 100644 --- a/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.cpp +++ b/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.cpp @@ -1,312 +1,336 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.12 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkBinaryThresholdTool.h" #include "mitkBinaryThresholdTool.xpm" #include "mitkToolManager.h" #include "mitkBoundingObjectToSegmentationFilter.h" #include #include "mitkLevelWindowProperty.h" #include "mitkColorProperty.h" #include "mitkProperties.h" #include "mitkOrganTypeProperty.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkDataStorage.h" #include "mitkRenderingManager.h" #include "mitkImageCast.h" #include "mitkImageAccessByItk.h" #include "mitkImageTimeSelector.h" #include #include #include "mitkPadImageFilter.h" #include "mitkMaskAndCutRoiImageFilter.h" namespace mitk { MITK_TOOL_MACRO(MitkExt_EXPORT, BinaryThresholdTool, "Thresholding tool"); } mitk::BinaryThresholdTool::BinaryThresholdTool() :m_SensibleMinimumThresholdValue(-100), m_SensibleMaximumThresholdValue(+100), -m_CurrentThresholdValue(1) +m_CurrentThresholdValue(1), +m_IsFloatImage(false) { this->SupportRoiOn(); m_ThresholdFeedbackNode = DataNode::New(); mitk::CoreObjectFactory::GetInstance()->SetDefaultProperties( m_ThresholdFeedbackNode ); m_ThresholdFeedbackNode->SetProperty( "color", ColorProperty::New(1.0, 0.0, 0.0) ); m_ThresholdFeedbackNode->SetProperty( "texture interpolation", BoolProperty::New(false) ); m_ThresholdFeedbackNode->SetProperty( "layer", IntProperty::New( 100 ) ); m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(100, 1) ) ); m_ThresholdFeedbackNode->SetProperty( "name", StringProperty::New("Thresholding feedback") ); m_ThresholdFeedbackNode->SetProperty( "opacity", FloatProperty::New(0.3) ); m_ThresholdFeedbackNode->SetProperty( "helper object", BoolProperty::New(true) ); } mitk::BinaryThresholdTool::~BinaryThresholdTool() { } const char** mitk::BinaryThresholdTool::GetXPM() const { return mitkBinaryThresholdTool_xpm; } const char* mitk::BinaryThresholdTool::GetName() const { return "Thresholding"; } void mitk::BinaryThresholdTool::Activated() { m_ToolManager->RoiDataChanged += mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::OnRoiDataChanged); m_OriginalImageNode = m_ToolManager->GetReferenceData(0); m_NodeForThresholding = m_OriginalImageNode; if ( m_NodeForThresholding.IsNotNull() ) { SetupPreviewNodeFor( m_NodeForThresholding ); } else { m_ToolManager->ActivateTool(-1); } } void mitk::BinaryThresholdTool::Deactivated() { m_ToolManager->RoiDataChanged -= mitk::MessageDelegate(this, &mitk::BinaryThresholdTool::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::BinaryThresholdTool::SetThresholdValue(int value) { if (m_ThresholdFeedbackNode.IsNotNull()) { m_CurrentThresholdValue = value; - m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(m_CurrentThresholdValue, 1) ) ); + + if (m_IsFloatImage) + m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(m_CurrentThresholdValue * 0.01f, 0.01f) ) ); + else + m_ThresholdFeedbackNode->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow(m_CurrentThresholdValue, 1) ) ); + RenderingManager::GetInstance()->RequestUpdateAll(); } } void mitk::BinaryThresholdTool::AcceptCurrentThresholdValue(const std::string& organName, const Color& color) { CreateNewSegmentationFromThreshold(m_NodeForThresholding, organName, color ); RenderingManager::GetInstance()->RequestUpdateAll(); m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdTool::CancelThresholding() { m_ToolManager->ActivateTool(-1); } void mitk::BinaryThresholdTool::SetupPreviewNodeFor( DataNode* nodeForThresholding ) { if (nodeForThresholding) { Image::Pointer image = dynamic_cast( nodeForThresholding->GetData() ); Image::Pointer originalImage = dynamic_cast (m_OriginalImageNode->GetData()); if (image.IsNotNull()) { // initialize and a new node with the same image as our reference image // use the level window property of this image copy to display the result of a thresholding operation m_ThresholdFeedbackNode->SetData( image ); int layer(50); nodeForThresholding->GetIntProperty("layer", layer); m_ThresholdFeedbackNode->SetIntProperty("layer", layer+1); if (DataStorage* storage = m_ToolManager->GetDataStorage()) { if (storage->Exists(m_ThresholdFeedbackNode)) storage->Remove(m_ThresholdFeedbackNode); storage->Add( m_ThresholdFeedbackNode, m_OriginalImageNode ); } if (image.GetPointer() == originalImage.GetPointer()) { - m_SensibleMinimumThresholdValue = static_cast( originalImage->GetScalarValueMin() ); - m_SensibleMaximumThresholdValue = static_cast( originalImage->GetScalarValueMax() ); + if (originalImage->GetPixelType().GetType() == mitkIpPicFloat) + { + m_SensibleMinimumThresholdValue = static_cast( originalImage->GetScalarValueMin() * 100.0f); + m_SensibleMaximumThresholdValue = static_cast( originalImage->GetScalarValueMax() * 100.0f); + m_IsFloatImage = true; + } + else + { + m_SensibleMinimumThresholdValue = static_cast( originalImage->GetScalarValueMin() ); + m_SensibleMaximumThresholdValue = static_cast( originalImage->GetScalarValueMax() ); + m_IsFloatImage = false; + } } LevelWindowProperty::Pointer lwp = dynamic_cast( m_ThresholdFeedbackNode->GetProperty( "levelwindow" )); if (lwp) { m_CurrentThresholdValue = static_cast( lwp->GetLevelWindow().GetLevel() ); } else { m_CurrentThresholdValue = (m_SensibleMaximumThresholdValue + m_SensibleMinimumThresholdValue)/2; } IntervalBordersChanged.Send(m_SensibleMinimumThresholdValue, m_SensibleMaximumThresholdValue); ThresholdingValueChanged.Send(m_CurrentThresholdValue); } } } void mitk::BinaryThresholdTool::CreateNewSegmentationFromThreshold(DataNode* node, const std::string& organName, const Color& color) { if (node) { Image::Pointer image = dynamic_cast( m_NodeForThresholding->GetData() ); if (image.IsNotNull()) { // create a new image of the same dimensions and smallest possible pixel type DataNode::Pointer emptySegmentation = Tool::CreateEmptySegmentationNode( image, organName, color ); if (emptySegmentation) { // actually perform a thresholding and ask for an organ type for (unsigned int timeStep = 0; timeStep < image->GetTimeSteps(); ++timeStep) { try { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( image ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer image3D = timeSelector->GetOutput(); AccessFixedDimensionByItk_2( image3D, ITKThresholding, 3, dynamic_cast(emptySegmentation->GetData()), timeStep ); } catch(...) { Tool::ErrorMessage("Error accessing single time steps of the original image. Cannot create segmentation."); } } 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()); } if (DataStorage::Pointer storage = m_ToolManager->GetDataStorage()) { storage->Add( emptySegmentation, m_OriginalImageNode ); // add as a child, because the segmentation "derives" from the original } m_ToolManager->SetWorkingData( emptySegmentation ); } } } } template void mitk::BinaryThresholdTool::ITKThresholding( itk::Image* originalImage, Image* segmentation, unsigned int timeStep ) { ImageTimeSelector::Pointer timeSelector = ImageTimeSelector::New(); timeSelector->SetInput( segmentation ); timeSelector->SetTimeNr( timeStep ); timeSelector->UpdateLargestPossibleRegion(); Image::Pointer segmentation3D = timeSelector->GetOutput(); typedef itk::Image< Tool::DefaultSegmentationDataType, 3> SegmentationType; // this is sure for new segmentations SegmentationType::Pointer itkSegmentation; CastToItkImage( segmentation3D, itkSegmentation ); // iterate over original and segmentation typedef itk::ImageRegionConstIterator< itk::Image > InputIteratorType; typedef itk::ImageRegionIterator< SegmentationType > SegmentationIteratorType; InputIteratorType inputIterator( originalImage, originalImage->GetLargestPossibleRegion() ); SegmentationIteratorType outputIterator( itkSegmentation, itkSegmentation->GetLargestPossibleRegion() ); inputIterator.GoToBegin(); outputIterator.GoToBegin(); while (!outputIterator.IsAtEnd()) { - if ( (signed)inputIterator.Get() >= m_CurrentThresholdValue ) + if (m_IsFloatImage) { - outputIterator.Set( 1 ); + float realThresholdValue = m_CurrentThresholdValue * 0.01f; + + if (inputIterator.Get() >= realThresholdValue ) + outputIterator.Set( 1 ); + else + outputIterator.Set( 0 ); } else { - outputIterator.Set( 0 ); + if ( (signed)inputIterator.Get() >= m_CurrentThresholdValue ) + outputIterator.Set( 1 ); + else + outputIterator.Set( 0 ); } ++inputIterator; ++outputIterator; } } void mitk::BinaryThresholdTool::OnRoiDataChanged() { mitk::DataNode::Pointer node = m_ToolManager->GetRoiData(0); if (node.IsNotNull()) { mitk::Image::Pointer image = dynamic_cast (m_NodeForThresholding->GetData()); if (image.IsNull()) return; mitk::MaskAndCutRoiImageFilter::Pointer roiFilter = mitk::MaskAndCutRoiImageFilter::New(); roiFilter->SetInput(image); roiFilter->SetRegionOfInterest(node->GetData()); roiFilter->Update(); mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); mitk::Image::Pointer tmpImage = roiFilter->GetOutput(); tmpNode->SetData(tmpImage); m_SensibleMaximumThresholdValue = static_cast (roiFilter->GetMaxValue()); m_SensibleMinimumThresholdValue = static_cast (roiFilter->GetMinValue()); SetupPreviewNodeFor( tmpNode ); m_NodeForThresholding = tmpNode; return; } else { this->SetupPreviewNodeFor(m_OriginalImageNode); m_NodeForThresholding = m_OriginalImageNode; return; } } diff --git a/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.h b/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.h index a9f21155a4..54351bd655 100644 --- a/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.h +++ b/Modules/MitkExt/Interactions/mitkBinaryThresholdTool.h @@ -1,88 +1,89 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.0 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef mitkBinaryThresholdTool_h_Included #define mitkBinaryThresholdTool_h_Included #include "mitkCommon.h" #include "MitkExtExports.h" #include "mitkAutoSegmentationTool.h" #include "mitkDataNode.h" #include namespace mitk { /** \brief Calculates the segmented volumes for binary images. \ingroup ToolManagerEtAl \sa mitk::Tool \sa QmitkInteractiveSegmentation Last contributor: $Author$ */ class MitkExt_EXPORT BinaryThresholdTool : public AutoSegmentationTool { public: Message2 IntervalBordersChanged; Message1 ThresholdingValueChanged; mitkClassMacro(BinaryThresholdTool, AutoSegmentationTool); itkNewMacro(BinaryThresholdTool); virtual const char** GetXPM() const; virtual const char* GetName() const; virtual void Activated(); virtual void Deactivated(); virtual void SetThresholdValue(int value); virtual void AcceptCurrentThresholdValue(const std::string& organName, const Color& color); virtual void CancelThresholding(); protected: BinaryThresholdTool(); // purposely hidden virtual ~BinaryThresholdTool(); void SetupPreviewNodeFor( DataNode* nodeForThresholding ); void CreateNewSegmentationFromThreshold(DataNode* node, const std::string& organType, const Color& color); void OnRoiDataChanged(); template void ITKThresholding( itk::Image* originalImage, mitk::Image* segmentation, unsigned int timeStep ); DataNode::Pointer m_ThresholdFeedbackNode; DataNode::Pointer m_OriginalImageNode; DataNode::Pointer m_NodeForThresholding; int m_SensibleMinimumThresholdValue; int m_SensibleMaximumThresholdValue; int m_CurrentThresholdValue; + bool m_IsFloatImage; }; } // namespace #endif diff --git a/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.cpp b/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.cpp index 1f928d3f46..03f74ba655 100644 --- a/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.cpp +++ b/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.cpp @@ -1,147 +1,148 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.12 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkBinaryThresholdToolGUI.h" #include "QmitkNewSegmentationDialog.h" #include #include #include #include MITK_TOOL_GUI_MACRO(QmitkExt_EXPORT, QmitkBinaryThresholdToolGUI, "") QmitkBinaryThresholdToolGUI::QmitkBinaryThresholdToolGUI() :QmitkToolGUI(), m_Slider(NULL), m_Spinner(NULL) { // create the visible widgets QBoxLayout* mainLayout = new QVBoxLayout(this); QLabel* label = new QLabel( "Threshold :", this ); QFont f = label->font(); f.setBold(false); label->setFont( f ); mainLayout->addWidget(label); QBoxLayout* layout = new QHBoxLayout(); m_Spinner = new QSpinBox(); m_Spinner->setMaximum(20); m_Spinner->setMinimum(5); m_Spinner->setValue(1); connect(m_Spinner, SIGNAL(editingFinished()), this, SLOT(OnSpinnerValueChanged()) ); layout->addWidget(m_Spinner); //m_Slider = new QSlider( 5, 20, 1, 1, Qt::Horizontal, this ); m_Slider = new QSlider( Qt::Horizontal, this ); m_Slider->setMinimum(5); m_Slider->setMaximum(20); m_Slider->setPageStep(1); m_Slider->setValue(1); connect( m_Slider, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); layout->addWidget( m_Slider ); QPushButton* okButton = new QPushButton("Ok", this); connect( okButton, SIGNAL(clicked()), this, SLOT(OnAcceptThresholdPreview())); okButton->setFont( f ); layout->addWidget( okButton ); mainLayout->addLayout(layout); connect( this, SIGNAL(NewToolAssociated(mitk::Tool*)), this, SLOT(OnNewToolAssociated(mitk::Tool*)) ); } QmitkBinaryThresholdToolGUI::~QmitkBinaryThresholdToolGUI() { // !!! if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged ); m_BinaryThresholdTool->ThresholdingValueChanged -= mitk::MessageDelegate1( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged ); } } void QmitkBinaryThresholdToolGUI::OnNewToolAssociated(mitk::Tool* tool) { if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged -= mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged ); m_BinaryThresholdTool->ThresholdingValueChanged -= mitk::MessageDelegate1( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged ); } m_BinaryThresholdTool = dynamic_cast( tool ); if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->IntervalBordersChanged += mitk::MessageDelegate2( this, &QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged ); m_BinaryThresholdTool->ThresholdingValueChanged += mitk::MessageDelegate1( this, &QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged ); } } void QmitkBinaryThresholdToolGUI::OnSliderValueChanged(int value) { if (m_BinaryThresholdTool.IsNotNull()) { m_BinaryThresholdTool->SetThresholdValue( value ); } m_Spinner->setValue(value); } + void QmitkBinaryThresholdToolGUI::OnAcceptThresholdPreview() { if (m_BinaryThresholdTool.IsNotNull()) { QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog( this ); // needs a QWidget as parent, "this" is not QWidget dialog->setPrompt("What did you just segment?"); int dialogReturnValue = dialog->exec(); std::string organName = dialog->GetSegmentationName().toStdString(); mitk::Color color = dialog->GetColor(); delete dialog; if ( dialogReturnValue != QDialog::Rejected ) // user clicked cancel or pressed Esc or something similar { m_BinaryThresholdTool->AcceptCurrentThresholdValue( organName, color ); } else { m_BinaryThresholdTool->CancelThresholding(); } } } void QmitkBinaryThresholdToolGUI::OnThresholdingIntervalBordersChanged(int lower, int upper) { m_Slider->setRange(lower, upper); m_Spinner->setRange(lower, upper); } void QmitkBinaryThresholdToolGUI::OnThresholdingValueChanged(int current) { m_Slider->setValue(current); m_Spinner->setValue(current); } void QmitkBinaryThresholdToolGUI::OnSpinnerValueChanged() { m_Slider->setValue(m_Spinner->value()); } diff --git a/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.h b/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.h index f975cb5214..b59c56aca2 100644 --- a/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.h +++ b/Modules/QmitkExt/QmitkBinaryThresholdToolGUI.h @@ -1,70 +1,72 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 1.0 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QmitkBinaryThresholdToolGUI_h_Included #define QmitkBinaryThresholdToolGUI_h_Included #include "QmitkToolGUI.h" #include "QmitkExtExports.h" #include "mitkBinaryThresholdTool.h" #include class QSlider; /** \ingroup org_mitk_gui_qt_interactivesegmentation_internal \brief GUI for mitk::BinaryThresholdTool. This GUI shows a slider to change the tool's threshold and an OK button to accept a preview for actual thresholding. Last contributor: $Author$ */ class QmitkExt_EXPORT QmitkBinaryThresholdToolGUI : public QmitkToolGUI { Q_OBJECT public: mitkClassMacro(QmitkBinaryThresholdToolGUI, QmitkToolGUI); itkNewMacro(QmitkBinaryThresholdToolGUI); void OnThresholdingIntervalBordersChanged(int lower, int upper); void OnThresholdingValueChanged(int current); + void OnThresholdingIntervalBordersChanged(double lower, double upper); + void OnThresholdingValueChanged(double current); signals: public slots: protected slots: void OnNewToolAssociated(mitk::Tool*); void OnSliderValueChanged(int value); void OnAcceptThresholdPreview(); void OnSpinnerValueChanged(); protected: QmitkBinaryThresholdToolGUI(); virtual ~QmitkBinaryThresholdToolGUI(); QSlider* m_Slider; QSpinBox* m_Spinner; mitk::BinaryThresholdTool::Pointer m_BinaryThresholdTool; }; #endif