diff --git a/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/QmitkRegionGrowingView.cpp b/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/QmitkRegionGrowingView.cpp index fffa1b147c..e519b2108a 100644 --- a/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/QmitkRegionGrowingView.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.regiongrowing/src/internal/QmitkRegionGrowingView.cpp @@ -1,266 +1,267 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 17495 $ 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. =========================================================================*/ // Blueberry #include #include // MITK #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkProperties.h" #include "mitkColorProperty.h" #include "mitkImageTimeSelector.h" // Qmitk #include "QmitkRegionGrowingView.h" #include "QmitkPointListWidget.h" #include "QmitkStdMultiWidget.h" // Qt #include // ITK #include const std::string QmitkRegionGrowingView::VIEW_ID = "org.mitk.views.regiongrowing"; QmitkRegionGrowingView::QmitkRegionGrowingView() : QmitkFunctionality() , m_Controls( 0 ) , m_MultiWidget( NULL ) { } QmitkRegionGrowingView::QmitkRegionGrowingView(const QmitkRegionGrowingView& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } QmitkRegionGrowingView::~QmitkRegionGrowingView() { } void QmitkRegionGrowingView::Deactivated() { m_Controls->lstPoints->DeactivateInteractor(true); } void QmitkRegionGrowingView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkRegionGrowingViewControls; m_Controls->setupUi( parent ); connect( m_Controls->btnPerformImageProcessing, SIGNAL(clicked()), this, SLOT(DoImageProcessing()) ); // let the point set widget know about the multi widget (crosshair updates) m_Controls->lstPoints->SetMultiWidget( m_MultiWidget ); // create a new DataNode containing a PointSet with some interaction m_PointSet = mitk::PointSet::New(); mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New(); pointSetNode->SetData( m_PointSet ); pointSetNode->SetName("seed points for region growing"); pointSetNode->SetProperty("helper object", mitk::BoolProperty::New(true) ); pointSetNode->SetProperty("layer", mitk::IntProperty::New(1024) ); // add the pointset to the data tree (for rendering and access by other modules) GetDefaultDataStorage()->Add( pointSetNode ); // tell the GUI widget about out point set m_Controls->lstPoints->SetPointSetNode( pointSetNode ); } } void QmitkRegionGrowingView::StdMultiWidgetAvailable (QmitkStdMultiWidget &stdMultiWidget) { m_MultiWidget = &stdMultiWidget; m_Controls->lstPoints->SetMultiWidget( m_MultiWidget ); } void QmitkRegionGrowingView::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; m_Controls->lstPoints->SetMultiWidget( NULL ); } void QmitkRegionGrowingView::OnSelectionChanged( std::vector nodes ) { // iterate all selected objects, adjust warning visibility for( std::vector::iterator it = nodes.begin(); it != nodes.end(); ++it ) { mitk::DataNode::Pointer node = *it; if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { m_Controls->lblWarning->setVisible( false ); return; } } m_Controls->lblWarning->setVisible( true ); } void QmitkRegionGrowingView::DoImageProcessing() { std::vector nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode* node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, "Region growing functionality", "Please load and select an image before region growing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; } message << "."; MITK_INFO << message.str(); // So we have an image. Get the current time step to see if the user has set some seed points already unsigned int t = m_MultiWidget->GetTimeNavigationController()->GetTime()->GetPos(); if ( m_PointSet->GetSize(t) == 0 ) { // no points there. Not good for region growing QMessageBox::information( NULL, "Region growing functionality", "Please set some seed points inside the image first.\n" "(hold Shift key and click left mouse button inside the image.)" ); return; } // actually perform region growing. Here we have both an image and some seed points if (image->GetDimension() == 4) { mitk::ImageTimeSelector::Pointer timeSelector = mitk::ImageTimeSelector::New(); timeSelector->SetInput(image); timeSelector->SetTimeNr(t); timeSelector->UpdateLargestPossibleRegion(); mitk::Image::Pointer image3D = timeSelector->GetOutput(); AccessByItk_n(image3D, ItkImageProcessing, (image3D->GetGeometry(), node, m_Controls->sliderOffsetValue->value(), t)); } else { AccessByItk_n(image, ItkImageProcessing, (image->GetGeometry(), node, m_Controls->sliderOffsetValue->value(), t)); // some magic to call the correctly templated function } } } } template < typename TPixel, unsigned int VImageDimension > void QmitkRegionGrowingView::ItkImageProcessing( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Geometry3D* imageGeometry, mitk::DataNode* parent, int thresholdOffset, unsigned int t) { - typedef itk::Image< TPixel, VImageDimension > InputImageType; - typedef typename InputImageType::IndexType IndexType; + typedef itk::Image< TPixel, VImageDimension > InputImageType; + typedef typename InputImageType::IndexType IndexType; + typedef itk::Image< unsigned char, VImageDimension > OutputImageType; // instantiate an ITK region growing filter, set its parameters - typedef itk::ConnectedThresholdImageFilter RegionGrowingFilterType; + typedef itk::ConnectedThresholdImageFilter RegionGrowingFilterType; typename RegionGrowingFilterType::Pointer regionGrower = RegionGrowingFilterType::New(); regionGrower->SetInput( itkImage ); // don't forget this // determine a thresholding interval IndexType seedIndex; TPixel min( std::numeric_limits::max() ); TPixel max( std::numeric_limits::min() ); mitk::PointSet::PointsContainer* points = m_PointSet->GetPointSet(t)->GetPoints(); for ( mitk::PointSet::PointsConstIterator pointsIterator = points->Begin(); pointsIterator != points->End(); ++pointsIterator ) { // first test if this point is inside the image at all if ( !imageGeometry->IsInside( pointsIterator.Value()) ) { continue; } // convert world coordinates to image indices imageGeometry->WorldToIndex( pointsIterator.Value(), seedIndex); // get the pixel value at this point TPixel currentPixelValue = itkImage->GetPixel( seedIndex ); // adjust minimum and maximum values if (currentPixelValue > max) max = currentPixelValue; if (currentPixelValue < min) min = currentPixelValue; regionGrower->AddSeed( seedIndex ); } std::cout << "Values between " << min << " and " << max << std::endl; min -= thresholdOffset; max += thresholdOffset; // set thresholds and execute filter regionGrower->SetLower( min ); regionGrower->SetUpper( max ); regionGrower->Update(); mitk::Image::Pointer resultImage = mitk::ImportItkImage( regionGrower->GetOutput() ); mitk::DataNode::Pointer newNode = mitk::DataNode::New(); newNode->SetData( resultImage ); // set some properties newNode->SetProperty("binary", mitk::BoolProperty::New(true)); newNode->SetProperty("name", mitk::StringProperty::New("dumb segmentation")); newNode->SetProperty("color", mitk::ColorProperty::New(1.0,0.0,0.0)); newNode->SetProperty("volumerendering", mitk::BoolProperty::New(false)); newNode->SetProperty("layer", mitk::IntProperty::New(1)); newNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); // add result to data tree this->GetDefaultDataStorage()->Add( newNode, parent ); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } diff --git a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp index c5e04c0193..3dbd1d1580 100644 --- a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.cpp @@ -1,120 +1,172 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 18019 $ 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 "QmitkSegmentationPreferencePage.h" #include #include #include #include #include #include #include +#include #include #include QmitkSegmentationPreferencePage::QmitkSegmentationPreferencePage() : m_MainControl(0) , m_Initializing(false) { } QmitkSegmentationPreferencePage::~QmitkSegmentationPreferencePage() { } void QmitkSegmentationPreferencePage::Init(berry::IWorkbench::Pointer ) { } void QmitkSegmentationPreferencePage::CreateQtControl(QWidget* parent) { m_Initializing = true; berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry() .GetServiceById(berry::IPreferencesService::ID); m_SegmentationPreferencesNode = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); m_MainControl = new QWidget(parent); QVBoxLayout* displayOptionsLayout = new QVBoxLayout; m_RadioOutline = new QRadioButton( "Draw as outline", m_MainControl); displayOptionsLayout->addWidget( m_RadioOutline ); m_RadioOverlay = new QRadioButton( "Draw as transparent overlay", m_MainControl); displayOptionsLayout->addWidget( m_RadioOverlay ); QFormLayout *formLayout = new QFormLayout; + formLayout->setHorizontalSpacing(8); + formLayout->setVerticalSpacing(24); formLayout->addRow( "2D display", displayOptionsLayout ); m_VolumeRenderingCheckBox = new QCheckBox( "Show as volume rendering", m_MainControl ); formLayout->addRow( "3D display", m_VolumeRenderingCheckBox ); connect( m_VolumeRenderingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnVolumeRenderingCheckboxChecked(int)) ); + + QFormLayout* surfaceLayout = new QFormLayout; + surfaceLayout->setSpacing(8); + + m_SmoothingCheckBox = new QCheckBox("Use image spacing as smoothing value hint", m_MainControl); + surfaceLayout->addRow(m_SmoothingCheckBox); + connect(m_SmoothingCheckBox, SIGNAL(stateChanged(int)), this, SLOT(OnSmoothingCheckboxChecked(int))); + + m_SmoothingSpinBox = new QDoubleSpinBox(m_MainControl); + m_SmoothingSpinBox->setMinimum(0.0); + m_SmoothingSpinBox->setSingleStep(0.5); + m_SmoothingSpinBox->setValue(1.0); + m_SmoothingSpinBox->setToolTip("The Smoothing value is used as variance for a gaussian blur."); + surfaceLayout->addRow("Smoothing value (mm)", m_SmoothingSpinBox); + + m_DecimationSpinBox = new QDoubleSpinBox(m_MainControl); + m_DecimationSpinBox->setMinimum(0.0); + m_DecimationSpinBox->setMaximum(0.99); + m_DecimationSpinBox->setSingleStep(0.1); + m_DecimationSpinBox->setValue(0.5); + m_DecimationSpinBox->setToolTip("Valid range is [0, 1). High values increase decimation, especially when very close to 1. A value of 0 disables decimation."); + surfaceLayout->addRow("Decimation rate", m_DecimationSpinBox); + + formLayout->addRow("Smoothed surface creation", surfaceLayout); m_MainControl->setLayout(formLayout); this->Update(); m_Initializing = false; } QWidget* QmitkSegmentationPreferencePage::GetQtControl() const { return m_MainControl; } bool QmitkSegmentationPreferencePage::PerformOk() { m_SegmentationPreferencesNode->PutBool("draw outline", m_RadioOutline->isChecked()); m_SegmentationPreferencesNode->PutBool("volume rendering", m_VolumeRenderingCheckBox->isChecked()); + m_SegmentationPreferencesNode->PutBool("smoothing hint", m_SmoothingCheckBox->isChecked()); + m_SegmentationPreferencesNode->PutDouble("smoothing value", m_SmoothingSpinBox->value()); + m_SegmentationPreferencesNode->PutDouble("decimation rate", m_DecimationSpinBox->value()); return true; } void QmitkSegmentationPreferencePage::PerformCancel() { } void QmitkSegmentationPreferencePage::Update() { //m_EnableSingleEditing->setChecked(m_SegmentationPreferencesNode->GetBool("Single click property editing", true)); if (m_SegmentationPreferencesNode->GetBool("draw outline", true) ) { m_RadioOutline->setChecked( true ); } else { m_RadioOverlay->setChecked( true ); } m_VolumeRenderingCheckBox->setChecked( m_SegmentationPreferencesNode->GetBool("volume rendering", false) ); + + if (m_SegmentationPreferencesNode->GetBool("smoothing hint", true)) + { + m_SmoothingCheckBox->setChecked(true); + m_SmoothingSpinBox->setDisabled(true); + } + else + { + m_SmoothingCheckBox->setChecked(false); + m_SmoothingSpinBox->setEnabled(true); + } + + m_SmoothingSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("smoothing value", 1.0)); + m_DecimationSpinBox->setValue(m_SegmentationPreferencesNode->GetDouble("decimation rate", 0.5)); } void QmitkSegmentationPreferencePage::OnVolumeRenderingCheckboxChecked(int state) { if (m_Initializing) return; if ( state != Qt::Unchecked ) { QMessageBox::information(NULL, "Memory warning", "Turning on volume rendering of segmentations will make the application more memory intensive (and potentially prone to crashes).\n\n" "If you encounter out-of-memory problems, try turning off volume rendering again."); } } + +void QmitkSegmentationPreferencePage::OnSmoothingCheckboxChecked(int state) +{ + if (state != Qt::Unchecked) + m_SmoothingSpinBox->setDisabled(true); + else + m_SmoothingSpinBox->setEnabled(true); +} diff --git a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h index ad3443be2b..234d26a88d 100644 --- a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h +++ b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/QmitkSegmentationPreferencePage.h @@ -1,83 +1,88 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 16224 $ 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 QmitkSegmentationPreferencePage_h_included #define QmitkSegmentationPreferencePage_h_included #include "berryIQtPreferencePage.h" #include "org_mitk_gui_qt_segmentation_Export.h" #include class QWidget; class QCheckBox; class QRadioButton; +class QDoubleSpinBox; class MITK_QT_SEGMENTATION QmitkSegmentationPreferencePage : public QObject, public berry::IQtPreferencePage { Q_OBJECT Q_INTERFACES(berry::IPreferencePage) public: QmitkSegmentationPreferencePage(); QmitkSegmentationPreferencePage(const QmitkSegmentationPreferencePage& other) { Q_UNUSED(other) throw std::runtime_error("Copy constructor not implemented"); } ~QmitkSegmentationPreferencePage(); void Init(berry::IWorkbench::Pointer workbench); void CreateQtControl(QWidget* widget); QWidget* GetQtControl() const; /// /// \see IPreferencePage::PerformOk() /// virtual bool PerformOk(); /// /// \see IPreferencePage::PerformCancel() /// virtual void PerformCancel(); /// /// \see IPreferencePage::Update() /// virtual void Update(); protected slots: void OnVolumeRenderingCheckboxChecked(int); + void OnSmoothingCheckboxChecked(int); protected: QWidget* m_MainControl; QRadioButton* m_RadioOutline; QRadioButton* m_RadioOverlay; QCheckBox* m_VolumeRenderingCheckBox; + QCheckBox* m_SmoothingCheckBox; + QDoubleSpinBox* m_SmoothingSpinBox; + QDoubleSpinBox* m_DecimationSpinBox; bool m_Initializing; berry::IPreferences::Pointer m_SegmentationPreferencesNode; }; #endif /* QMITKDATAMANAGERPREFERENCEPAGE_H_ */ diff --git a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp index 4f7eb3e927..e4e2f132b5 100644 --- a/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp @@ -1,107 +1,160 @@ #include "QmitkCreatePolygonModelAction.h" +#include "mitkShowSegmentationAsSmoothedSurface.h" #include "mitkShowSegmentationAsSurface.h" #include "mitkProgressBar.h" #include "mitkStatusBar.h" +#include +#include + QmitkCreatePolygonModelAction::QmitkCreatePolygonModelAction() { } QmitkCreatePolygonModelAction::~QmitkCreatePolygonModelAction() { } void QmitkCreatePolygonModelAction::Run(const std::vector& selectedNodes) { NodeList selection = selectedNodes; for ( NodeList::iterator iter = selection.begin(); iter != selection.end(); ++iter ) { mitk::DataNode* node = *iter; if (node) { mitk::Image::Pointer image = dynamic_cast( node->GetData() ); if (image.IsNull()) return; try { - mitk::ShowSegmentationAsSurface::Pointer surfaceFilter = mitk::ShowSegmentationAsSurface::New(); - - // attach observer to get notified about result - itk::SimpleMemberCommand::Pointer goodCommand = itk::SimpleMemberCommand::New(); - goodCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); - surfaceFilter->AddObserver(mitk::ResultAvailable(), goodCommand); - itk::SimpleMemberCommand::Pointer badCommand = itk::SimpleMemberCommand::New(); - badCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); - surfaceFilter->AddObserver(mitk::ProcessingError(), badCommand); - - mitk::DataNode::Pointer nodepointer = node; - surfaceFilter->SetPointerParameter("Input", image); - surfaceFilter->SetPointerParameter("Group node", nodepointer); - surfaceFilter->SetParameter("Show result", true ); - surfaceFilter->SetParameter("Sync visibility", false ); - surfaceFilter->SetDataStorage( *m_DataStorage ); - - if (this->m_IsSmoothed) + if (!m_IsSmoothed) { - surfaceFilter->SetParameter("Smooth", true ); - //surfaceFilter->SetParameter("Apply median", true ); - surfaceFilter->SetParameter("Apply median", false ); // median makes the resulting surfaces look like lego models - surfaceFilter->SetParameter("Median kernel size", 3u ); - surfaceFilter->SetParameter("Gaussian SD", 2.5f ); - surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated ); - surfaceFilter->SetParameter("Decimation rate", 0.8f ); + mitk::ShowSegmentationAsSurface::Pointer surfaceFilter = mitk::ShowSegmentationAsSurface::New(); + + // attach observer to get notified about result + itk::SimpleMemberCommand::Pointer goodCommand = itk::SimpleMemberCommand::New(); + goodCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); + surfaceFilter->AddObserver(mitk::ResultAvailable(), goodCommand); + itk::SimpleMemberCommand::Pointer badCommand = itk::SimpleMemberCommand::New(); + badCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); + surfaceFilter->AddObserver(mitk::ProcessingError(), badCommand); + + mitk::DataNode::Pointer nodepointer = node; + surfaceFilter->SetPointerParameter("Input", image); + surfaceFilter->SetPointerParameter("Group node", nodepointer); + surfaceFilter->SetParameter("Show result", true ); + surfaceFilter->SetParameter("Sync visibility", false ); + surfaceFilter->SetDataStorage( *m_DataStorage ); + + /*if (this->m_IsSmoothed) + { + surfaceFilter->SetParameter("Smooth", true ); + //surfaceFilter->SetParameter("Apply median", true ); + surfaceFilter->SetParameter("Apply median", false ); // median makes the resulting surfaces look like lego models + surfaceFilter->SetParameter("Median kernel size", 3u ); + surfaceFilter->SetParameter("Gaussian SD", 2.5f ); + surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated ); + surfaceFilter->SetParameter("Decimation rate", 0.8f ); + } + else + {*/ + surfaceFilter->SetParameter("Smooth", false ); + surfaceFilter->SetParameter("Apply median", false ); + surfaceFilter->SetParameter("Median kernel size", 3u ); + surfaceFilter->SetParameter("Gaussian SD", 1.5f ); + surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated ); + surfaceFilter->SetParameter("Decimation rate", 0.8f ); + //} + + mitk::ProgressBar::GetInstance()->AddStepsToDo(10); + mitk::ProgressBar::GetInstance()->Progress(2); + mitk::StatusBar::GetInstance()->DisplayText("Surface creation started in background..."); + surfaceFilter->StartAlgorithm(); } else { - surfaceFilter->SetParameter("Smooth", false ); - surfaceFilter->SetParameter("Apply median", false ); - surfaceFilter->SetParameter("Median kernel size", 3u ); - surfaceFilter->SetParameter("Gaussian SD", 1.5f ); - surfaceFilter->SetParameter("Decimate mesh", m_IsDecimated ); - surfaceFilter->SetParameter("Decimation rate", 0.8f ); + mitk::ShowSegmentationAsSmoothedSurface::Pointer filter = mitk::ShowSegmentationAsSmoothedSurface::New(); + + itk::SimpleMemberCommand::Pointer goodCommand = itk::SimpleMemberCommand::New(); + goodCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); + filter->AddObserver(mitk::ResultAvailable(), goodCommand); + + itk::SimpleMemberCommand::Pointer badCommand = itk::SimpleMemberCommand::New(); + badCommand->SetCallbackFunction(this, &QmitkCreatePolygonModelAction::OnSurfaceCalculationDone); + filter->AddObserver(mitk::ProcessingError(), badCommand); + + mitk::DataNode::Pointer nodepointer = node; + filter->SetPointerParameter("Input", image); + filter->SetPointerParameter("Group node", nodepointer); + filter->SetDataStorage(*m_DataStorage); + + berry::IPreferencesService::Pointer prefService = berry::Platform::GetServiceRegistry().GetServiceById(berry::IPreferencesService::ID); + berry::IPreferences::Pointer segPref = prefService->GetSystemPreferences()->Node("/org.mitk.views.segmentation"); + + bool smoothingHint = segPref->GetBool("smoothing hint", true); + float smoothing = (float)segPref->GetDouble("smoothing value", 1.0); + float decimation = (float)segPref->GetDouble("decimation rate", 0.5); + + if (smoothingHint) + { + smoothing = 0.0; + mitk::Vector3D spacing = image->GetGeometry()->GetSpacing(); + + for (mitk::Vector3D::Iterator iter = spacing.Begin(); iter != spacing.End(); ++iter) + smoothing = std::max(smoothing, *iter); + + filter->SetParameter("Smoothing", smoothing); + } + else + { + filter->SetParameter("Smoothing", smoothing); + } + + filter->SetParameter("Decimation", decimation); + + mitk::ProgressBar::GetInstance()->AddStepsToDo(8); + mitk::StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background..."); + + filter->StartAlgorithm(); } - - mitk::ProgressBar::GetInstance()->AddStepsToDo(10); - mitk::ProgressBar::GetInstance()->Progress(2); - mitk::StatusBar::GetInstance()->DisplayText("Surface creation started in background..."); - surfaceFilter->StartAlgorithm(); } catch(...) { MITK_ERROR << "surface creation filter had an error"; } } else { MITK_INFO << " a NULL node selected"; } } } void QmitkCreatePolygonModelAction::OnSurfaceCalculationDone() { mitk::ProgressBar::GetInstance()->Progress(8); } void QmitkCreatePolygonModelAction::SetSmoothed(bool smoothed) { this->m_IsSmoothed = smoothed; } void QmitkCreatePolygonModelAction::SetDecimated(bool decimated) { this->m_IsDecimated = decimated; } void QmitkCreatePolygonModelAction::SetDataStorage(mitk::DataStorage* dataStorage) { this->m_DataStorage = dataStorage; } void QmitkCreatePolygonModelAction::SetFunctionality(berry::QtViewPart *functionality) { //not needed } diff --git a/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.h b/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.h new file mode 100644 index 0000000000..84254142b3 --- /dev/null +++ b/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.h @@ -0,0 +1,139 @@ +#ifndef __itkIntelligentBinaryClosingFilter_h +#define __itkIntelligentBinaryClosingFilter_h + + +#if defined(_MSC_VER) +#pragma warning ( disable : 4786 ) +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + + +namespace itk +{ +/** \class itkIntelligentBinaryClosingFilter + * WARNING: This filtezr needs at least ITK version 3.2 + * or above to run and compile!!! + * */ + + +template +class ITK_EXPORT IntelligentBinaryClosingFilter : + public ImageToImageFilter< TInputImage, TOutputImage > +{ + +public: + /** Standard "Self" typedef. */ + typedef IntelligentBinaryClosingFilter Self; + + /** The type of input image. */ + typedef TInputImage InputImageType; + + /** Dimension of the input and output images. */ + itkStaticConstMacro (ImageDimension, unsigned int, + TInputImage::ImageDimension); + + /** The type of output image. */ + typedef TOutputImage OutputImageType; + + /** Standard super class typedef support. */ + typedef ImageToImageFilter< InputImageType, OutputImageType > Superclass; + + /** Smart pointer typedef support */ + typedef SmartPointer Pointer; + + /** Run-time type information (and related methods) */ + itkTypeMacro(IntelligentBinaryClosingFilter, ImageToImageFilter); + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Standard process object method. This filter is not multithreaded. */ + void GenerateData(); + + /** Overloaded to link the input to this filter with the input of the + mini-pipeline */ + void SetInput(const InputImageType *input) + { + // processObject is not const-correct so a const_cast is needed here + this->ProcessObject::SetNthInput(0, + const_cast( input ) ); + m_DilateImageFilter->SetInput( const_cast( input ) ); + } + + virtual void SetInput( unsigned int i, const TInputImage * image) + { + if (i != 0) + { itkExceptionMacro(<< "Filter has only one input."); } + else + { this->SetInput(image); } + } + + itkGetMacro( ClosingRadius, float ); + itkSetMacro( ClosingRadius, float ); + + itkGetMacro( SurfaceRatio, float ); + itkSetMacro( SurfaceRatio, float ); + + +protected: + + IntelligentBinaryClosingFilter(); + virtual ~IntelligentBinaryClosingFilter() {} + IntelligentBinaryClosingFilter(const Self&) {} + void operator=(const Self&) {} + void PrintSelf(std::ostream& os, Indent indent) const; + + +private: + + typedef typename InputImageType::PixelType InputPixelType; + typedef BinaryBallStructuringElement + StructuringElementType; + typedef BinaryErodeImageFilter + BinaryErodeImageFilterType; + typedef BinaryDilateImageFilter + BinaryDilateImageFilterType; + typedef SubtractImageFilter + SubtractImageFilterType; + typedef ConnectedComponentImageFilter + ConnectedComponentImageFilterType; + typedef RelabelComponentImageFilter + RelabelComponentImageFilterType; + typedef GrayscaleDilateImageFilter + DilateComponentImageFilterType; + typedef ImageRegionIterator InputIteratorType; + typedef ImageRegionConstIterator ConstInputIteratorType; + typedef ImageRegionIterator OutputIteratorType; + + typename BinaryErodeImageFilterType::Pointer m_ErodeImageFilter; + typename BinaryDilateImageFilterType::Pointer m_DilateImageFilter; + typename SubtractImageFilterType::Pointer m_SubtractImageFilter; + typename ConnectedComponentImageFilterType::Pointer m_ConnectedComponentImageFilter; + typename RelabelComponentImageFilterType::Pointer m_RelabelComponentImageFilter; + typename DilateComponentImageFilterType::Pointer m_BorderDetectionDilateFilter; + //typename BinaryDilateImageFilterType::Pointer m_BorderAdjacencyDilateFilter; + float m_ClosingRadius; + float m_SurfaceRatio; + +}; + +} // end namespace itk + + +#ifndef ITK_MANUAL_INSTANTIATION +#include "itkIntelligentBinaryClosingFilter.txx" + +#endif + +#endif //IntelligentBinaryClosingFilter_h diff --git a/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.txx b/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.txx new file mode 100644 index 0000000000..8a121a31ac --- /dev/null +++ b/Modules/MitkExt/Algorithms/itkIntelligentBinaryClosingFilter.txx @@ -0,0 +1,134 @@ +#ifndef _itkIntelligentBinaryClosingFilter_txx +#define _itkIntelligentBinaryClosingFilter_txx + +#include "itkIntelligentBinaryClosingFilter.h" +#include + +namespace itk +{ + +template< class TInputImage, class TOutputImage > +IntelligentBinaryClosingFilter ::IntelligentBinaryClosingFilter() +{ + m_ErodeImageFilter = BinaryErodeImageFilterType::New(); + m_DilateImageFilter = BinaryDilateImageFilterType::New(); + m_SubtractImageFilter = SubtractImageFilterType::New(); + m_ConnectedComponentImageFilter = ConnectedComponentImageFilterType::New(); + m_RelabelComponentImageFilter = RelabelComponentImageFilterType::New(); + m_RelabelComponentImageFilter->SetInPlace( true ); + m_BorderDetectionDilateFilter = DilateComponentImageFilterType::New(); + m_ClosingRadius = 4.0; + m_SurfaceRatio = 70; +} + + +template< class TInputImage, class TOutputImage > +void IntelligentBinaryClosingFilter::GenerateData() +{ + const InputImageType *input = this->GetInput(); + // Allocate the output image. + typename OutputImageType::Pointer output = this->GetOutput(); + output->SetRequestedRegion( input->GetRequestedRegion() ); + output->SetBufferedRegion( input->GetBufferedRegion() ); + output->SetLargestPossibleRegion( input->GetLargestPossibleRegion() ); + output->Allocate(); + + // set up structuring element for closing + StructuringElementType seClosing; + unsigned long radius[ImageDimension]; + const typename InputImageType::SpacingType spacing = input->GetSpacing(); + for (unsigned int d=0; dSetInput( this->GetInput() ); + m_DilateImageFilter->SetKernel( seClosing ); + m_DilateImageFilter->SetDilateValue( 1 ); + m_ErodeImageFilter->SetInput( m_DilateImageFilter->GetOutput() ); + m_ErodeImageFilter->SetKernel( seClosing ); + m_ErodeImageFilter->SetErodeValue( 1 ); + + // subtraction + m_SubtractImageFilter->SetInput1( m_ErodeImageFilter->GetOutput() ); + m_SubtractImageFilter->SetInput2( this->GetInput() ); + + // connected components + m_ConnectedComponentImageFilter->SetInput( m_SubtractImageFilter->GetOutput() ); + m_RelabelComponentImageFilter->SetInput( m_ConnectedComponentImageFilter->GetOutput() ); + m_RelabelComponentImageFilter->Update(); + + // set up structuring element for border voxel detection + StructuringElementType seBorder; + for (unsigned int d=0; dSetInput( m_RelabelComponentImageFilter->GetOutput() ); + m_BorderDetectionDilateFilter->SetKernel( seBorder ); + m_BorderDetectionDilateFilter->Update(); + + // count volumes and border voxels for all components + OutputIteratorType itComp( m_RelabelComponentImageFilter->GetOutput(), + m_RelabelComponentImageFilter->GetOutput()->GetLargestPossibleRegion() ); + OutputIteratorType itBorder( m_BorderDetectionDilateFilter->GetOutput(), + m_BorderDetectionDilateFilter->GetOutput()->GetLargestPossibleRegion() ); + ConstInputIteratorType itIn( input, input->GetLargestPossibleRegion() ); + + std::vector volume( m_RelabelComponentImageFilter->GetNumberOfObjects()+1, 0 ); + std::vector border( m_RelabelComponentImageFilter->GetNumberOfObjects()+1, 0 ); + std::vector adjacent( m_RelabelComponentImageFilter->GetNumberOfObjects()+1, 0 ); + typename OutputImageType::ValueType borderId, compId; + for (itComp.GoToBegin(), itBorder.GoToBegin(), itIn.GoToBegin(); !itComp.IsAtEnd(); ++itComp, ++itBorder, ++itIn ) + { + borderId = itBorder.Get(); + if (borderId != 0) { + compId = itComp.Get(); + if (compId != 0) { + volume[compId]++; + } + else { + // this is border country + border[borderId]++; + if (itIn.Get() != 0) adjacent[borderId]++; + } + } + } + + // calculate ratios + std::vector ratio( m_RelabelComponentImageFilter->GetNumberOfObjects()+1, 0 ); + MITK_INFO << " " << m_RelabelComponentImageFilter->GetNumberOfObjects() << " components found" << std::endl; + for (unsigned int i=0; iGetLargestPossibleRegion() ); + for (itOut.GoToBegin(), itIn.GoToBegin(), itComp.GoToBegin(); !itOut.IsAtEnd(); ++itOut, ++itIn, ++itComp ) + { + if (itIn.Get() != 0) { + itOut.Set( 1 ); + } + else { + compId = itComp.Get(); + if (ratio[compId] > m_SurfaceRatio) itOut.Set( 1 ); + else itOut.Set( 0 ); + } + } +} + + +template +void IntelligentBinaryClosingFilter::PrintSelf(std::ostream& os, Indent indent) const +{ + Superclass::PrintSelf(os,indent); +} + +} // end namespace itk + +#endif diff --git a/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp new file mode 100644 index 0000000000..58321d1baa --- /dev/null +++ b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp @@ -0,0 +1,509 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +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 "mitkShowSegmentationAsSmoothedSurface.h" +#include "mitkImageToItk.h" +#include "itkIntelligentBinaryClosingFilter.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace mitk; +using namespace std; + +ShowSegmentationAsSmoothedSurface::ShowSegmentationAsSmoothedSurface() +{ +} + +ShowSegmentationAsSmoothedSurface::~ShowSegmentationAsSmoothedSurface() +{ +} + +void ShowSegmentationAsSmoothedSurface::Initialize(const NonBlockingAlgorithm *other) +{ + Superclass::Initialize(other); + + bool syncVisibility = false; + + if (other != NULL) + other->GetParameter("Sync visibility", syncVisibility); + + SetParameter("Sync visibility", syncVisibility); + SetParameter("Wireframe", false); + + // The Smoothing value is used as variance for a Gauß filter. + // A reasonable default value equals the image spacing in mm. + SetParameter("Smoothing", 1.0f); + + // Valid range for decimation value is [0, 1). High values + // increase decimation, especially when very close to 1. + // A value of 0 disables decimation. + SetParameter("Decimation", 0.5f); +} + +bool ShowSegmentationAsSmoothedSurface::ReadyToRun() +{ + try + { + mitk::Image::Pointer image; + GetPointerParameter("Input", image); + + return image.IsNotNull() && GetGroupNode(); + } + catch (const invalid_argument &) + { + return false; + } +} + +bool ShowSegmentationAsSmoothedSurface::ThreadedUpdateFunction() +{ + Image::Pointer image; + GetPointerParameter("Input", image); + + float smoothing; + GetParameter("Smoothing", smoothing); + + float decimation; + GetParameter("Decimation", decimation); + + MITK_INFO << "CREATING SMOOTHED POLYGON MODEL" << endl; + MITK_INFO << " Smoothing = " << smoothing << endl; + MITK_INFO << " Decimation = " << decimation << endl; + + Geometry3D::Pointer geometry = image->GetGeometry(); + + // Make ITK image out of MITK image + + typedef itk::Image CharImageType; + typedef itk::Image ShortImageType; + typedef itk::Image FloatImageType; + + ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); + + try + { + imageToItkFilter->SetInput(image); + } + catch (const itk::ExceptionObject &e) + { + // Most probably the input image type is wrong. Binary images are expected to be + // >unsigned< char images. + MITK_ERROR << e.GetDescription() << endl; + return false; + } + + imageToItkFilter->Update(); + + CharImageType::Pointer itkImage = imageToItkFilter->GetOutput(); + + // Get bounding box and relabel + + MITK_INFO << "Extracting VOI..." << endl; + + int imageLabel = 1; + bool roiFound = false; + + CharImageType::IndexType minIndex; + minIndex.Fill(numeric_limits::max()); + + CharImageType::IndexType maxIndex; + maxIndex.Fill(numeric_limits::min()); + + itk::ImageRegionIteratorWithIndex iter(itkImage, itkImage->GetLargestPossibleRegion()); + + for (iter.GoToBegin(); !iter.IsAtEnd(); ++iter) + { + if (iter.Get() == imageLabel) + { + roiFound = true; + iter.Set(1); + + CharImageType::IndexType currentIndex = iter.GetIndex(); + + for (unsigned int dim = 0; dim < 3; ++dim) + { + minIndex[dim] = min(currentIndex[dim], minIndex[dim]); + maxIndex[dim] = max(currentIndex[dim], maxIndex[dim]); + } + } + else + { + iter.Set(0); + } + } + + if (!roiFound) + { + ProgressBar::GetInstance()->Progress(10); + MITK_ERROR << "Didn't found segmentation labeled with " << imageLabel << "!" << endl; + return false; + } + + ProgressBar::GetInstance()->Progress(1); + + // Extract and pad bounding box + + typedef itk::RegionOfInterestImageFilter ROIFilterType; + + ROIFilterType::Pointer roiFilter = ROIFilterType::New(); + CharImageType::RegionType region; + CharImageType::SizeType size; + + for (unsigned int dim = 0; dim < 3; ++dim) + { + size[dim] = maxIndex[dim] - minIndex[dim] + 1; + } + + region.SetIndex(minIndex); + region.SetSize(size); + + roiFilter->SetInput(itkImage); + roiFilter->SetRegionOfInterest(region); + roiFilter->ReleaseDataFlagOn(); + roiFilter->ReleaseDataBeforeUpdateFlagOn(); + + typedef itk::ConstantPadImageFilter PadFilterType; + + PadFilterType::Pointer padFilter = PadFilterType::New(); + const PadFilterType::SizeValueType pad[3] = { 10, 10, 10 }; + + padFilter->SetInput(roiFilter->GetOutput()); + padFilter->SetConstant(0); + padFilter->SetPadLowerBound(pad); + padFilter->SetPadUpperBound(pad); + padFilter->ReleaseDataFlagOn(); + padFilter->ReleaseDataBeforeUpdateFlagOn(); + padFilter->Update(); + + CharImageType::Pointer roiImage = padFilter->GetOutput(); + + roiImage->DisconnectPipeline(); + roiFilter = 0; + padFilter = 0; + + // Correct origin of real geometry (changed by cropping and padding) + + typedef AffineGeometryFrame3D::TransformType TransformType; + + TransformType::Pointer transform = TransformType::New(); + TransformType::OutputVectorType translation; + + for (unsigned int dim = 0; dim < 3; ++dim) + translation[dim] = (int)minIndex[dim] - (int)pad[dim]; + + transform->SetIdentity(); + transform->Translate(translation); + geometry->Compose(transform, true); + + ProgressBar::GetInstance()->Progress(1); + + // Median + + MITK_INFO << "Median..." << endl; + + typedef itk::BinaryMedianImageFilter MedianFilterType; + + MedianFilterType::Pointer medianFilter = MedianFilterType::New(); + CharImageType::SizeType radius = { 1, 1, 1 }; + + medianFilter->SetRadius(radius); + medianFilter->SetBackgroundValue(0); + medianFilter->SetForegroundValue(1); + medianFilter->SetInput(roiImage); + medianFilter->ReleaseDataFlagOn(); + medianFilter->ReleaseDataBeforeUpdateFlagOn(); + medianFilter->Update(); + + ProgressBar::GetInstance()->Progress(1); + + // Intelligent closing + + MITK_INFO << "Intelligent closing..." << endl; + + unsigned int surfaceRatio = 70; + + typedef itk::IntelligentBinaryClosingFilter ClosingFilterType; + + ClosingFilterType::Pointer closingFilter = ClosingFilterType::New(); + + closingFilter->SetInput(medianFilter->GetOutput()); + closingFilter->ReleaseDataFlagOn(); + closingFilter->ReleaseDataBeforeUpdateFlagOn(); + closingFilter->SetSurfaceRatio(surfaceRatio); + closingFilter->Update(); + + ShortImageType::Pointer closedImage = closingFilter->GetOutput(); + + closedImage->DisconnectPipeline(); + roiImage = 0; + medianFilter = 0; + closingFilter = 0; + + ProgressBar::GetInstance()->Progress(1); + + // Gaussian blur + + MITK_INFO << "Gauss..." << endl; + + typedef itk::BinaryThresholdImageFilter BinaryThresholdToFloatFilterType; + + BinaryThresholdToFloatFilterType::Pointer binThresToFloatFilter = BinaryThresholdToFloatFilterType::New(); + + binThresToFloatFilter->SetInput(closedImage); + binThresToFloatFilter->SetLowerThreshold(1); + binThresToFloatFilter->SetUpperThreshold(1); + binThresToFloatFilter->SetInsideValue(100); + binThresToFloatFilter->SetOutsideValue(0); + binThresToFloatFilter->ReleaseDataFlagOn(); + binThresToFloatFilter->ReleaseDataBeforeUpdateFlagOn(); + + typedef itk::DiscreteGaussianImageFilter GaussianFilterType; + + // From the following line on, IntelliSense (VS 2008) is broken. Any idea how to fix it? + GaussianFilterType::Pointer gaussFilter = GaussianFilterType::New(); + + gaussFilter->SetInput(binThresToFloatFilter->GetOutput()); + gaussFilter->SetUseImageSpacing(true); + gaussFilter->SetVariance(smoothing); + gaussFilter->ReleaseDataFlagOn(); + gaussFilter->ReleaseDataBeforeUpdateFlagOn(); + + typedef itk::BinaryThresholdImageFilter BinaryThresholdFromFloatFilterType; + + BinaryThresholdFromFloatFilterType::Pointer binThresFromFloatFilter = BinaryThresholdFromFloatFilterType::New(); + + binThresFromFloatFilter->SetInput(gaussFilter->GetOutput()); + binThresFromFloatFilter->SetLowerThreshold(50); + binThresFromFloatFilter->SetUpperThreshold(255); + binThresFromFloatFilter->SetInsideValue(1); + binThresFromFloatFilter->SetOutsideValue(0); + binThresFromFloatFilter->ReleaseDataFlagOn(); + binThresFromFloatFilter->ReleaseDataBeforeUpdateFlagOn(); + binThresFromFloatFilter->Update(); + + CharImageType::Pointer blurredImage = binThresFromFloatFilter->GetOutput(); + + blurredImage->DisconnectPipeline(); + closedImage = 0; + binThresToFloatFilter = 0; + gaussFilter = 0; + + ProgressBar::GetInstance()->Progress(1); + + // Fill holes + + MITK_INFO << "Filling cavities..." << endl; + + typedef itk::ConnectedThresholdImageFilter ConnectedThresholdFilterType; + + ConnectedThresholdFilterType::Pointer connectedThresFilter = ConnectedThresholdFilterType::New(); + + CharImageType::IndexType corner; + + corner[0] = 0; + corner[1] = 0; + corner[2] = 0; + + connectedThresFilter->SetInput(blurredImage); + connectedThresFilter->SetSeed(corner); + connectedThresFilter->SetLower(0); + connectedThresFilter->SetUpper(0); + connectedThresFilter->SetReplaceValue(2); + connectedThresFilter->ReleaseDataFlagOn(); + connectedThresFilter->ReleaseDataBeforeUpdateFlagOn(); + + typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; + + BinaryThresholdFilterType::Pointer binThresFilter = BinaryThresholdFilterType::New(); + + binThresFilter->SetInput(connectedThresFilter->GetOutput()); + binThresFilter->SetLowerThreshold(0); + binThresFilter->SetUpperThreshold(0); + binThresFilter->SetInsideValue(50); + binThresFilter->SetOutsideValue(0); + binThresFilter->ReleaseDataFlagOn(); + binThresFilter->ReleaseDataBeforeUpdateFlagOn(); + + typedef itk::AddImageFilter AddFilterType; + + AddFilterType::Pointer addFilter = AddFilterType::New(); + + addFilter->SetInput1(blurredImage); + addFilter->SetInput2(binThresFilter->GetOutput()); + addFilter->ReleaseDataFlagOn(); + addFilter->ReleaseDataBeforeUpdateFlagOn(); + addFilter->Update(); + + ProgressBar::GetInstance()->Progress(1); + + // Surface extraction + + MITK_INFO << "Surface extraction..." << endl; + + Image::Pointer filteredImage = Image::New(); + CastToMitkImage(addFilter->GetOutput(), filteredImage); + + filteredImage->SetGeometry(geometry); + + ImageToSurfaceFilter::Pointer imageToSurfaceFilter = ImageToSurfaceFilter::New(); + + imageToSurfaceFilter->SetInput(filteredImage); + imageToSurfaceFilter->SetThreshold(50); + imageToSurfaceFilter->SmoothOn(); + imageToSurfaceFilter->SetDecimate(ImageToSurfaceFilter::NoDecimation); + + m_Surface = imageToSurfaceFilter->GetOutput(); + + ProgressBar::GetInstance()->Progress(1); + + // Mesh decimation + + if (decimation > 0.0f && decimation < 1.0f) + { + MITK_INFO << "Quadric mesh decimation..." << endl; + + vtkQuadricDecimation *quadricDecimation = vtkQuadricDecimation::New(); + quadricDecimation->SetInput(m_Surface->GetVtkPolyData()); + quadricDecimation->SetTargetReduction(decimation); + quadricDecimation->AttributeErrorMetricOn(); + quadricDecimation->Update(); + + vtkCleanPolyData* cleaner = vtkCleanPolyData::New(); + cleaner->SetInput(quadricDecimation->GetOutput()); + cleaner->PieceInvariantOn(); + cleaner->ConvertLinesToPointsOn(); + cleaner->ConvertStripsToPolysOn(); + cleaner->PointMergingOn(); + cleaner->Update(); + + m_Surface->SetVtkPolyData(cleaner->GetOutput()); + } + + ProgressBar::GetInstance()->Progress(1); + + // Compute Normals + + vtkPolyDataNormals* computeNormals = vtkPolyDataNormals::New(); + computeNormals->SetInput(m_Surface->GetVtkPolyData()); + computeNormals->SetFeatureAngle(360.0f); + computeNormals->FlipNormalsOff(); + computeNormals->Update(); + + m_Surface->SetVtkPolyData(computeNormals->GetOutput()); + + return true; +} + +void ShowSegmentationAsSmoothedSurface::ThreadedUpdateSuccessful() +{ + DataNode::Pointer node = LookForPointerTargetBelowGroupNode("Surface representation"); + bool addToTree = node.IsNull(); + + if (addToTree) + { + node = DataNode::New(); + + bool wireframe = false; + GetParameter("Wireframe", wireframe); + + if (wireframe) + { + VtkRepresentationProperty *representation = dynamic_cast( + node->GetProperty("material.representation")); + + if (representation != NULL) + representation->SetRepresentationToWireframe(); + } + + node->SetProperty("opacity", FloatProperty::New(0.3)); + node->SetProperty("line width", IntProperty::New(1)); + node->SetProperty("scalar visibility", BoolProperty::New(false)); + + UIDGenerator uidGenerator("Surface_"); + node->SetProperty("FILENAME", StringProperty::New(uidGenerator.GetUID() + ".vtk")); + + std::string groupNodeName = "surface"; + DataNode *groupNode = GetGroupNode(); + + if (groupNode != NULL) + groupNode->GetName(groupNodeName); + + node->SetProperty("name", StringProperty::New(groupNodeName)); + } + + node->SetData(m_Surface); + + if (addToTree) + { + DataNode* groupNode = GetGroupNode(); + + if (groupNode != NULL) + { + groupNode->SetProperty("Surface representation", SmartPointerProperty::New(node)); + + BaseProperty *colorProperty = groupNode->GetProperty("color"); + + if (colorProperty != NULL) + node->ReplaceProperty("color", colorProperty); + else + node->SetProperty("color", ColorProperty::New(1.0f, 1.0f, 0.0f)); + + bool showResult = true; + GetParameter("Show result", showResult); + + bool syncVisibility = false; + GetParameter("Sync visibility", syncVisibility); + + Image::Pointer image; + GetPointerParameter("Input", image); + + BaseProperty *organTypeProperty = image->GetProperty("organ type"); + + if (organTypeProperty != NULL) + m_Surface->SetProperty("organ type", organTypeProperty); + + BaseProperty *visibleProperty = groupNode->GetProperty("visible"); + + if (visibleProperty != NULL && syncVisibility) + node->ReplaceProperty("visible", visibleProperty); + else + node->SetProperty("visible", BoolProperty::New(showResult)); + } + + InsertBelowGroupNode(node); + } + + StatusBar::GetInstance()->Clear(); + + Superclass::ThreadedUpdateSuccessful(); +} diff --git a/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.h b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.h new file mode 100644 index 0000000000..d2779109b8 --- /dev/null +++ b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.h @@ -0,0 +1,46 @@ +/*========================================================================= + +Program: Medical Imaging & Interaction Toolkit +Language: C++ +Date: $Date$ +Version: $Revision$ + +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 MITK_SHOW_SEGMENTATION_AS_SMOOTHED_SURFACE_H +#define MITK_SHOW_SEGMENTATION_AS_SMOOTHED_SURFACE_H + +#include "mitkSegmentationSink.h" +#include + +namespace mitk +{ + class MitkExt_EXPORT ShowSegmentationAsSmoothedSurface : public SegmentationSink + { + public: + mitkClassMacro(ShowSegmentationAsSmoothedSurface, SegmentationSink) + mitkAlgorithmNewMacro(ShowSegmentationAsSmoothedSurface) + + protected: + void Initialize(const NonBlockingAlgorithm *other = NULL); + bool ReadyToRun(); + bool ThreadedUpdateFunction(); + void ThreadedUpdateSuccessful(); + + private: + ShowSegmentationAsSmoothedSurface(); + ~ShowSegmentationAsSmoothedSurface(); + + Surface::Pointer m_Surface; + }; +} + +#endif diff --git a/Modules/MitkExt/files.cmake b/Modules/MitkExt/files.cmake index a4b226760e..b7d615b751 100644 --- a/Modules/MitkExt/files.cmake +++ b/Modules/MitkExt/files.cmake @@ -1,194 +1,195 @@ SET(CPP_FILES Algorithms/mitkMaskAndCutRoiImageFilter.cpp Algorithms/mitkBoundingObjectToSegmentationFilter.cpp Algorithms/vtkPointSetSlicer.cxx Algorithms/mitkCoreExtObjectFactory.cpp Algorithms/mitkAngleCorrectByPointFilter.cpp Algorithms/mitkAutoCropImageFilter.cpp Algorithms/mitkBoundingObjectCutter.cpp Algorithms/mitkCalculateSegmentationVolume.cpp Algorithms/mitkContourSetToPointSetFilter.cpp Algorithms/mitkContourUtils.cpp Algorithms/mitkCorrectorAlgorithm.cpp Algorithms/mitkCylindricToCartesianFilter.cpp Algorithms/mitkDiffImageApplier.cpp Algorithms/mitkDopplerToStrainRateFilter.cpp Algorithms/mitkGeometryClipImageFilter.cpp Algorithms/mitkGeometryDataSource.cpp Algorithms/mitkHeightFieldSurfaceClipImageFilter.cpp Algorithms/mitkImageToLookupTableFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkInterpolateLinesFilter.cpp Algorithms/mitkLabeledImageToSurfaceFilter.cpp Algorithms/mitkLabeledImageVolumeCalculator.cpp Algorithms/mitkLookupTableSource.cpp Algorithms/mitkManualSegmentationToSurfaceFilter.cpp Algorithms/mitkMaskImageFilter.cpp Algorithms/mitkMeshSource.cpp Algorithms/mitkNonBlockingAlgorithm.cpp Algorithms/mitkOverwriteSliceImageFilter.cpp Algorithms/mitkOverwriteDirectedPlaneImageFilter.cpp Algorithms/mitkPadImageFilter.cpp Algorithms/mitkPlaneCutFilter.cpp Algorithms/mitkPlaneFit.cpp Algorithms/mitkPlanesPerpendicularToLinesFilter.cpp Algorithms/mitkPointLocator.cpp Algorithms/mitkPointSetToCurvedGeometryFilter.cpp Algorithms/mitkPointSetToGeometryDataFilter.cpp Algorithms/mitkPointSetIndexToWorldTransformFilter.cpp Algorithms/mitkSurfaceIndexToWorldTransformFilter.cpp Algorithms/mitkPolygonToRingFilter.cpp Algorithms/mitkProbeFilter.cpp Algorithms/mitkSegmentationSink.cpp Algorithms/mitkShapeBasedInterpolationAlgorithm.cpp + Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp Algorithms/mitkShowSegmentationAsSurface.cpp Algorithms/mitkSimpleHistogram.cpp Algorithms/mitkSimpleUnstructuredGridHistogram.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkUnstructuredGridHistogram.cpp Algorithms/mitkUnstructuredGridSource.cpp Algorithms/mitkVolumeVisualizationImagePreprocessor.cpp Controllers/mitkMovieGenerator.cpp Controllers/mitkMultiStepper.cpp Controllers/mitkSegmentationInterpolationController.cpp Controllers/mitkToolManager.cpp DataManagement/mitkAffineTransformationOperation.cpp DataManagement/mitkApplyDiffImageOperation.cpp DataManagement/mitkBoundingObject.cpp DataManagement/mitkBoundingObjectGroup.cpp DataManagement/mitkCellOperation.cpp DataManagement/mitkColorConversions.cpp DataManagement/mitkColorSequence.cpp DataManagement/mitkColorSequenceCycleH.cpp DataManagement/mitkColorSequenceHalfTones.cpp DataManagement/mitkColorSequenceRainbow.cpp DataManagement/mitkCompressedImageContainer.cpp DataManagement/mitkCone.cpp DataManagement/mitkContour.cpp DataManagement/mitkContourSet.cpp DataManagement/mitkCuboid.cpp DataManagement/mitkCylinder.cpp DataManagement/mitkDataStorageSelection.cpp DataManagement/mitkDelegateManager.cpp DataManagement/mitkDrawOperation.cpp DataManagement/mitkEllipsoid.cpp DataManagement/mitkExternAbstractTransformGeometry.cpp DataManagement/mitkExtrudedContour.cpp DataManagement/mitkFrameOfReferenceUIDManager.cpp DataManagement/mitkGridRepresentationProperty.cpp DataManagement/mitkGridVolumeMapperProperty.cpp DataManagement/mitkItkBaseDataAdapter.cpp DataManagement/mitkLabeledImageLookupTable.cpp DataManagement/mitkLineOperation.cpp DataManagement/mitkMesh.cpp DataManagement/mitkObjectSet.cpp DataManagement/mitkOrganTypeProperty.cpp DataManagement/mitkPlaneLandmarkProjector.cpp DataManagement/mitkPlane.cpp DataManagement/mitkPropertyManager.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkSeedsImage.cpp DataManagement/mitkSeedsImageLookupTableSource.cpp DataManagement/mitkSphereLandmarkProjector.cpp # DataManagement/mitkUSLookupTableSource.cpp DataManagement/mitkUnstructuredGrid.cpp DataManagement/mitkVideoSource.cpp DataManagement/vtkObjectSet.cpp IO/mitkObjFileIOFactory.cpp IO/mitkObjFileReader.cpp IO/mitkPACSPlugin.cpp IO/mitkParRecFileIOFactory.cpp IO/mitkParRecFileReader.cpp IO/mitkStlVolumeTimeSeriesIOFactory.cpp IO/mitkStlVolumeTimeSeriesReader.cpp IO/mitkUnstructuredGridVtkWriter.cpp IO/mitkUnstructuredGridVtkWriterFactory.cpp IO/mitkVtkUnstructuredGridIOFactory.cpp IO/mitkVtkUnstructuredGridReader.cpp IO/mitkVtkVolumeTimeSeriesIOFactory.cpp IO/mitkVtkVolumeTimeSeriesReader.cpp Interactions/mitkAutoSegmentationTool.cpp Interactions/mitkConferenceEventMapper.cpp Interactions/mitkConnectPointsInteractor.cpp Interactions/mitkContourInteractor.cpp Interactions/mitkContourTool.cpp #Interactions/mitkCoordinateSupplier.cpp #Interactions/mitkDisplayCoordinateOperation.cpp #Interactions/mitkDisplayInteractor.cpp Interactions/mitkAffineInteractor3D.cpp Interactions/mitkDisplayPointSetInteractor.cpp #Interactions/mitkDisplayVectorInteractor.cpp Interactions/mitkExtrudedContourInteractor.cpp Interactions/mitkFeedbackContourTool.cpp Interactions/mitkInteractionDebug.cpp Interactions/mitkInteractionDebugger.cpp Interactions/mitkPaintbrushTool.cpp Interactions/mitkPointInteractor.cpp Interactions/mitkPointSelectorInteractor.cpp #Interactions/mitkPositionTracker.cpp Interactions/mitkSeedsInteractor.cpp Interactions/mitkSegTool2D.cpp Interactions/mitkSegmentationsProcessingTool.cpp Interactions/mitkSetRegionTool.cpp Interactions/mitkSocketClient.cpp Interactions/mitkSurfaceDeformationInteractor3D.cpp Interactions/mitkSurfaceInteractor.cpp Interactions/mitkTool.cpp Interactions/mitkAddContourTool.cpp Interactions/mitkAutoCropTool.cpp Interactions/mitkBinaryThresholdTool.cpp Interactions/mitkCalculateGrayValueStatisticsTool.cpp Interactions/mitkCalculateVolumetryTool.cpp Interactions/mitkCorrectorTool2D.cpp Interactions/mitkCreateSurfaceTool.cpp Interactions/mitkEraseRegionTool.cpp Interactions/mitkFillRegionTool.cpp Interactions/mitkRegionGrowingTool.cpp Interactions/mitkSubtractContourTool.cpp Interactions/mitkDrawPaintbrushTool.cpp Interactions/mitkErasePaintbrushTool.cpp Interactions/mitkMorphologicTool.cpp Interactions/mitkErodeTool.cpp Interactions/mitkDilateTool.cpp Interactions/mitkOpeningTool.cpp Interactions/mitkClosingTool.cpp Interactions/mitkBinaryThresholdULTool.cpp Interactions/mitkPixelManipulationTool.cpp Interactions/mitkRegionGrow3DTool.cpp Rendering/mitkContourMapper2D.cpp Rendering/mitkContourSetMapper2D.cpp Rendering/mitkContourSetVtkMapper3D.cpp Rendering/mitkContourVtkMapper3D.cpp Rendering/mitkEnhancedPointSetVtkMapper3D.cpp Rendering/mitkImageBackground2D.cpp Rendering/mitkLineMapper2D.cpp # Rendering/mitkLineVtkMapper3D.cpp Rendering/mitkMeshMapper2D.cpp Rendering/mitkMeshVtkMapper3D.cpp Rendering/mitkNativeRenderWindowInteractor.cpp Rendering/mitkSplineMapper2D.cpp Rendering/mitkSplineVtkMapper3D.cpp Rendering/mitkUnstructuredGridMapper2D.cpp Rendering/mitkUnstructuredGridVtkMapper3D.cpp Rendering/mitkVectorImageMapper2D.cpp Rendering/vtkUnstructuredGridMapper.cpp Rendering/vtkMaskedGlyph2D.cpp Rendering/vtkMaskedGlyph3D.cpp Rendering/vtkMitkVolumeTextureMapper3D.cpp Rendering/vtkMitkOpenGLVolumeTextureMapper3D.cpp Rendering/mitkGPUVolumeMapper3D.cpp Rendering/vtkMitkGPUVolumeRayCastMapper.cpp Rendering/vtkMitkOpenGLGPUVolumeRayCastMapper.cpp Rendering/vtkMitkOpenGLGPUVolumeRayCastMapperShaders.cpp ) IF(WIN32 AND NOT MINGW) SET(CPP_FILES Controllers/mitkMovieGeneratorWin32.cpp ${CPP_FILES} ) ENDIF(WIN32 AND NOT MINGW)