diff --git a/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp b/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp index 880d00ac5e..f6dcbfa80b 100644 --- a/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp +++ b/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.cpp @@ -1,185 +1,178 @@ /*============================================================================ 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 "mitkBooleanOperation.h" #include #include #include #include #include #include typedef itk::Image ImageType; -static mitk::Image::Pointer Get3DSegmentation(mitk::Image::Pointer segmentation, unsigned int time) +static mitk::Image::Pointer Get3DSegmentation(mitk::Image::Pointer segmentation, mitk::TimePointType time) { if (segmentation->GetDimension() != 4) return segmentation; auto imageTimeSelector = mitk::ImageTimeSelector::New(); imageTimeSelector->SetInput(segmentation); - imageTimeSelector->SetTimeNr(static_cast(time)); + imageTimeSelector->SetTimeNr(segmentation->GetTimeGeometry()->TimePointToTimeStep(time)); imageTimeSelector->UpdateLargestPossibleRegion(); return imageTimeSelector->GetOutput(); } -static ImageType::Pointer CastTo3DItkImage(mitk::Image::Pointer segmentation, unsigned int time) +static ImageType::Pointer CastTo3DItkImage(mitk::Image::Pointer segmentation, mitk::TimePointType time) { ImageType::Pointer result; mitk::CastToItkImage(Get3DSegmentation(segmentation, time), result); return result; } mitk::BooleanOperation::BooleanOperation(Type type, mitk::Image::Pointer segmentationA, mitk::Image::Pointer segmentationB, - unsigned int time) - : m_Type(type), m_SegmentationA(segmentationA), m_SegmentationB(segmentationB), m_Time(time) + TimePointType time) + : m_Type(type), m_SegmentationA(segmentationA), m_SegmentationB(segmentationB), m_TimePoint(time) { this->ValidateSegmentations(); } mitk::BooleanOperation::~BooleanOperation() { } mitk::LabelSetImage::Pointer mitk::BooleanOperation::GetResult() const { switch (m_Type) { case Difference: return this->GetDifference(); case Intersection: return this->GetIntersection(); case Union: return this->GetUnion(); default: mitkThrow() << "Unknown boolean operation type '" << m_Type << "'!"; } } mitk::LabelSetImage::Pointer mitk::BooleanOperation::GetDifference() const { - auto input1 = CastTo3DItkImage(m_SegmentationA, m_Time); - auto input2 = CastTo3DItkImage(m_SegmentationB, m_Time); + auto input1 = CastTo3DItkImage(m_SegmentationA, m_TimePoint); + auto input2 = CastTo3DItkImage(m_SegmentationB, m_TimePoint); auto notFilter = itk::NotImageFilter::New(); notFilter->SetInput(input2); auto andFilter = itk::AndImageFilter::New(); andFilter->SetInput1(input1); andFilter->SetInput2(notFilter->GetOutput()); andFilter->UpdateLargestPossibleRegion(); auto tempResult = Image::New(); CastToMitkImage(andFilter->GetOutput(), tempResult); tempResult->DisconnectPipeline(); auto result = mitk::LabelSetImage::New(); result->InitializeByLabeledImage(tempResult); return result; } mitk::LabelSetImage::Pointer mitk::BooleanOperation::GetIntersection() const { - auto input1 = CastTo3DItkImage(m_SegmentationA, m_Time); - auto input2 = CastTo3DItkImage(m_SegmentationB, m_Time); + auto input1 = CastTo3DItkImage(m_SegmentationA, m_TimePoint); + auto input2 = CastTo3DItkImage(m_SegmentationB, m_TimePoint); auto andFilter = itk::AndImageFilter::New(); andFilter->SetInput1(input1); andFilter->SetInput2(input2); andFilter->UpdateLargestPossibleRegion(); auto tempResult = Image::New(); CastToMitkImage(andFilter->GetOutput(), tempResult); tempResult->DisconnectPipeline(); auto result = mitk::LabelSetImage::New(); result->InitializeByLabeledImage(tempResult); return result; } mitk::LabelSetImage::Pointer mitk::BooleanOperation::GetUnion() const { - auto input1 = CastTo3DItkImage(m_SegmentationA, m_Time); - auto input2 = CastTo3DItkImage(m_SegmentationB, m_Time); + auto input1 = CastTo3DItkImage(m_SegmentationA, m_TimePoint); + auto input2 = CastTo3DItkImage(m_SegmentationB, m_TimePoint); auto orFilter = itk::OrImageFilter::New(); orFilter->SetInput1(input1); orFilter->SetInput2(input2); orFilter->UpdateLargestPossibleRegion(); auto tempResult = Image::New(); CastToMitkImage(orFilter->GetOutput(), tempResult); tempResult->DisconnectPipeline(); auto result = mitk::LabelSetImage::New(); result->InitializeByLabeledImage(tempResult); return result; } void mitk::BooleanOperation::ValidateSegmentation(mitk::Image::Pointer segmentation) const { if (segmentation.IsNull()) mitkThrow() << "Segmentation is nullptr!"; if (segmentation->GetImageDescriptor()->GetNumberOfChannels() != 1) mitkThrow() << "Segmentation has more than one channel!"; auto pixelType = segmentation->GetImageDescriptor()->GetChannelDescriptor().GetPixelType(); if (pixelType.GetPixelType() != itk::ImageIOBase::SCALAR || (pixelType.GetComponentType() != itk::ImageIOBase::UCHAR && pixelType.GetComponentType() != itk::ImageIOBase::USHORT)) mitkThrow() << "Segmentation is neither of type 'unsigned char' nor type 'unsigned short'!"; auto dimension = segmentation->GetDimension(); if (dimension > 4) mitkThrow() << "Segmentation has more than four dimensions!"; - if (m_Time != 0) - { - if (dimension < 4) - mitkThrow() << "Expected four-dimensional segmentation!"; - - if (segmentation->GetDimension(3) < m_Time) - mitkThrow() << "Extent of fourth dimension of segmentation is less than specified time!"; - } - else if (dimension < 3) - { + if (dimension < 3) mitkThrow() << "Segmentation has less than three dimensions!"; - } + + if (!segmentation->GetTimeGeometry()->IsValidTimePoint(m_TimePoint)) + mitkThrow() << "Segmentation is not defined for specified time point. Time point: " << m_TimePoint; } void mitk::BooleanOperation::ValidateSegmentations() const { this->ValidateSegmentation(m_SegmentationA); this->ValidateSegmentation(m_SegmentationB); if (m_SegmentationA->GetDimension() != m_SegmentationB->GetDimension()) mitkThrow() << "Segmentations have different dimensions!"; } diff --git a/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.h b/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.h index 5fc6858c52..a80ebf3d91 100644 --- a/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.h +++ b/Modules/Segmentation/SegmentationUtilities/BooleanOperations/mitkBooleanOperation.h @@ -1,73 +1,73 @@ /*============================================================================ 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 mitkBooleanOperation_h #define mitkBooleanOperation_h #include #include namespace mitk { /** \brief Executes a boolean operation on two different segmentations. * * All parameters of the boolean operations must be specified during construction. * The actual operation is executed when calling GetResult(). */ class MITKSEGMENTATION_EXPORT BooleanOperation { public: enum Type { None, Difference, Intersection, Union }; /* \brief Construct a boolean operation. * * Throws an mitk::Exception when segmentations are somehow invalid. * * \param[in] type The type of the boolean operation. * \param[in] segmentationA The first operand of the boolean operation. * \param[in] segmentationB The second operand of the boolean operation. - * \param[in] The time step at which the operation will be executed. + * \param[in] The time point at which the operation will be executed. */ - BooleanOperation(Type type, Image::Pointer segmentationA, Image::Pointer segmentationB, unsigned int time = 0); + BooleanOperation(Type type, Image::Pointer segmentationA, Image::Pointer segmentationB, mitk::TimePointType time = 0.); ~BooleanOperation(); /* \brief Execute boolean operation and return resulting segmentation. * * \return The resulting segmentation. */ LabelSetImage::Pointer GetResult() const; private: BooleanOperation(const BooleanOperation &); BooleanOperation &operator=(const BooleanOperation &); LabelSetImage::Pointer GetDifference() const; LabelSetImage::Pointer GetIntersection() const; LabelSetImage::Pointer GetUnion() const; void ValidateSegmentation(Image::Pointer segmentation) const; void ValidateSegmentations() const; Type m_Type; Image::Pointer m_SegmentationA; Image::Pointer m_SegmentationB; - unsigned int m_Time; + TimePointType m_TimePoint; }; } #endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp index 64c496cda8..87c10cacf2 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp @@ -1,140 +1,140 @@ /*============================================================================ 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 "../../Common/QmitkDataSelectionWidget.h" #include #include #include static const char* const HelpText = "Select two different masks above"; 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_"; } } void AddToDataStorage(mitk::DataStorage::Pointer dataStorage, mitk::Image::Pointer segmentation, const std::string& name, mitk::DataNode::Pointer parent = nullptr) { mitk::DataNode::Pointer dataNode = mitk::DataNode::New(); dataNode->SetBoolProperty("binary", true); 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(QmitkDataSelectionWidget::MaskPredicate); m_Controls.dataSelectionWidget->AddDataSelection(QmitkDataSelectionWidget::MaskPredicate); 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*) { QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; mitk::DataNode::Pointer node0 = dataSelectionWidget->GetSelection(0); mitk::DataNode::Pointer node1 = dataSelectionWidget->GetSelection(1); if (node0.IsNotNull() && node1.IsNotNull() && node0 != node1) { 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) { mitk::SliceNavigationController* timeNavigationController = this->GetTimeNavigationController(); assert(timeNavigationController != nullptr); mitk::Image::Pointer segmentation0 = static_cast(m_Controls.dataSelectionWidget->GetSelection(0)->GetData()); mitk::Image::Pointer segmentation1 = static_cast(m_Controls.dataSelectionWidget->GetSelection(1)->GetData()); mitk::Image::Pointer result; try { - mitk::BooleanOperation booleanOperation(type, segmentation0, segmentation1, timeNavigationController->GetTime()->GetPos()); + mitk::BooleanOperation booleanOperation(type, segmentation0, segmentation1, timeNavigationController->GetSelectedTimePoint()); result = booleanOperation.GetResult(); } catch (const mitk::Exception &exception) { MITK_ERROR << "Boolean operation failed: " << exception.GetDescription(); } assert(result.IsNotNull()); QmitkDataSelectionWidget* dataSelectionWidget = m_Controls.dataSelectionWidget; AddToDataStorage( dataSelectionWidget->GetDataStorage(), result, GetPrefix(type) + dataSelectionWidget->GetSelection(1)->GetName(), dataSelectionWidget->GetSelection(0)); } diff --git a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp index d66b78dc14..abb337ba5b 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp +++ b/Plugins/org.mitk.gui.qt.segmentation/src/internal/SegmentationUtilities/BooleanOperations/QmitkBooleanOperationsWidget.cpp @@ -1,141 +1,141 @@ /*============================================================================ 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 "../../Common/QmitkDataSelectionWidget.h" #include #include #include #include static const char* const HelpText = "Select two different segmentations above"; 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->GetTime()->GetPos()); + 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()); } }