diff --git a/Modules/Segmentation/Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp b/Modules/Segmentation/Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp index 969e1c7e84..7c724274d0 100644 --- a/Modules/Segmentation/Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp +++ b/Modules/Segmentation/Algorithms/mitkFeatureBasedEdgeDetectionFilter.cpp @@ -1,196 +1,195 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkFeatureBasedEdgeDetectionFilter.h" #include #include #include #include #include #include #include #include -#include #include #include #include #include #include #include #include #include mitk::FeatureBasedEdgeDetectionFilter::FeatureBasedEdgeDetectionFilter() { this->SetNumberOfRequiredInputs(1); this->SetNumberOfIndexedOutputs(1); } mitk::FeatureBasedEdgeDetectionFilter::~FeatureBasedEdgeDetectionFilter() { } void mitk::FeatureBasedEdgeDetectionFilter::GenerateData() { mitk::Image::ConstPointer image = ImageToUnstructuredGridFilter::GetInput(); if (m_SegmentationMask.IsNull()) { MITK_WARN << "Please set a segmentation mask first" << std::endl; return; } // First create a threshold segmentation of the image. The threshold is determined // by the mean +/- stddev of the pixel values that are covered by the segmentation mask // Compute mean and stdDev based on the current segmentation mitk::ImageStatisticsCalculator::Pointer statCalc = mitk::ImageStatisticsCalculator::New(); statCalc->SetInputImage(image); mitk::ImageMaskGenerator::Pointer imgMask = mitk::ImageMaskGenerator::New(); imgMask->SetInputImage(image); imgMask->SetImageMask(m_SegmentationMask); auto stats = statCalc->GetStatistics()->GetStatisticsForTimeStep(0); double mean = stats.GetValueConverted(mitk::ImageStatisticsConstants::MEAN()); double stdDev = stats.GetValueConverted(mitk::ImageStatisticsConstants::STANDARDDEVIATION()); double upperThreshold = mean + stdDev; double lowerThreshold = mean - stdDev; // Perform thresholding mitk::Image::Pointer thresholdImage = mitk::Image::New(); AccessByItk_3(image.GetPointer(), ITKThresholding, lowerThreshold, upperThreshold, thresholdImage) mitk::ProgressBar::GetInstance() ->Progress(2); // Postprocess threshold segmentation // First a closing will be executed mitk::Image::Pointer closedImage = mitk::Image::New(); AccessByItk_1(thresholdImage, ThreadedClosing, closedImage); // Then we will holes that might exist mitk::MorphologicalOperations::FillHoles(closedImage); mitk::ProgressBar::GetInstance()->Progress(); // Extract the binary edges of the resulting segmentation mitk::Image::Pointer edgeImage = mitk::Image::New(); AccessByItk_1(closedImage, ContourSearch, edgeImage); // Convert the edge image into an unstructured grid mitk::ImageToUnstructuredGridFilter::Pointer i2UFilter = mitk::ImageToUnstructuredGridFilter::New(); i2UFilter->SetInput(edgeImage); i2UFilter->SetThreshold(1.0); i2UFilter->Update(); m_PointGrid = this->GetOutput(); if (m_PointGrid.IsNull()) m_PointGrid = mitk::UnstructuredGrid::New(); m_PointGrid->SetVtkUnstructuredGrid(i2UFilter->GetOutput()->GetVtkUnstructuredGrid()); mitk::ProgressBar::GetInstance()->Progress(); } template void mitk::FeatureBasedEdgeDetectionFilter::ThreadedClosing(itk::Image *originalImage, mitk::Image::Pointer &result) { typedef itk::BinaryBallStructuringElement myKernelType; myKernelType ball; ball.SetRadius(1); ball.CreateStructuringElement(); typedef typename itk::Image ImageType; typename itk::DilateObjectMorphologyImageFilter::Pointer dilationFilter = itk::DilateObjectMorphologyImageFilter::New(); dilationFilter->SetInput(originalImage); dilationFilter->SetKernel(ball); dilationFilter->Update(); typename itk::Image::Pointer dilatedImage = dilationFilter->GetOutput(); typename itk::ErodeObjectMorphologyImageFilter::Pointer erodeFilter = itk::ErodeObjectMorphologyImageFilter::New(); erodeFilter->SetInput(dilatedImage); erodeFilter->SetKernel(ball); erodeFilter->Update(); mitk::GrabItkImageMemory(erodeFilter->GetOutput(), result); } template void mitk::FeatureBasedEdgeDetectionFilter::ContourSearch(itk::Image *originalImage, mitk::Image::Pointer &result) { typedef itk::Image ImageType; typedef itk::BinaryContourImageFilter binaryContourImageFilterType; typename binaryContourImageFilterType::Pointer binaryContourFilter = binaryContourImageFilterType::New(); binaryContourFilter->SetInput(originalImage); binaryContourFilter->SetForegroundValue(1); binaryContourFilter->SetBackgroundValue(0); binaryContourFilter->Update(); typename itk::Image::Pointer itkImage = itk::Image::New(); itkImage->Graft(binaryContourFilter->GetOutput()); mitk::GrabItkImageMemory(itkImage, result); } template void mitk::FeatureBasedEdgeDetectionFilter::ITKThresholding(const itk::Image *originalImage, double lower, double upper, mitk::Image::Pointer &result) { typedef itk::Image ImageType; typedef itk::Image SegmentationType; typedef itk::BinaryThresholdImageFilter ThresholdFilterType; if (typeid(TPixel) != typeid(float) && typeid(TPixel) != typeid(double)) { // round the thresholds if we have nor a float or double image lower = std::floor(lower + 0.5); upper = std::floor(upper - 0.5); } if (lower >= upper) { upper = lower; } typename ThresholdFilterType::Pointer filter = ThresholdFilterType::New(); filter->SetInput(originalImage); filter->SetLowerThreshold(lower); filter->SetUpperThreshold(upper); filter->SetInsideValue(1); filter->SetOutsideValue(0); filter->Update(); mitk::GrabItkImageMemory(filter->GetOutput(), result); } void mitk::FeatureBasedEdgeDetectionFilter::SetSegmentationMask(mitk::Image::Pointer segmentation) { this->m_SegmentationMask = segmentation; } void mitk::FeatureBasedEdgeDetectionFilter::GenerateOutputInformation() { Superclass::GenerateOutputInformation(); } diff --git a/Modules/SegmentationUI/CMakeLists.txt b/Modules/SegmentationUI/CMakeLists.txt index be064b6867..e8ff32e1d3 100644 --- a/Modules/SegmentationUI/CMakeLists.txt +++ b/Modules/SegmentationUI/CMakeLists.txt @@ -1,5 +1,5 @@ MITK_CREATE_MODULE ( -INCLUDE_DIRS Qmitk -DEPENDS MitkSegmentation MitkQtWidgetsExt -PACKAGE_DEPENDS PRIVATE CTK|CTKWidgets nlohmann_json + INCLUDE_DIRS Qmitk SegmentationUtilities + DEPENDS MitkSegmentation MitkQtWidgetsExt + PACKAGE_DEPENDS PRIVATE CTK|CTKWidgets nlohmann_json ) diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.cpp new file mode 100644 index 0000000000..0ed04049ee --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.cpp @@ -0,0 +1,144 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkBooleanOperationsWidget.h" +#include "QmitkDataSelectionWidget.h" +#include +#include +#include +#include + +static const char* const HelpText = "Select two different segmentations above"; + +namespace +{ + static std::string GetPrefix(mitk::BooleanOperation::Type type) + { + switch (type) + { + case mitk::BooleanOperation::Difference: + return "DifferenceFrom_"; + + case mitk::BooleanOperation::Intersection: + return "IntersectionWith_"; + + case mitk::BooleanOperation::Union: + return "UnionWith_"; + + default: + assert(false && "Unknown boolean operation type"); + return "UNKNOWN_BOOLEAN_OPERATION_WITH_"; + } + } + + static void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr) + { + auto dataNode = mitk::DataNode::New(); + + dataNode->SetName(name); + dataNode->SetData(segmentation); + + dataStorage->Add(dataNode, parent); + } +} + +QmitkBooleanOperationsWidget::QmitkBooleanOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QmitkSegmentationUtilityWidget(timeNavigationController, parent) +{ + m_Controls.setupUi(this); + + m_Controls.dataSelectionWidget->AddDataSelection("", "Select 1st segmentation", "Select 1st segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection("", "Select 2nd segmentation", "Select 2nd segmentation", "", QmitkDataSelectionWidget::SegmentationPredicate); + + m_Controls.dataSelectionWidget->SetHelpText(HelpText); + + connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + connect(m_Controls.differenceButton, SIGNAL(clicked()), this, SLOT(OnDifferenceButtonClicked())); + connect(m_Controls.intersectionButton, SIGNAL(clicked()), this, SLOT(OnIntersectionButtonClicked())); + connect(m_Controls.unionButton, SIGNAL(clicked()), this, SLOT(OnUnionButtonClicked())); +} + +QmitkBooleanOperationsWidget::~QmitkBooleanOperationsWidget() +{ +} + +void QmitkBooleanOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) +{ + auto dataSelectionWidget = m_Controls.dataSelectionWidget; + + auto nodeA = dataSelectionWidget->GetSelection(0); + auto nodeB = dataSelectionWidget->GetSelection(1); + + if (nodeA.IsNotNull() && nodeB.IsNotNull() && nodeA != nodeB) + { + dataSelectionWidget->SetHelpText(""); + this->EnableButtons(); + } + else + { + dataSelectionWidget->SetHelpText(HelpText); + this->EnableButtons(false); + } +} + +void QmitkBooleanOperationsWidget::EnableButtons(bool enable) +{ + m_Controls.differenceButton->setEnabled(enable); + m_Controls.intersectionButton->setEnabled(enable); + m_Controls.unionButton->setEnabled(enable); +} + +void QmitkBooleanOperationsWidget::OnDifferenceButtonClicked() +{ + this->DoBooleanOperation(mitk::BooleanOperation::Difference); +} + +void QmitkBooleanOperationsWidget::OnIntersectionButtonClicked() +{ + this->DoBooleanOperation(mitk::BooleanOperation::Intersection); +} + +void QmitkBooleanOperationsWidget::OnUnionButtonClicked() +{ + this->DoBooleanOperation(mitk::BooleanOperation::Union); +} + +void QmitkBooleanOperationsWidget::DoBooleanOperation(mitk::BooleanOperation::Type type) +{ + auto timeNavigationController = this->GetTimeNavigationController(); + assert(timeNavigationController != nullptr); + + mitk::Image::Pointer segmentationA = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(0)->GetData()); + mitk::Image::Pointer segmentationB = dynamic_cast(m_Controls.dataSelectionWidget->GetSelection(1)->GetData()); + mitk::Image::Pointer result; + + try + { + mitk::BooleanOperation booleanOperation(type, segmentationA, segmentationB, timeNavigationController->GetSelectedTimePoint()); + result = booleanOperation.GetResult(); + + assert(result.IsNotNull()); + + auto dataSelectionWidget = m_Controls.dataSelectionWidget; + + AddToDataStorage( + dataSelectionWidget->GetDataStorage(), + result, + GetPrefix(type) + dataSelectionWidget->GetSelection(1)->GetName(), + dataSelectionWidget->GetSelection(0)); + } + catch (const mitk::Exception& exception) + { + MITK_ERROR << "Boolean operation failed: " << exception.GetDescription(); + QMessageBox::information(nullptr, "Boolean operation failed", exception.GetDescription()); + } +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.h new file mode 100644 index 0000000000..743bb42e4a --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidget.h @@ -0,0 +1,43 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkBooleanOperationsWidget_h +#define QmitkBooleanOperationsWidget_h + +#include + +#include "QmitkSegmentationUtilityWidget.h" +#include +#include + +class MITKSEGMENTATIONUI_EXPORT QmitkBooleanOperationsWidget : public QmitkSegmentationUtilityWidget +{ + Q_OBJECT + +public: + explicit QmitkBooleanOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + ~QmitkBooleanOperationsWidget() override; + +private slots: + void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + void OnDifferenceButtonClicked(); + void OnIntersectionButtonClicked(); + void OnUnionButtonClicked(); + +private: + void EnableButtons(bool enable = true); + void DoBooleanOperation(mitk::BooleanOperation::Type type); + + Ui::QmitkBooleanOperationsWidgetControls m_Controls; +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui new file mode 100644 index 0000000000..00a0389ab4 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui @@ -0,0 +1,181 @@ + + + QmitkBooleanOperationsWidgetControls + + + + 0 + 0 + 210 + 91 + + + + + + + + 0 + 0 + + + + + + + + + + false + + + + 0 + 0 + + + + Subtracts first segmentation from the second one + + + Difference + + + + :/Qmitk/BooleanDifference_48x48.png:/Qmitk/BooleanDifference_48x48.png + + + + + 24 + 24 + + + + false + + + false + + + Qt::ToolButtonTextUnderIcon + + + Qt::NoArrow + + + + + + + false + + + + 0 + 0 + + + + Keeps just the overlapping areas of two the segmentations + + + Intersection + + + + :/Qmitk/BooleanIntersection_48x48.png:/Qmitk/BooleanIntersection_48x48.png + + + + + 24 + 24 + + + + false + + + false + + + Qt::ToolButtonTextUnderIcon + + + Qt::NoArrow + + + + + + + false + + + + 0 + 0 + + + + Combines the two segmentations + + + Union + + + + :/Qmitk/BooleanUnion_48x48.png:/Qmitk/BooleanUnion_48x48.png + + + + + 24 + 24 + + + + false + + + false + + + Qt::ToolButtonTextUnderIcon + + + Qt::NoArrow + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkDataSelectionWidget + QWidget +
QmitkDataSelectionWidget.h
+ 1 +
+
+ + + + +
diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp new file mode 100644 index 0000000000..70bed04b71 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.cpp @@ -0,0 +1,246 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkContourModelToImageWidget.h" +#include "mitkImage.h" +#include "QmitkDataSelectionWidget.h" + +#include +#include +#include +#include + +#include +#include +#include +#include + +static const char* const HelpText = "Select a image and a contour(set)"; + +class QmitkContourModelToImageWidgetPrivate +{ +public: + QmitkContourModelToImageWidgetPrivate(); + ~QmitkContourModelToImageWidgetPrivate(); + + /** @brief Check if selections is valid. */ + void SelectionControl( unsigned int index, const mitk::DataNode* selection); + + /** @brief Enable buttons if data selction is valid. */ + void EnableButtons(bool enable = true); + + /** @brief Does the actual contour filling */ + mitk::LabelSetImage::Pointer FillContourModelSetIntoImage(mitk::Image *image, mitk::ContourModelSet *contourSet, mitk::TimePointType timePoint); + + Ui::QmitkContourModelToImageWidgetControls m_Controls; + QFutureWatcher m_Watcher; +}; + +QmitkContourModelToImageWidgetPrivate::QmitkContourModelToImageWidgetPrivate() +{ +} + +QmitkContourModelToImageWidgetPrivate::~QmitkContourModelToImageWidgetPrivate() +{ +} + +void QmitkContourModelToImageWidgetPrivate::EnableButtons(bool enable) +{ + m_Controls.btnProcess->setEnabled(enable); +} + +void QmitkContourModelToImageWidgetPrivate::SelectionControl(unsigned int index, const mitk::DataNode* /*selection*/) +{ + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); + + dataSelectionWidget->SetHelpText(""); + this->EnableButtons(); +} + +mitk::LabelSetImage::Pointer QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage(mitk::Image* image, mitk::ContourModelSet* contourSet, mitk::TimePointType timePoint) +{ + // Use mitk::ContourModelSetToImageFilter to fill the ContourModelSet into the image + mitk::ContourModelSetToImageFilter::Pointer contourFiller = mitk::ContourModelSetToImageFilter::New(); + auto timeStep = image->GetTimeGeometry()->TimePointToTimeStep(timePoint); + contourFiller->SetTimeStep(timeStep); + contourFiller->SetImage(image); + contourFiller->SetInput(contourSet); + contourFiller->MakeOutputBinaryOn(); + + try + { + contourFiller->Update(); + } + catch (const std::exception & e) + { + MITK_ERROR << "Error while converting contour model. "<< e.what(); + } + catch (...) + { + MITK_ERROR << "Unknown error while converting contour model."; + } + + if (nullptr == contourFiller->GetOutput()) + { + MITK_ERROR<<"Could not write the selected contours into the image!"; + } + + auto result = mitk::LabelSetImage::New(); + result->InitializeByLabeledImage(contourFiller->GetOutput()); + + return result; +} + +void QmitkContourModelToImageWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode* selection) +{ + Q_D(QmitkContourModelToImageWidget); + QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); + mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); + + if (node0.IsNull() || node1.IsNull() ) + { + d->EnableButtons(false); + dataSelectionWidget->SetHelpText(HelpText); + } + else + { + d->SelectionControl(index, selection); + } +} + +void QmitkContourModelToImageWidget::OnProcessingFinished() +{ + // Called when processing finished + // Adding the result to the data storage + + Q_D(QmitkContourModelToImageWidget); + + // Adding the result to the data storage + auto result = d->m_Watcher.result(); + if (result.IsNotNull()) + { + QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); + mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); + + mitk::DataNode::Pointer filled = mitk::DataNode::New(); + std::stringstream stream; + stream << imageNode->GetName(); + stream << "_"; + stream << contourNode->GetName(); + filled->SetName(stream.str()); + filled->SetData(result); + + dataSelectionWidget->GetDataStorage()->Add(filled, imageNode); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + else + { + MITK_ERROR<<"Error filling contours into an image!"; + } + + d->EnableButtons(); +} + +void QmitkContourModelToImageWidget::OnProcessPressed() +{ + Q_D(QmitkContourModelToImageWidget); + + QmitkDataSelectionWidget* dataSelectionWidget = d->m_Controls.dataSelectionWidget; + + mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); + mitk::DataNode::Pointer contourNode = dataSelectionWidget->GetSelection(1); + + // Check if data nodes are valid + if(imageNode.IsNull() || contourNode.IsNull() ) + { + MITK_ERROR << "Selection does not contain valid data"; + QMessageBox::information( this, "Contour To Image", + "Selection does not contain valid data, please select a binary image and a contour(set)", + QMessageBox::Ok ); + d->m_Controls.btnProcess->setEnabled(false); + return; + } + + mitk::Image::Pointer image = static_cast(imageNode->GetData()); + + // Check if the image is valid + if (image.IsNull()) + { + MITK_ERROR<<"Error writing contours into image! Invalid image data selected!"; + return; + } + + const auto timePoint = this->GetTimeNavigationController()->GetSelectedTimePoint(); + if (!image->GetTimeGeometry()->IsValidTimePoint(timePoint)) + { + MITK_ERROR << "Error writing contours into image! Currently selected time point is not supported by selected image data."; + return; + } + + // Check if the selected contours are valid + mitk::ContourModelSet::Pointer contourSet; + mitk::ContourModel::Pointer contour = dynamic_cast(contourNode->GetData()); + if (contour.IsNotNull()) + { + contourSet = mitk::ContourModelSet::New(); + contourSet->AddContourModel(contour); + } + else + { + contourSet = static_cast(contourNode->GetData()); + if (contourSet.IsNull()) + { + MITK_ERROR<<"Error writing contours into binary image! Invalid contour data selected!"; + return; + } + } + + //Disable Buttons during calculation and initialize Progressbar + d->EnableButtons(false); + + // Start the computation in a background thread + QFuture< mitk::LabelSetImage::Pointer > future = QtConcurrent::run(d, &QmitkContourModelToImageWidgetPrivate::FillContourModelSetIntoImage, image, contourSet, timePoint); + d->m_Watcher.setFuture(future); +} + +QmitkContourModelToImageWidget::QmitkContourModelToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QmitkSegmentationUtilityWidget(timeNavigationController, parent), + d_ptr(new QmitkContourModelToImageWidgetPrivate()) +{ + Q_D(QmitkContourModelToImageWidget); + + // Set up UI + d->m_Controls.setupUi(this); + d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); + d->m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ContourModelPredicate); + d->m_Controls.dataSelectionWidget->SetHelpText(HelpText); + d->EnableButtons(false); + + // Create connections + connect (d->m_Controls.btnProcess, SIGNAL(pressed()), this, SLOT(OnProcessPressed())); + connect(d->m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), + this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + connect(&d->m_Watcher, SIGNAL(finished()), this, SLOT(OnProcessingFinished())); + + if( d->m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && + d->m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) + { + OnSelectionChanged(0, d->m_Controls.dataSelectionWidget->GetSelection(0)); + } +} + +QmitkContourModelToImageWidget::~QmitkContourModelToImageWidget() +{ +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h new file mode 100644 index 0000000000..51145fea12 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidget.h @@ -0,0 +1,72 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkContourModelToImageWidget_h +#define QmitkContourModelToImageWidget_h + +#include + +#include "QmitkSegmentationUtilityWidget.h" +#include + +#include + +class QmitkContourModelToImageWidgetPrivate; + +namespace mitk { + class Image; + class ContourModelSet; + class ContourModel; + class Geometry3D; + class PlaneGeometry; +} + +/*! + \brief QmitkContourModelToImageWidget + + Tool masks an image with a binary image or a surface. The Method requires + an image and a binary image mask or a surface. The input image and the binary + image mask must be of the same size. Masking with a surface creates first a + binary image of the surface and then use this for the masking of the input image. +*/ +class MITKSEGMENTATIONUI_EXPORT QmitkContourModelToImageWidget : public QmitkSegmentationUtilityWidget +{ + Q_OBJECT + +public: + + /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ + explicit QmitkContourModelToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + + /** @brief Defaul destructor. */ + ~QmitkContourModelToImageWidget() override; + +private slots: + + /** @brief This slot is called if the selection in the workbench is changed. */ + void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + + /** @brief This slot is called if user activates the button to mask an image. */ + void OnProcessPressed(); + + /** @brief This slot is called after processing is finished */ + void OnProcessingFinished(); + +private: + + QScopedPointer d_ptr; + + Q_DECLARE_PRIVATE(QmitkContourModelToImageWidget) + Q_DISABLE_COPY(QmitkContourModelToImageWidget) +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui new file mode 100644 index 0000000000..3409e8ae5b --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui @@ -0,0 +1,56 @@ + + + QmitkContourModelToImageWidgetControls + + + + 0 + 0 + 98 + 62 + + + + + + + + 0 + 0 + + + + + + + + Process + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkDataSelectionWidget + QWidget +
QmitkDataSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.cpp new file mode 100644 index 0000000000..a5bd1eabbe --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.cpp @@ -0,0 +1,382 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkImageMaskingWidget.h" +#include "mitkImage.h" +#include "QmitkDataSelectionWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace +{ + bool IsSurface(const mitk::DataNode* dataNode) + { + if (nullptr != dataNode) + { + if (nullptr != dynamic_cast(dataNode->GetData())) + return true; + } + + return false; + } +} + +static const char* const HelpText = "Select an image and a segmentation or surface"; + +QmitkImageMaskingWidget::QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QmitkSegmentationUtilityWidget(timeNavigationController, parent) +{ + m_Controls.setupUi(this); + + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImagePredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SegmentationOrSurfacePredicate); + m_Controls.dataSelectionWidget->SetHelpText(HelpText); + + // T28795: Disable 2-d reference images since they do not work yet (segmentations are at least 3-d images with a single slice) + m_Controls.dataSelectionWidget->SetPredicate(0, mitk::NodePredicateAnd::New( + mitk::NodePredicateNot::New(mitk::NodePredicateDimension::New(2)), + m_Controls.dataSelectionWidget->GetPredicate(0))); + + this->EnableButtons(false); + + connect(m_Controls.btnMaskImage, SIGNAL(clicked()), this, SLOT(OnMaskImagePressed())); + connect(m_Controls.rbnCustom, SIGNAL(toggled(bool)), this, SLOT(OnCustomValueButtonToggled(bool))); + connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), + this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + + if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && + m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) + { + this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); + } +} + +QmitkImageMaskingWidget::~QmitkImageMaskingWidget() +{ +} + +void QmitkImageMaskingWidget::OnSelectionChanged(unsigned int index, const mitk::DataNode *selection) +{ + auto *dataSelectionWidget = m_Controls.dataSelectionWidget; + auto node0 = dataSelectionWidget->GetSelection(0); + + if (index == 0) + { + dataSelectionWidget->SetPredicate(1, QmitkDataSelectionWidget::SegmentationOrSurfacePredicate); + + if (node0.IsNotNull()) + { + dataSelectionWidget->SetPredicate(1, mitk::NodePredicateAnd::New( + mitk::NodePredicateGeometry::New(node0->GetData()->GetGeometry()), + dataSelectionWidget->GetPredicate(1))); + } + } + + auto node1 = dataSelectionWidget->GetSelection(1); + + if (node0.IsNull() || node1.IsNull()) + { + dataSelectionWidget->SetHelpText(HelpText); + this->EnableButtons(false); + } + else + { + this->SelectionControl(index, selection); + } +} + +void QmitkImageMaskingWidget::SelectionControl(unsigned int index, const mitk::DataNode* selection) +{ + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(index); + + //if Image-Masking is enabled, check if image-dimension of reference and binary image is identical + if( !IsSurface(dataSelectionWidget->GetSelection(1)) ) + { + if( dataSelectionWidget->GetSelection(0) == dataSelectionWidget->GetSelection(1) ) + { + dataSelectionWidget->SetHelpText("Select two different images above"); + this->EnableButtons(false); + return; + } + + else if( node.IsNotNull() && selection ) + { + mitk::Image::Pointer referenceImage = dynamic_cast ( dataSelectionWidget->GetSelection(0)->GetData() ); + mitk::Image::Pointer maskImage = dynamic_cast ( dataSelectionWidget->GetSelection(1)->GetData() ); + + if (maskImage.IsNull()) + { + dataSelectionWidget->SetHelpText("Different image sizes cannot be masked"); + this->EnableButtons(false); + return; + } + } + + else + { + dataSelectionWidget->SetHelpText(HelpText); + return; + } + } + + dataSelectionWidget->SetHelpText(""); + this->EnableButtons(); +} + +void QmitkImageMaskingWidget::EnableButtons(bool enable) +{ + m_Controls.grpBackgroundValue->setEnabled(enable); + m_Controls.btnMaskImage->setEnabled(enable); +} + +template +void GetRange(const itk::Image*, double& bottom, double& top) +{ + bottom = std::numeric_limits::lowest(); + top = std::numeric_limits::max(); +} + +void QmitkImageMaskingWidget::OnCustomValueButtonToggled(bool checked) +{ + m_Controls.txtCustom->setEnabled(checked); +} + +void QmitkImageMaskingWidget::OnMaskImagePressed() +{ + //Disable Buttons during calculation and initialize Progressbar + this->EnableButtons(false); + mitk::ProgressBar::GetInstance()->AddStepsToDo(4); + mitk::ProgressBar::GetInstance()->Progress(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + + //create result image, get mask node and reference image + mitk::Image::Pointer resultImage(nullptr); + mitk::DataNode::Pointer maskingNode = dataSelectionWidget->GetSelection(1); + mitk::Image::Pointer referenceImage = static_cast(dataSelectionWidget->GetSelection(0)->GetData()); + + if(referenceImage.IsNull() || maskingNode.IsNull() ) + { + MITK_ERROR << "Selection does not contain an image"; + QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain an image", QMessageBox::Ok ); + m_Controls.btnMaskImage->setEnabled(true); + return; + } + + //Do Image-Masking + if (!IsSurface(maskingNode)) + { + mitk::ProgressBar::GetInstance()->Progress(); + + mitk::Image::Pointer maskImage = dynamic_cast ( maskingNode->GetData() ); + + if(maskImage.IsNull() ) + { + MITK_ERROR << "Selection does not contain a segmentation"; + QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a segmentation", QMessageBox::Ok ); + this->EnableButtons(); + return; + } + + resultImage = this->MaskImage(referenceImage, maskImage); + } + + //Do Surface-Masking + else + { + mitk::ProgressBar::GetInstance()->Progress(); + + //1. convert surface to image + mitk::Surface::Pointer surface = dynamic_cast ( maskingNode->GetData() ); + + //TODO Get 3D Surface of current time step + + if(surface.IsNull()) + { + MITK_ERROR << "Selection does not contain a surface"; + QMessageBox::information( this, "Image and Surface Masking", "Selection does not contain a surface", QMessageBox::Ok ); + this->EnableButtons(); + return; + } + + mitk::Image::Pointer maskImage = this->ConvertSurfaceToImage( referenceImage, surface ); + + //2. mask reference image with mask image + if(maskImage.IsNotNull() && + referenceImage->GetLargestPossibleRegion().GetSize() == maskImage->GetLargestPossibleRegion().GetSize() ) + { + resultImage = this->MaskImage( referenceImage, maskImage ); + } + } + + mitk::ProgressBar::GetInstance()->Progress(); + + if( resultImage.IsNull() ) + { + MITK_ERROR << "Masking failed"; + QMessageBox::information( this, "Image and Surface Masking", "Masking failed. For more information please see logging window.", QMessageBox::Ok ); + this->EnableButtons(); + mitk::ProgressBar::GetInstance()->Progress(4); + return; + } + + //Add result to data storage + this->AddToDataStorage( + dataSelectionWidget->GetDataStorage(), + resultImage, + dataSelectionWidget->GetSelection(0)->GetName() + "_" + dataSelectionWidget->GetSelection(1)->GetName(), + dataSelectionWidget->GetSelection(0)); + + this->EnableButtons(); + + mitk::ProgressBar::GetInstance()->Progress(); +} + +mitk::Image::Pointer QmitkImageMaskingWidget::MaskImage(mitk::Image::Pointer referenceImage, mitk::Image::Pointer maskImage ) +{ + mitk::ScalarType backgroundValue = 0.0; + + if (m_Controls.rbnMinimum->isChecked()) + { + backgroundValue = referenceImage->GetStatistics()->GetScalarValueMin(); + } + else if (m_Controls.rbnCustom->isChecked()) + { + auto warningTitle = QStringLiteral("Invalid custom pixel value"); + + bool ok = false; + auto originalBackgroundValue = m_Controls.txtCustom->text().toDouble(&ok); + + if (!ok) + { + // Input is not even a number + QMessageBox::warning(nullptr, warningTitle, "Please enter a valid number as custom pixel value."); + return nullptr; + } + else + { + // Clamp to the numerical limits of the pixel/component type + double bottom, top; + if (referenceImage->GetDimension() == 4) + { + AccessFixedDimensionByItk_n(referenceImage, GetRange, 4, (bottom, top)); + } + else + { + AccessByItk_n(referenceImage, GetRange, (bottom, top)); + } + backgroundValue = std::max(bottom, std::min(originalBackgroundValue, top)); + + // Get rid of decimals for integral numbers + auto type = referenceImage->GetPixelType().GetComponentType(); + if (type != itk::IOComponentEnum::FLOAT && type != itk::IOComponentEnum::DOUBLE) + backgroundValue = std::round(backgroundValue); + } + + // Ask the user for permission before correcting their input + if (std::abs(originalBackgroundValue - backgroundValue) > 1e-4) + { + auto warningText = QString( + "

