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 60b942c30a..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,170 +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); - surfaceLayout->addRow("Smoothing value", m_SmoothingSpinBox); + 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/internal/QmitkCreatePolygonModelAction.cpp b/Modules/Bundles/org.mitk.gui.qt.segmentation/src/internal/QmitkCreatePolygonModelAction.cpp index b92c3c2375..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,161 +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 { if (!m_IsSmoothed) { 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 { 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(10); - mitk::ProgressBar::GetInstance()->Progress(1); - mitk::StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background (this may take a while)..."); + mitk::ProgressBar::GetInstance()->AddStepsToDo(8); + mitk::StatusBar::GetInstance()->DisplayText("Smoothed surface creation started in background..."); filter->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/mitkShowSegmentationAsSmoothedSurface.cpp b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp index 2669ebf6b5..58321d1baa 100644 --- a/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp +++ b/Modules/MitkExt/Algorithms/mitkShowSegmentationAsSmoothedSurface.cpp @@ -1,549 +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 dacimation value is ]0, 1[. High values + // 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(); - imageToItkFilter->SetInput(image); + + 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(); - gaussFilter->Update(); - - FloatImageType::Pointer blurredImage = gaussFilter->GetOutput(); - - blurredImage->DisconnectPipeline(); - closedImage = 0; - binThresToFloatFilter = 0; - gaussFilter = 0; - - ProgressBar::GetInstance()->Progress(1); - - // Isolate largest component - - MITK_INFO << "Isolate largest component..." << endl; typedef itk::BinaryThresholdImageFilter BinaryThresholdFromFloatFilterType; BinaryThresholdFromFloatFilterType::Pointer binThresFromFloatFilter = BinaryThresholdFromFloatFilterType::New(); - binThresFromFloatFilter->SetInput(blurredImage); + binThresFromFloatFilter->SetInput(gaussFilter->GetOutput()); binThresFromFloatFilter->SetLowerThreshold(50); binThresFromFloatFilter->SetUpperThreshold(255); binThresFromFloatFilter->SetInsideValue(1); binThresFromFloatFilter->SetOutsideValue(0); binThresFromFloatFilter->ReleaseDataFlagOn(); binThresFromFloatFilter->ReleaseDataBeforeUpdateFlagOn(); + binThresFromFloatFilter->Update(); - typedef itk::ConnectedComponentImageFilter ConnectedComponentFilterType; - - ConnectedComponentFilterType::Pointer connectedComponentFilter = ConnectedComponentFilterType::New(); - - connectedComponentFilter->SetInput(binThresFromFloatFilter->GetOutput()); - - typedef itk::RelabelComponentImageFilter RelabelComponentFilterType; - - RelabelComponentFilterType::Pointer relabelComponentFilter = RelabelComponentFilterType::New(); - - relabelComponentFilter->SetInput(connectedComponentFilter->GetOutput()); - relabelComponentFilter->ReleaseDataFlagOn(); - relabelComponentFilter->ReleaseDataBeforeUpdateFlagOn(); - relabelComponentFilter->Update(); - - MITK_INFO << " " << relabelComponentFilter->GetNumberOfObjects() << " components found" << endl; - - typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; - - BinaryThresholdFilterType::Pointer binThresFilter = BinaryThresholdFilterType::New(); - - binThresFilter->SetInput(relabelComponentFilter->GetOutput()); - binThresFilter->SetLowerThreshold(2); - binThresFilter->SetUpperThreshold(255); - binThresFilter->SetInsideValue(0); - binThresFilter->SetOutsideValue(1); - binThresFilter->ReleaseDataFlagOn(); - binThresFilter->ReleaseDataBeforeUpdateFlagOn(); - binThresFilter->Update(); - - typedef itk::MultiplyImageFilter MultiplyFilterType; - - MultiplyFilterType::Pointer multiplyFilter = MultiplyFilterType::New(); - - multiplyFilter->SetInput1(blurredImage); - multiplyFilter->SetInput2(binThresFilter->GetOutput()); - multiplyFilter->ReleaseDataFlagOn(); - multiplyFilter->ReleaseDataBeforeUpdateFlagOn(); - multiplyFilter->Update(); - - CharImageType::Pointer singleComponentImage = multiplyFilter->GetOutput(); + CharImageType::Pointer blurredImage = binThresFromFloatFilter->GetOutput(); - singleComponentImage->DisconnectPipeline(); - blurredImage = 0; - binThresFromFloatFilter = 0; - connectedComponentFilter = 0; - relabelComponentFilter = 0; - binThresFilter = 0; - multiplyFilter = 0; - - // Fill holes + blurredImage->DisconnectPipeline(); + closedImage = 0; + binThresToFloatFilter = 0; + gaussFilter = 0; ProgressBar::GetInstance()->Progress(1); - - MITK_INFO << "Filling cavities..." << endl; - binThresFilter = BinaryThresholdFilterType::New(); + // Fill holes - binThresFilter->SetInput(singleComponentImage); - binThresFilter->SetLowerThreshold(50); - binThresFilter->SetUpperThreshold(255); - binThresFilter->SetInsideValue(1); - binThresFilter->SetOutsideValue(0); - binThresFilter->ReleaseDataFlagOn(); - binThresFilter->ReleaseDataBeforeUpdateFlagOn(); + 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(binThresFilter->GetOutput()); + connectedThresFilter->SetInput(blurredImage); connectedThresFilter->SetSeed(corner); connectedThresFilter->SetLower(0); connectedThresFilter->SetUpper(0); connectedThresFilter->SetReplaceValue(2); connectedThresFilter->ReleaseDataFlagOn(); connectedThresFilter->ReleaseDataBeforeUpdateFlagOn(); - BinaryThresholdFilterType::Pointer binThresFilter2 = BinaryThresholdFilterType::New(); + typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; + + BinaryThresholdFilterType::Pointer binThresFilter = BinaryThresholdFilterType::New(); - binThresFilter2->SetInput(connectedThresFilter->GetOutput()); - binThresFilter2->SetLowerThreshold(0); - binThresFilter2->SetUpperThreshold(0); - binThresFilter2->SetInsideValue(50); - binThresFilter2->SetOutsideValue(0); - binThresFilter2->ReleaseDataFlagOn(); - binThresFilter2->ReleaseDataBeforeUpdateFlagOn(); + 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(singleComponentImage); - addFilter->SetInput2(binThresFilter2->GetOutput()); + 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(); }