The custom pixel value %1 lies not within the range of valid pixel values for the selected image.

" + "

Apply the closest valid pixel value %2 instead?

").arg(originalBackgroundValue).arg(backgroundValue); + + auto ret = QMessageBox::warning( + nullptr, + warningTitle, + warningText, + QMessageBox::StandardButton::Apply | QMessageBox::StandardButton::Cancel, + QMessageBox::StandardButton::Apply); + + if (QMessageBox::StandardButton::Apply != ret) + return nullptr; + + m_Controls.txtCustom->setText(QString("%1").arg(backgroundValue)); + } + } + + auto maskFilter = mitk::MaskImageFilter::New(); + maskFilter->SetInput(referenceImage); + maskFilter->SetMask(maskImage); + maskFilter->OverrideOutsideValueOn(); + maskFilter->SetOutsideValue(backgroundValue); + + try + { + maskFilter->Update(); + } + catch(const itk::ExceptionObject& e) + { + MITK_ERROR << e.GetDescription(); + return nullptr; + } + + return maskFilter->GetOutput(); +} + +mitk::Image::Pointer QmitkImageMaskingWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) +{ + mitk::ProgressBar::GetInstance()->AddStepsToDo(2); + mitk::ProgressBar::GetInstance()->Progress(); + + mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); + surfaceToImageFilter->MakeOutputBinaryOn(); + surfaceToImageFilter->SetInput(surface); + surfaceToImageFilter->SetImage(image); + try + { + surfaceToImageFilter->Update(); + } + catch(itk::ExceptionObject& excpt) + { + MITK_ERROR << excpt.GetDescription(); + return nullptr; + } + + mitk::ProgressBar::GetInstance()->Progress(); + mitk::Image::Pointer resultImage = mitk::Image::New(); + resultImage = surfaceToImageFilter->GetOutput(); + + return resultImage; +} + +void QmitkImageMaskingWidget::AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent ) +{ + auto dataNode = mitk::DataNode::New(); + + dataNode->SetName(name); + dataNode->SetData(segmentation); + + if (parent.IsNotNull()) + { + mitk::LevelWindow levelWindow; + parent->GetLevelWindow(levelWindow); + dataNode->SetLevelWindow(levelWindow); + } + + dataStorage->Add(dataNode, parent); +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h new file mode 100644 index 0000000000..8d9ba8aa93 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidget.h @@ -0,0 +1,79 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkImageMaskingWidget_h +#define QmitkImageMaskingWidget_h + +#include + +#include "QmitkSegmentationUtilityWidget.h" +#include + +#include + +namespace mitk { + class Image; +} + +/*! + \brief QmitkImageMaskingWidget + + Tool masks an image with a binary image or a surface. The Method requires + an image and a binary image mask or a surface. The input image and the binary + image mask must be of the same size. Masking with a surface creates first a + binary image of the surface and then use this for the masking of the input image. +*/ +class MITKSEGMENTATIONUI_EXPORT QmitkImageMaskingWidget : public QmitkSegmentationUtilityWidget +{ + Q_OBJECT + +public: + + /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ + explicit QmitkImageMaskingWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + + /** @brief Defaul destructor. */ + ~QmitkImageMaskingWidget() override; + +private slots: + + /** @brief This slot is called if the selection in the workbench is changed. */ + void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + + /** @brief This slot is called if user activates the button to mask an image. */ + void OnMaskImagePressed(); + + /** @brief This slot is called if the user toggles the "Custom" radio button. */ + void OnCustomValueButtonToggled(bool checked); + +private: + + /** @brief Check if selections is valid. */ + void SelectionControl( unsigned int index, const mitk::DataNode* selection); + + /** @brief Enable buttons if data selction is valid. */ + void EnableButtons(bool enable = true); + + /** @brief Mask an image with a given binary mask. Note that the input image and the mask image must be of the same size. */ + itk::SmartPointer MaskImage(itk::SmartPointer referenceImage, itk::SmartPointer maskImage ); + + /** @brief Convert a surface into an binary image. */ + itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, mitk::Surface::Pointer surface ); + + /** @brief Adds a new data object to the DataStorage.*/ + void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, itk::SmartPointer segmentation, + const std::string& name, mitk::DataNode::Pointer parent = nullptr); + + Ui::QmitkImageMaskingWidgetControls m_Controls; +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidgetControls.ui new file mode 100644 index 0000000000..6d0bfa0eaf --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkImageMaskingWidgetControls.ui @@ -0,0 +1,109 @@ + + + QmitkImageMaskingWidgetControls + + + + 0 + 0 + 238 + 329 + + + + + + + + 0 + 0 + + + + + + + + Background value + + + + + + Zero + + + true + + + + + + + Minimum + + + + + + + + + + 0 + 0 + + + + Custom: + + + + + + + false + + + 0 + + + + + + + + + + + + Mask + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkDataSelectionWidget + QWidget +
QmitkDataSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp new file mode 100644 index 0000000000..5a15febb83 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp @@ -0,0 +1,251 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkMorphologicalOperationsWidget.h" +#include +#include +#include + +static const char* const HelpText = "Select a segmentation above"; + +QmitkMorphologicalOperationsWidget::QmitkMorphologicalOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QmitkSegmentationUtilityWidget(timeNavigationController, parent) +{ + m_Controls.setupUi(this); + + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SegmentationPredicate); + m_Controls.dataSelectionWidget->SetHelpText(HelpText); + + connect(m_Controls.btnClosing, SIGNAL(clicked()), this, SLOT(OnClosingButtonClicked())); + connect(m_Controls.btnOpening, SIGNAL(clicked()), this, SLOT(OnOpeningButtonClicked())); + connect(m_Controls.btnDilatation, SIGNAL(clicked()), this, SLOT(OnDilatationButtonClicked())); + connect(m_Controls.btnErosion, SIGNAL(clicked()), this, SLOT(OnErosionButtonClicked())); + connect(m_Controls.btnFillHoles, SIGNAL(clicked()), this, SLOT(OnFillHolesButtonClicked())); + connect(m_Controls.radioButtonMorphoCross, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); + connect(m_Controls.radioButtonMorphoBall, SIGNAL(clicked()), this, SLOT(OnRadioButtonsClicked())); + connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + + if (m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull()) + this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); +} + +QmitkMorphologicalOperationsWidget::~QmitkMorphologicalOperationsWidget() +{ +} + +void QmitkMorphologicalOperationsWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) +{ + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + + if (node.IsNotNull()) + { + m_Controls.dataSelectionWidget->SetHelpText(""); + this->EnableButtons(true); + } + else + { + m_Controls.dataSelectionWidget->SetHelpText(HelpText); + this->EnableButtons(false); + } +} + +void QmitkMorphologicalOperationsWidget::EnableButtons(bool enable) +{ + m_Controls.btnClosing->setEnabled(enable); + m_Controls.btnDilatation->setEnabled(enable); + m_Controls.btnErosion->setEnabled(enable); + m_Controls.btnFillHoles->setEnabled(enable); + m_Controls.btnOpening->setEnabled(enable); +} + +void QmitkMorphologicalOperationsWidget::OnRadioButtonsClicked() +{ + bool enable = m_Controls.radioButtonMorphoBall->isChecked(); + + m_Controls.sliderMorphFactor->setEnabled(enable); + m_Controls.spinBoxMorphFactor->setEnabled(enable); +} + +void QmitkMorphologicalOperationsWidget::OnClosingButtonClicked() +{ + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + mitk::Image::Pointer image = static_cast(node->GetData()); + mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); + try + { + int factor = m_Controls.spinBoxMorphFactor->isEnabled() + ? m_Controls.spinBoxMorphFactor->value() + : 1; + + mitk::MorphologicalOperations::Closing(image, factor, structuralElement); + } + catch (const itk::ExceptionObject& exception) + { + MITK_WARN << "Exception caught: " << exception.GetDescription(); + + QApplication::restoreOverrideCursor(); + return; + } + + node->SetData(image); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + QApplication::restoreOverrideCursor(); +} + +void QmitkMorphologicalOperationsWidget::OnOpeningButtonClicked() +{ + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + mitk::Image::Pointer image = static_cast(node->GetData()); + + mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); + + try + { + int factor = m_Controls.spinBoxMorphFactor->isEnabled() + ? m_Controls.spinBoxMorphFactor->value() + : 1; + + mitk::MorphologicalOperations::Opening(image, factor, structuralElement); + } + catch (const itk::ExceptionObject& exception) + { + MITK_WARN << "Exception caught: " << exception.GetDescription(); + + QApplication::restoreOverrideCursor(); + return; + } + + node->SetData(image); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + QApplication::restoreOverrideCursor(); +} + +void QmitkMorphologicalOperationsWidget::OnDilatationButtonClicked() +{ + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + mitk::Image::Pointer image = static_cast(node->GetData()); + mitk::MorphologicalOperations::StructuralElementType structuralElement = this->CreateStructerElement_UI(); + + try + { + int factor = m_Controls.spinBoxMorphFactor->isEnabled() + ? m_Controls.spinBoxMorphFactor->value() + : 1; + + mitk::MorphologicalOperations::Dilate(image, factor, structuralElement); + } + catch (const itk::ExceptionObject& exception) + { + MITK_WARN << "Exception caught: " << exception.GetDescription(); + + QApplication::restoreOverrideCursor(); + return; + } + + node->SetData(image); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + QApplication::restoreOverrideCursor(); +} + +void QmitkMorphologicalOperationsWidget::OnErosionButtonClicked() +{ + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + mitk::Image::Pointer image = static_cast(node->GetData()); +mitk::MorphologicalOperations::StructuralElementType structuralElement = CreateStructerElement_UI(); + + try + { + int factor = m_Controls.spinBoxMorphFactor->isEnabled() + ? m_Controls.spinBoxMorphFactor->value() + : 1; + + mitk::MorphologicalOperations::Erode(image, factor, structuralElement); + } + catch (const itk::ExceptionObject& exception) + { + MITK_WARN << "Exception caught: " << exception.GetDescription(); + + QApplication::restoreOverrideCursor(); + return; + } + + node->SetData(image); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + QApplication::restoreOverrideCursor(); +} + +void QmitkMorphologicalOperationsWidget::OnFillHolesButtonClicked() +{ + QApplication::setOverrideCursor(QCursor(Qt::BusyCursor)); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer node = dataSelectionWidget->GetSelection(0); + mitk::Image::Pointer image = static_cast(node->GetData()); + + try + { + mitk::MorphologicalOperations::FillHoles(image); + } + catch (const itk::ExceptionObject& exception) + { + MITK_WARN << "Exception caught: " << exception.GetDescription(); + + QApplication::restoreOverrideCursor(); + return; + } + + node->SetData(image); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + QApplication::restoreOverrideCursor(); +} + + +mitk::MorphologicalOperations::StructuralElementType QmitkMorphologicalOperationsWidget::CreateStructerElement_UI() +{ + bool ball = m_Controls.radioButtonMorphoBall->isChecked(); + int accum_flag = 0; + if(ball){ + if(m_Controls.planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Ball; // 3D Operation + if(m_Controls.planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Ball_Axial; // 2D Operation - Axial plane + if(m_Controls.planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Ball_Sagittal; // 2D Operation - Sagittal plane + if(m_Controls.planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Ball_Coronal; // 2D Operation - Coronal plane + }else{ + if(m_Controls.planeSelectionComboBox->currentIndex() == 0) accum_flag = mitk::MorphologicalOperations::Cross; + if(m_Controls.planeSelectionComboBox->currentIndex() == 1) accum_flag = mitk::MorphologicalOperations::Cross_Axial; + if(m_Controls.planeSelectionComboBox->currentIndex() == 2) accum_flag = mitk::MorphologicalOperations::Cross_Sagittal; + if(m_Controls.planeSelectionComboBox->currentIndex() == 3) accum_flag = mitk::MorphologicalOperations::Cross_Coronal; + } + return (mitk::MorphologicalOperations::StructuralElementType)accum_flag; +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h new file mode 100644 index 0000000000..b5a5913135 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidget.h @@ -0,0 +1,49 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkMorphologicalOperationsWidget_h +#define QmitkMorphologicalOperationsWidget_h + +#include + +#include "QmitkSegmentationUtilityWidget.h" +#include +#include + +/** \brief GUI class for morphological segmentation tools. + */ +class MITKSEGMENTATIONUI_EXPORT QmitkMorphologicalOperationsWidget : public QmitkSegmentationUtilityWidget +{ + Q_OBJECT + +public: + explicit QmitkMorphologicalOperationsWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + ~QmitkMorphologicalOperationsWidget() override; + +public slots: + void OnClosingButtonClicked(); + void OnOpeningButtonClicked(); + void OnDilatationButtonClicked(); + void OnErosionButtonClicked(); + void OnFillHolesButtonClicked(); + void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + void OnRadioButtonsClicked(); + +protected: + void EnableButtons(bool enable); + +private: + Ui::QmitkMorphologicalOperationsWidgetControls m_Controls; + mitk::MorphologicalOperations::StructuralElementType CreateStructerElement_UI(); +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui new file mode 100644 index 0000000000..bf923876d3 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui @@ -0,0 +1,328 @@ + + + QmitkMorphologicalOperationsWidgetControls + + + + 0 + 0 + 184 + 377 + + + + + + + + 0 + 0 + + + + + + + + Structuring Element + + + + + + Ball + + + true + + + + + + + Cross + + + + + + + + 3D Operation + + + + + 2D Operation - Axial + + + + + 2D Operation - Sagittal + + + + + 2D Operation - Coronal + + + + + + + + + + + + + Radius + + + + + + + 1 + + + 20 + + + 1 + + + Qt::Horizontal + + + + + + + 1 + + + 20 + + + + + + + + + + + false + + + + 0 + 0 + + + + Dilation + + + + :/Qmitk/Dilate_48x48.png:/Qmitk/Dilate_48x48.png + + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + false + + + + 0 + 0 + + + + Erosion + + + + :/Qmitk/Erode_48x48.png:/Qmitk/Erode_48x48.png + + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + false + + + + 0 + 0 + + + + Closing + + + + :/Qmitk/Closing_48x48.png:/Qmitk/Closing_48x48.png + + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + false + + + + 0 + 0 + + + + Opening + + + + :/Qmitk/Opening_48x48.png:/Qmitk/Opening_48x48.png + + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + false + + + + 0 + 0 + + + + Globally fills holes in segmentation (structuring element and radius not required) + + + Fill Holes + + + + :/Qmitk/FillHoles_48x48.png:/Qmitk/FillHoles_48x48.png + + + + + 32 + 32 + + + + Qt::ToolButtonTextUnderIcon + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkDataSelectionWidget + QWidget +
QmitkDataSelectionWidget.h
+ 1 +
+
+ + + + + + sliderMorphFactor + valueChanged(int) + spinBoxMorphFactor + setValue(int) + + + 240 + 27 + + + 766 + 36 + + + + + spinBoxMorphFactor + valueChanged(int) + sliderMorphFactor + setValue(int) + + + 784 + 38 + + + 657 + 38 + + + + +
diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp new file mode 100644 index 0000000000..2389dda82b --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp @@ -0,0 +1,34 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkSegmentationUtilityWidget.h" + +QmitkSegmentationUtilityWidget::QmitkSegmentationUtilityWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QWidget(parent) +{ + this->SetTimeNavigationController(timeNavigationController); +} + +QmitkSegmentationUtilityWidget::~QmitkSegmentationUtilityWidget() +{ +} + +mitk::SliceNavigationController* QmitkSegmentationUtilityWidget::GetTimeNavigationController() const +{ + return m_TimeNavigationController; +} + +void QmitkSegmentationUtilityWidget::SetTimeNavigationController(mitk::SliceNavigationController* timeNavigationController) +{ + m_TimeNavigationController = timeNavigationController; + this->setEnabled(timeNavigationController != nullptr); +} diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.h new file mode 100644 index 0000000000..d0328f9804 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSegmentationUtilityWidget.h @@ -0,0 +1,53 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkSegmentationUtilityWidget_h +#define QmitkSegmentationUtilityWidget_h + +#include + +#include + +namespace mitk +{ + class SliceNavigationController; +} + +/** \brief Base class for segmentation utility widgets that need access to the time navigation controller. + * + * Call GetTimeNavigationController() in your derived class to gain access to the time navigation controller. + * The time navigation controller is not not available at all times and hence this method can return nullptr. + */ +class MITKSEGMENTATIONUI_EXPORT QmitkSegmentationUtilityWidget : public QWidget +{ + Q_OBJECT + +public: + explicit QmitkSegmentationUtilityWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + ~QmitkSegmentationUtilityWidget() override; + + /** \brief Usually called only from QmitkSegmentationUtilitiesView::RenderWindowPartActivated() and QmitkSegmentationUtilitiesView::RenderWindowPartDeactivated(). + */ + void SetTimeNavigationController(mitk::SliceNavigationController* timeNavigationController); + +protected: + /** \brief Call this method to access the time navigation controller. + * + * \return Pointer to the time navigation controller or nullptr, if it is not available. + */ + mitk::SliceNavigationController* GetTimeNavigationController() const; + +private: + mitk::SliceNavigationController* m_TimeNavigationController; +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.cpp b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.cpp new file mode 100644 index 0000000000..d358c17492 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.cpp @@ -0,0 +1,157 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "QmitkSurfaceToImageWidget.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +static const char* const HelpText = "Select an image and a surface above"; + +QmitkSurfaceToImageWidget::QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent) + : QmitkSegmentationUtilityWidget(timeNavigationController, parent) +{ + m_Controls.setupUi(this); + + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::ImageAndSegmentationPredicate); + m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::SurfacePredicate); + m_Controls.dataSelectionWidget->SetHelpText(HelpText); + + this->EnableButtons(false); + + connect (m_Controls.btnSurface2Image, SIGNAL(pressed()), this, SLOT(OnSurface2ImagePressed())); + connect(m_Controls.dataSelectionWidget, SIGNAL(SelectionChanged(unsigned int, const mitk::DataNode*)), + this, SLOT(OnSelectionChanged(unsigned int, const mitk::DataNode*))); + + if( m_Controls.dataSelectionWidget->GetSelection(0).IsNotNull() && + m_Controls.dataSelectionWidget->GetSelection(1).IsNotNull() ) + { + this->OnSelectionChanged(0, m_Controls.dataSelectionWidget->GetSelection(0)); + } +} + +QmitkSurfaceToImageWidget::~QmitkSurfaceToImageWidget() +{ +} + +void QmitkSurfaceToImageWidget::EnableButtons(bool enable) +{ + m_Controls.btnSurface2Image->setEnabled(enable); +} + +void QmitkSurfaceToImageWidget::OnSelectionChanged(unsigned int, const mitk::DataNode*) +{ + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::DataNode::Pointer imageNode = dataSelectionWidget->GetSelection(0); + mitk::DataNode::Pointer surfaceNode = dataSelectionWidget->GetSelection(1); + + if (imageNode.IsNull() || surfaceNode.IsNull() ) + { + dataSelectionWidget->SetHelpText(HelpText); + this->EnableButtons(false); + } + else + { + mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); + mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); + if( image->GetTimeSteps() != surface->GetTimeSteps() ) + { + dataSelectionWidget->SetHelpText("Image and surface are of different size"); + this->EnableButtons(false); + } + else + { + dataSelectionWidget->SetHelpText(""); + this->EnableButtons(); + } + } +} + +void QmitkSurfaceToImageWidget::OnSurface2ImagePressed() +{ + this->EnableButtons(false); + + QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; + mitk::Image::Pointer image = dynamic_cast( dataSelectionWidget->GetSelection(0)->GetData() ); + mitk::Surface::Pointer surface = dynamic_cast( dataSelectionWidget->GetSelection(1)->GetData() ); + + if( image.IsNull() || surface.IsNull()) + { + MITK_ERROR << "Selection does not contain an image and/or a surface"; + QMessageBox::information( this, "Surface To Image", "Selection does not contain an image and/or a surface", QMessageBox::Ok ); + this->EnableButtons(); + return; + } + + mitk::Image::Pointer resultImage(nullptr); + resultImage = this->ConvertSurfaceToImage( image, surface ); + + if( resultImage.IsNull() ) + { + MITK_ERROR << "Convert Surface to binary image failed"; + QMessageBox::information( this, "Surface To Image", "Convert Surface to binary image failed", QMessageBox::Ok ); + this->EnableButtons(); + return; + } + + //create name for result node + std::string nameOfResultImage = dataSelectionWidget->GetSelection(0)->GetName(); + nameOfResultImage.append("_"); + nameOfResultImage.append(dataSelectionWidget->GetSelection(1)->GetName()); + + //create data node and add to data storage + mitk::DataNode::Pointer resultNode = mitk::DataNode::New(); + resultNode->SetData( resultImage ); + resultNode->SetProperty("name", mitk::StringProperty::New(nameOfResultImage) ); +// resultNode->SetProperty("binary", mitk::BoolProperty::New(true) ); + + dataSelectionWidget->GetDataStorage()->Add(resultNode, dataSelectionWidget->GetSelection(0)); + + this->EnableButtons(); +} + +mitk::LabelSetImage::Pointer QmitkSurfaceToImageWidget::ConvertSurfaceToImage( mitk::Image::Pointer image, mitk::Surface::Pointer surface ) +{ + mitk::ProgressBar::GetInstance()->AddStepsToDo(2); + mitk::ProgressBar::GetInstance()->Progress(); + + mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); + surfaceToImageFilter->MakeOutputBinaryOn(); + surfaceToImageFilter->SetInput(surface); + surfaceToImageFilter->SetImage(image); + try + { + surfaceToImageFilter->Update(); + } + catch(itk::ExceptionObject& excpt) + { + MITK_ERROR << excpt.GetDescription(); + return nullptr; + } + + mitk::ProgressBar::GetInstance()->Progress(); + + mitk::Image::Pointer resultImage = surfaceToImageFilter->GetOutput(); + mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); + multilabelImage->InitializeByLabeledImage(resultImage); + + return multilabelImage; +} + diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h new file mode 100644 index 0000000000..b831a3c2e6 --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidget.h @@ -0,0 +1,66 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef QmitkSurfaceToImageWidget_h +#define QmitkSurfaceToImageWidget_h + +#include + +#include "QmitkSegmentationUtilityWidget.h" +#include + +namespace mitk { + class Surface; + class Image; + class LabelSetImage; +} + +/*! + \brief QmitkSurfaceToImageWidget + + The Tool converts a surface to a binary image. The Method requires + a surface and an image, which header information defines the output + image. The resulting binary image has the same dimension, size, and + Geometry3D as the input image. +*/ +class MITKSEGMENTATIONUI_EXPORT QmitkSurfaceToImageWidget : public QmitkSegmentationUtilityWidget +{ + Q_OBJECT + +public: + + /** @brief Default constructor, including creation of GUI elements and signals/slots connections. */ + explicit QmitkSurfaceToImageWidget(mitk::SliceNavigationController* timeNavigationController, QWidget* parent = nullptr); + + /** @brief Defaul destructor. */ + ~QmitkSurfaceToImageWidget() override; + +private slots: + + /** @brief This slot is called if the selection in the workbench is changed. */ + void OnSelectionChanged(unsigned int index, const mitk::DataNode* selection); + + /** @brief This slot is called if user activates the button to convert a surface into a binary image. */ + void OnSurface2ImagePressed(); + +private: + + /** @brief Enable buttons if data selction is valid. */ + void EnableButtons(bool enable = true); + + /** @brief Convert a surface into an binary image. */ + itk::SmartPointer ConvertSurfaceToImage( itk::SmartPointer image, itk::SmartPointer surface ); + + Ui::QmitkSurfaceToImageWidgetControls m_Controls; +}; + +#endif diff --git a/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui new file mode 100644 index 0000000000..e617a3205b --- /dev/null +++ b/Modules/SegmentationUI/SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui @@ -0,0 +1,56 @@ + + + QmitkSurfaceToImageWidgetControls + + + + 0 + 0 + 98 + 62 + + + + + + + + 0 + 0 + + + + + + + + Convert + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + QmitkDataSelectionWidget + QWidget +
QmitkDataSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Modules/SegmentationUI/files.cmake b/Modules/SegmentationUI/files.cmake index 5974d42e8d..13620d1022 100644 --- a/Modules/SegmentationUI/files.cmake +++ b/Modules/SegmentationUI/files.cmake @@ -1,79 +1,96 @@ -set( CPP_FILES -Qmitk/QmitkSegWithPreviewToolGUIBase.cpp -Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp -Qmitk/QmitkBinaryThresholdToolGUIBase.cpp -Qmitk/QmitkBinaryThresholdToolGUI.cpp -Qmitk/QmitkBinaryThresholdULToolGUI.cpp -Qmitk/QmitkConfirmSegmentationDialog.cpp -Qmitk/QmitkCopyToClipBoardDialog.cpp -Qmitk/QmitkDrawPaintbrushToolGUI.cpp -Qmitk/QmitkErasePaintbrushToolGUI.cpp -Qmitk/QmitkEditableContourToolGUIBase.cpp -Qmitk/QmitkGrowCutToolGUI.cpp -Qmitk/QmitkLiveWireTool2DGUI.cpp -Qmitk/QmitkLassoToolGUI.cpp -Qmitk/QmitkOtsuTool3DGUI.cpp -Qmitk/QmitkPaintbrushToolGUI.cpp -Qmitk/QmitkPickingToolGUI.cpp -Qmitk/QmitkSlicesInterpolator.cpp -Qmitk/QmitkToolGUI.cpp -Qmitk/QmitkToolGUIArea.cpp -Qmitk/QmitkToolSelectionBox.cpp -Qmitk/QmitknnUNetFolderParser.cpp -Qmitk/QmitknnUNetToolGUI.cpp -Qmitk/QmitknnUNetWorker.cpp -Qmitk/QmitknnUNetGPU.cpp -Qmitk/QmitkSurfaceStampWidget.cpp -Qmitk/QmitkMaskStampWidget.cpp -Qmitk/QmitkStaticDynamicSegmentationDialog.cpp -Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp -Qmitk/QmitkSimpleLabelSetListWidget.cpp +set(CPP_FILES + Qmitk/QmitkSegWithPreviewToolGUIBase.cpp + Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.cpp + Qmitk/QmitkBinaryThresholdToolGUIBase.cpp + Qmitk/QmitkBinaryThresholdToolGUI.cpp + Qmitk/QmitkBinaryThresholdULToolGUI.cpp + Qmitk/QmitkConfirmSegmentationDialog.cpp + Qmitk/QmitkCopyToClipBoardDialog.cpp + Qmitk/QmitkDrawPaintbrushToolGUI.cpp + Qmitk/QmitkErasePaintbrushToolGUI.cpp + Qmitk/QmitkEditableContourToolGUIBase.cpp + Qmitk/QmitkGrowCutToolGUI.cpp + Qmitk/QmitkLiveWireTool2DGUI.cpp + Qmitk/QmitkLassoToolGUI.cpp + Qmitk/QmitkOtsuTool3DGUI.cpp + Qmitk/QmitkPaintbrushToolGUI.cpp + Qmitk/QmitkPickingToolGUI.cpp + Qmitk/QmitkSlicesInterpolator.cpp + Qmitk/QmitkToolGUI.cpp + Qmitk/QmitkToolGUIArea.cpp + Qmitk/QmitkToolSelectionBox.cpp + Qmitk/QmitknnUNetFolderParser.cpp + Qmitk/QmitknnUNetToolGUI.cpp + Qmitk/QmitknnUNetWorker.cpp + Qmitk/QmitknnUNetGPU.cpp + Qmitk/QmitkSurfaceStampWidget.cpp + Qmitk/QmitkMaskStampWidget.cpp + Qmitk/QmitkStaticDynamicSegmentationDialog.cpp + Qmitk/QmitkSurfaceBasedInterpolatorWidget.cpp + Qmitk/QmitkSimpleLabelSetListWidget.cpp + SegmentationUtilities/QmitkBooleanOperationsWidget.cpp + SegmentationUtilities/QmitkContourModelToImageWidget.cpp + SegmentationUtilities/QmitkImageMaskingWidget.cpp + SegmentationUtilities/QmitkMorphologicalOperationsWidget.cpp + SegmentationUtilities/QmitkSurfaceToImageWidget.cpp + SegmentationUtilities/QmitkSegmentationUtilityWidget.cpp ) set(MOC_H_FILES -Qmitk/QmitkSegWithPreviewToolGUIBase.h -Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h -Qmitk/QmitkBinaryThresholdToolGUIBase.h -Qmitk/QmitkBinaryThresholdToolGUI.h -Qmitk/QmitkBinaryThresholdULToolGUI.h -Qmitk/QmitkConfirmSegmentationDialog.h -Qmitk/QmitkCopyToClipBoardDialog.h -Qmitk/QmitkDrawPaintbrushToolGUI.h -Qmitk/QmitkErasePaintbrushToolGUI.h -Qmitk/QmitkEditableContourToolGUIBase.h -Qmitk/QmitkGrowCutToolGUI.h -Qmitk/QmitkLiveWireTool2DGUI.h -Qmitk/QmitkLassoToolGUI.h -Qmitk/QmitkOtsuTool3DGUI.h -Qmitk/QmitkPaintbrushToolGUI.h -Qmitk/QmitkPickingToolGUI.h -Qmitk/QmitkSlicesInterpolator.h -Qmitk/QmitkToolGUI.h -Qmitk/QmitkToolGUIArea.h -Qmitk/QmitkToolSelectionBox.h -Qmitk/QmitknnUNetFolderParser.h -Qmitk/QmitknnUNetToolGUI.h -Qmitk/QmitknnUNetGPU.h -Qmitk/QmitknnUNetWorker.h -Qmitk/QmitknnUNetEnsembleLayout.h -Qmitk/QmitkSurfaceStampWidget.h -Qmitk/QmitkMaskStampWidget.h -Qmitk/QmitkStaticDynamicSegmentationDialog.h -Qmitk/QmitkSurfaceBasedInterpolatorWidget.h -Qmitk/QmitkSimpleLabelSetListWidget.h + Qmitk/QmitkSegWithPreviewToolGUIBase.h + Qmitk/QmitkMultiLabelSegWithPreviewToolGUIBase.h + Qmitk/QmitkBinaryThresholdToolGUIBase.h + Qmitk/QmitkBinaryThresholdToolGUI.h + Qmitk/QmitkBinaryThresholdULToolGUI.h + Qmitk/QmitkConfirmSegmentationDialog.h + Qmitk/QmitkCopyToClipBoardDialog.h + Qmitk/QmitkDrawPaintbrushToolGUI.h + Qmitk/QmitkErasePaintbrushToolGUI.h + Qmitk/QmitkEditableContourToolGUIBase.h + Qmitk/QmitkGrowCutToolGUI.h + Qmitk/QmitkLiveWireTool2DGUI.h + Qmitk/QmitkLassoToolGUI.h + Qmitk/QmitkOtsuTool3DGUI.h + Qmitk/QmitkPaintbrushToolGUI.h + Qmitk/QmitkPickingToolGUI.h + Qmitk/QmitkSlicesInterpolator.h + Qmitk/QmitkToolGUI.h + Qmitk/QmitkToolGUIArea.h + Qmitk/QmitkToolSelectionBox.h + Qmitk/QmitknnUNetFolderParser.h + Qmitk/QmitknnUNetToolGUI.h + Qmitk/QmitknnUNetGPU.h + Qmitk/QmitknnUNetWorker.h + Qmitk/QmitknnUNetEnsembleLayout.h + Qmitk/QmitkSurfaceStampWidget.h + Qmitk/QmitkMaskStampWidget.h + Qmitk/QmitkStaticDynamicSegmentationDialog.h + Qmitk/QmitkSurfaceBasedInterpolatorWidget.h + Qmitk/QmitkSimpleLabelSetListWidget.h + SegmentationUtilities/QmitkBooleanOperationsWidget.h + SegmentationUtilities/QmitkContourModelToImageWidget.h + SegmentationUtilities/QmitkImageMaskingWidget.h + SegmentationUtilities/QmitkMorphologicalOperationsWidget.h + SegmentationUtilities/QmitkSurfaceToImageWidget.h + SegmentationUtilities/QmitkSegmentationUtilityWidget.h ) set(UI_FILES -Qmitk/QmitkConfirmSegmentationDialog.ui -Qmitk/QmitkGrowCutToolWidgetControls.ui -Qmitk/QmitkOtsuToolWidgetControls.ui -Qmitk/QmitkSurfaceStampWidgetGUIControls.ui -Qmitk/QmitkMaskStampWidgetGUIControls.ui -Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui -Qmitk/QmitknnUNetToolGUIControls.ui -Qmitk/QmitkEditableContourToolGUIControls.ui + Qmitk/QmitkConfirmSegmentationDialog.ui + Qmitk/QmitkGrowCutToolWidgetControls.ui + Qmitk/QmitkOtsuToolWidgetControls.ui + Qmitk/QmitkSurfaceStampWidgetGUIControls.ui + Qmitk/QmitkMaskStampWidgetGUIControls.ui + Qmitk/QmitkSurfaceBasedInterpolatorWidgetGUIControls.ui + Qmitk/QmitknnUNetToolGUIControls.ui + Qmitk/QmitkEditableContourToolGUIControls.ui + SegmentationUtilities/QmitkBooleanOperationsWidgetControls.ui + SegmentationUtilities/QmitkContourModelToImageWidgetControls.ui + SegmentationUtilities/QmitkImageMaskingWidgetControls.ui + SegmentationUtilities/QmitkMorphologicalOperationsWidgetControls.ui + SegmentationUtilities/QmitkSurfaceToImageWidgetControls.ui ) set(QRC_FILES resources/SegmentationUI.qrc ) diff --git a/Modules/SegmentationUI/resources/BooleanDifference_48x48.png b/Modules/SegmentationUI/resources/BooleanDifference_48x48.png index 5d7b6a69d6..89a7c9322c 100644 Binary files a/Modules/SegmentationUI/resources/BooleanDifference_48x48.png and b/Modules/SegmentationUI/resources/BooleanDifference_48x48.png differ diff --git a/Modules/SegmentationUI/resources/BooleanIntersection_48x48.png b/Modules/SegmentationUI/resources/BooleanIntersection_48x48.png index 554c43281b..b7301f31f5 100644 Binary files a/Modules/SegmentationUI/resources/BooleanIntersection_48x48.png and b/Modules/SegmentationUI/resources/BooleanIntersection_48x48.png differ diff --git a/Modules/SegmentationUI/resources/BooleanLabelA_32x32.png b/Modules/SegmentationUI/resources/BooleanLabelA_32x32.png new file mode 100644 index 0000000000..7c4f33d1d1 Binary files /dev/null and b/Modules/SegmentationUI/resources/BooleanLabelA_32x32.png differ diff --git a/Modules/SegmentationUI/resources/BooleanLabelB_32x32.png b/Modules/SegmentationUI/resources/BooleanLabelB_32x32.png new file mode 100644 index 0000000000..b995040523 Binary files /dev/null and b/Modules/SegmentationUI/resources/BooleanLabelB_32x32.png differ diff --git a/Modules/SegmentationUI/resources/BooleanUnion_48x48.png b/Modules/SegmentationUI/resources/BooleanUnion_48x48.png index 4a425fc5c7..4b01a6d74c 100644 Binary files a/Modules/SegmentationUI/resources/BooleanUnion_48x48.png and b/Modules/SegmentationUI/resources/BooleanUnion_48x48.png differ diff --git a/Modules/SegmentationUI/resources/Closing_48x48.png b/Modules/SegmentationUI/resources/Closing_48x48.png new file mode 100644 index 0000000000..15fe6abe6d Binary files /dev/null and b/Modules/SegmentationUI/resources/Closing_48x48.png differ diff --git a/Modules/SegmentationUI/resources/Dilate_48x48.png b/Modules/SegmentationUI/resources/Dilate_48x48.png new file mode 100644 index 0000000000..ac913b3e10 Binary files /dev/null and b/Modules/SegmentationUI/resources/Dilate_48x48.png differ diff --git a/Modules/SegmentationUI/resources/Erode_48x48.png b/Modules/SegmentationUI/resources/Erode_48x48.png new file mode 100644 index 0000000000..9a1d09b660 Binary files /dev/null and b/Modules/SegmentationUI/resources/Erode_48x48.png differ diff --git a/Modules/SegmentationUI/resources/FillHoles_48x48.png b/Modules/SegmentationUI/resources/FillHoles_48x48.png new file mode 100644 index 0000000000..8a326f3230 Binary files /dev/null and b/Modules/SegmentationUI/resources/FillHoles_48x48.png differ diff --git a/Modules/SegmentationUI/resources/Opening_48x48.png b/Modules/SegmentationUI/resources/Opening_48x48.png new file mode 100644 index 0000000000..9f6fba8237 Binary files /dev/null and b/Modules/SegmentationUI/resources/Opening_48x48.png differ diff --git a/Modules/SegmentationUI/resources/SegmentationUI.qrc b/Modules/SegmentationUI/resources/SegmentationUI.qrc index cfab8d398d..6cb9f4894b 100644 --- a/Modules/SegmentationUI/resources/SegmentationUI.qrc +++ b/Modules/SegmentationUI/resources/SegmentationUI.qrc @@ -1,40 +1,47 @@ AcceptCurrentInterpolation.png AcceptAllInterpolations.png AcceptSurfaceInterpolation.png BooleanDifference_48x48.png BooleanIntersection_48x48.png BooleanUnion_48x48.png + BooleanLabelA_32x32.png + BooleanLabelB_32x32.png + Dilate_48x48.png + Erode_48x48.png + Closing_48x48.png + Opening_48x48.png + FillHoles_48x48.png Accept_48x48.png Cancel_48x48.png Run_48x48.png ImportLabelSet_48x48.png ImportLabeledImage_48x48.png DeleteLayer_48x48.png PreviousLayer_48x48.png NextLayer_48x48.png AddLayer_48x48.png SegmentationInteractor_48x48.png LockExterior_48x48.png UnlockExterior_48x48.png NewLabel_48x48.png NewSegmentation_48x48.png ClearSeeds_48x48.png Start.png Stop.png Help_48x48.png AdvancedTools.png visible.svg invisible.svg lock.svg unlock.svg MergeLabels.png RemoveLabel.png EraseLabel.png CreateSurface.png CreateMask.png RandomColor.png RenameLabel.png