diff --git a/Plugins/org.mitk.gui.qt.imagecropper/files.cmake b/Plugins/org.mitk.gui.qt.imagecropper/files.cmake index 27552186bb..59435c5859 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/files.cmake +++ b/Plugins/org.mitk.gui.qt.imagecropper/files.cmake @@ -1,36 +1,32 @@ -set(SRC_CPP_FILES - -) - set(INTERNAL_CPP_FILES - org_mitk_gui_qt_imagecropper_Activator.cpp - QmitkImageCropper.cpp + mitkPluginActivator.cpp + QmitkImageCropperView.cpp ) set(UI_FILES - src/internal/ImageCropperControls.ui + src/internal/QmitkImageCropperViewControls.ui ) set(MOC_H_FILES - src/internal/org_mitk_gui_qt_imagecropper_Activator.h - src/internal/QmitkImageCropper.h + src/internal/mitkPluginActivator.h + src/internal/QmitkImageCropperView.h ) set(CACHED_RESOURCE_FILES resources/crop.svg plugin.xml ) set(QRC_FILES resources/imagecropper.qrc ) set(CPP_FILES) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml b/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml index 7b2df1f616..ccc04b49d1 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml +++ b/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml @@ -1,27 +1,27 @@ + class="QmitkImageCropperView" > Crop images to a given size diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui deleted file mode 100644 index 2c0107ebed..0000000000 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui +++ /dev/null @@ -1,1133 +0,0 @@ - - - ImageCropperControls - - - - 0 - 0 - 329 - 863 - - - - - 0 - 0 - - - - QmitkTemplate - - - - - - 3 - - - - - - 0 - 0 - - - - QLabel { color: rgb(255, 0, 0) } - - - Please select an image. - - - - - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 120 - 120 - 120 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 127 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - Please select a bounding object. - - - - - - - - - false - - - - 0 - 0 - - - - - 0 - 90 - - - - Bounding object - - - - - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - - - - - - 0 - 0 - - - - New - - - - - - - - - - 0 - 0 - - - - Do Cropping - - - Mask - - - - - - - - 0 - 0 - - - - Crop - - - - - - - - - - true - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - - 127 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 127 - 127 - - - - - - - 255 - 63 - 63 - - - - - - - 127 - 0 - 0 - - - - - - - 170 - 0 - 0 - - - - - - - 127 - 0 - 0 - - - - - - - 255 - 255 - 255 - - - - - - - 127 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 0 - 0 - 0 - - - - - - - 255 - 0 - 0 - - - - - - - 255 - 255 - 220 - - - - - - - 0 - 0 - 0 - - - - - - - - Image geometry is rotated, result won't be pixel-aligned. You can reinit your image to get a pixel-aligned result, though. - - - Qt::PlainText - - - true - - - - - - - - 0 - 0 - - - - - 0 - 25 - - - - Advanced settings - - - false - - - 100 - - - Qt::ToolButtonTextBesideIcon - - - false - - - - - - - - 0 - 0 - - - - - 0 - 120 - - - - Output image settings - - - - - - - - - 0 - 0 - - - - Outside pixel value (masking): - - - - - - - false - - - - 0 - 0 - - - - - 16777210 - 16777215 - - - - - - - - - - - 0 - 0 - - - - Overrride original image - - - false - - - - - - - - 0 - 0 - - - - Only crop current timestep - / cut off other timesteps - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - - - - - - QmitkDataStorageComboBox - QComboBox -
QmitkDataStorageComboBox.h
-
- - ctkExpandButton - QToolButton -
ctkExpandButton.h
-
-
- - -
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp deleted file mode 100644 index 6b4c50132b..0000000000 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp +++ /dev/null @@ -1,574 +0,0 @@ -/*============================================================================ - -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 "QmitkImageCropper.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include // Includes for image casting between ITK and MITK: added after using Plugin Generator -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include - -const std::string QmitkImageCropper::VIEW_ID = "org.mitk.views.qmitkimagecropper"; - -QmitkImageCropper::QmitkImageCropper(QObject *) - : m_ParentWidget(nullptr), - m_ImageNode(nullptr), - m_CroppingObject(nullptr), - m_CroppingObjectNode(nullptr), - m_BoundingShapeInteractor(nullptr), - m_CropOutsideValue(0), - m_Advanced(0), - m_Active(0), - m_ScrollEnabled(true) -{ - CreateBoundingShapeInteractor(false); -} - -QmitkImageCropper::~QmitkImageCropper() -{ - //delete pointer objects - m_CroppingObjectNode = nullptr; - m_CroppingObject = nullptr; - - //disable interactor - if (m_BoundingShapeInteractor != nullptr) - { - m_BoundingShapeInteractor->SetDataNode(nullptr); - m_BoundingShapeInteractor->EnableInteraction(false); - } -} - -void QmitkImageCropper::SetFocus() -{ - m_Controls.buttonCreateNewBoundingBox->setFocus(); -} - -void QmitkImageCropper::CreateQtPartControl(QWidget *parent) -{ - // create GUI widgets from the Qt Designer's .ui file - m_Controls.setupUi(parent); - - m_Controls.boundingShapeSelector->SetDataStorage(this->GetDataStorage()); - m_Controls.boundingShapeSelector->SetPredicate(mitk::NodePredicateAnd::New( - mitk::TNodePredicateDataType::New(), - mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); - m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); - - connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(DoCropping())); - connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(DoMasking())); - connect(m_Controls.boundingShapeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), - this, SLOT(OnDataSelectionChanged(const mitk::DataNode*))); - connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(DoCreateNewBoundingObject())); - connect(m_Controls.buttonAdvancedSettings, SIGNAL(clicked()), this, SLOT(OnAdvancedSettingsButtonToggled())); - connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); - - setDefaultGUI(); - m_Controls.labelWarningRotation->setVisible(false); - - m_Advanced = false; - this->OnAdvancedSettingsButtonToggled(); - m_ParentWidget = parent; -} - -void QmitkImageCropper::OnDataSelectionChanged(const mitk::DataNode*) -{ - m_Controls.boundingShapeSelector->setEnabled(true); - m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); - - if (m_CroppingObjectNode.IsNotNull() && dynamic_cast(this->m_CroppingObjectNode->GetData())) - { - m_Controls.buttonAdvancedSettings->setEnabled(true); - m_Controls.groupImageSettings->setEnabled(true); - m_Controls.labelWarningBB->setVisible(false); - m_CroppingObject = dynamic_cast(m_CroppingObjectNode->GetData()); - m_Advanced = true; - - m_BoundingShapeInteractor->EnableInteraction(true); - m_BoundingShapeInteractor->SetDataNode(m_CroppingObjectNode); - - mitk::RenderingManager::GetInstance()->InitializeViews(); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - else - { - setDefaultGUI(); - m_CroppingObject = nullptr; - m_BoundingShapeInteractor->EnableInteraction(false); - m_BoundingShapeInteractor->SetDataNode(nullptr); - m_Advanced = false; - this->OnAdvancedSettingsButtonToggled(); - } -} - -void QmitkImageCropper::OnAdvancedSettingsButtonToggled() -{ - m_Controls.groupImageSettings->setVisible(m_Advanced); - m_Advanced = !m_Advanced; -} - -void QmitkImageCropper::CreateBoundingShapeInteractor(bool rotationEnabled) -{ - if (m_BoundingShapeInteractor.IsNull()) - { - m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New(); - m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); - m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); - } - m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled); -} - -mitk::Geometry3D::Pointer QmitkImageCropper::InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry) -{ - // convert a basegeometry into a Geometry3D (otherwise IO is not working properly) - if (geometry == nullptr) - mitkThrow() << "Geometry is not valid."; - - auto boundingGeometry = mitk::Geometry3D::New(); - boundingGeometry->SetBounds(geometry->GetBounds()); - boundingGeometry->SetImageGeometry(geometry->GetImageGeometry()); - boundingGeometry->SetOrigin(geometry->GetOrigin()); - boundingGeometry->SetSpacing(geometry->GetSpacing()); - boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()); - boundingGeometry->Modified(); - return boundingGeometry; -} - -QString QmitkImageCropper::AdaptBoundingObjectName(const QString& name) const -{ - unsigned int counter = 2; - QString newName = QString("%1 %2").arg(name).arg(counter); - - while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node) - { - return 0 == node->GetName().compare(newName.toStdString()); - }))) - { - newName = QString("%1 %2").arg(name).arg(++counter); - } - - return newName; -} - -void QmitkImageCropper::DoCreateNewBoundingObject() -{ - if (!m_ImageNode.IsExpired()) - { - auto imageNode = m_ImageNode.Lock(); - QString name = QString::fromStdString(imageNode->GetName() + " Bounding Shape"); - - auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node) - { - return 0 == node->GetName().compare(name.toStdString()); - })); - - if (nullptr != boundingShape) - name = this->AdaptBoundingObjectName(name); - - m_Controls.buttonCropping->setEnabled(true); - m_Controls.buttonMasking->setEnabled(true); - m_Controls.boundingShapeSelector->setEnabled(true); - m_Controls.groupImageSettings->setEnabled(true); - - // get current timestep to support 3d+t images - auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); - int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); - mitk::BaseGeometry::Pointer imageGeometry = static_cast(imageNode->GetData()->GetGeometry(timeStep)); - - m_CroppingObject = mitk::GeometryData::New(); - m_CroppingObject->SetGeometry(static_cast(this->InitializeWithImageGeometry(imageGeometry))); - m_CroppingObjectNode = mitk::DataNode::New(); - m_CroppingObjectNode->SetData(m_CroppingObject); - m_CroppingObjectNode->SetProperty("name", mitk::StringProperty::New(name.toStdString())); - m_CroppingObjectNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); - m_CroppingObjectNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); - m_CroppingObjectNode->SetProperty("layer", mitk::IntProperty::New(99)); - m_CroppingObjectNode->AddProperty("handle size factor", mitk::DoubleProperty::New(1.0 / 40.0)); - m_CroppingObjectNode->SetBoolProperty("pickable", true); - - if (!this->GetDataStorage()->Exists(m_CroppingObjectNode)) - { - GetDataStorage()->Add(m_CroppingObjectNode, imageNode); - m_Controls.boundingShapeSelector->SetSelectedNode(m_CroppingObjectNode); - m_CroppingObjectNode->SetVisibility(true); - m_BoundingShapeInteractor->EnableInteraction(true); - m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); - this->OnDataSelectionChanged(m_CroppingObjectNode); - } - } - // Adjust coordinate system by doing a reinit on - auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); - tempDataStorage->InsertElement(0, m_CroppingObjectNode); - - //// initialize the views to the bounding geometry - //mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); - //mitk::RenderingManager::GetInstance()->InitializeViews(bounds); - //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} -void QmitkImageCropper::setDefaultGUI() -{ - m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); - m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); - m_Controls.labelWarningImage->setVisible(true); - m_Controls.labelWarningBB->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); - m_Controls.labelWarningBB->setText(QString::fromStdString("Create a bounding shape below.")); - m_Controls.labelWarningBB->setVisible(true); - m_Controls.buttonCreateNewBoundingBox->setEnabled(false); - m_Controls.labelWarningRotation->setVisible(false); - m_Controls.buttonCropping->setEnabled(false); - m_Controls.buttonMasking->setEnabled(false); - m_Controls.boundingShapeSelector->setEnabled(false); - m_Controls.buttonAdvancedSettings->setEnabled(false); - m_Controls.groupImageSettings->setEnabled(false); - m_Controls.checkOverwriteImage->setChecked(false); - m_Controls.checkBoxCropTimeStepOnly->setChecked(false); -} - -void QmitkImageCropper::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, - const QList& nodes) -{ - bool rotationEnabled = false; - if (nodes.empty()) - { - setDefaultGUI(); - return; - } - m_ParentWidget->setEnabled(true); - - foreach(mitk::DataNode::Pointer node, nodes) - { - if (node.IsNotNull() && dynamic_cast(node->GetData())) - { - m_ImageNode = nodes[0]; - m_Controls.groupBoundingObject->setEnabled(true); - m_Controls.labelWarningImage->setStyleSheet(""); - m_Controls.labelWarningImage->setText(QString::fromStdString("Selected image: " + nodes[0]->GetName())); - m_Controls.buttonCreateNewBoundingBox->setEnabled(true); - - mitk::Image::Pointer image = dynamic_cast(nodes[0]->GetData()); - if (image != nullptr) - { - if (image->GetDimension() < 3) { - QMessageBox::warning(nullptr, - tr("Invalid image selected"), - tr("ImageCropper only works with 3 or more dimensions."), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); - setDefaultGUI(); - return; - } - - vtkSmartPointer imageMat = image->GetGeometry()->GetVtkMatrix(); - // check whether the image geometry is rotated, if so, no pixel aligned cropping or masking can be performed - if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) && - (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) && - (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0)) - { - rotationEnabled = false; - m_Controls.labelWarningRotation->setVisible(false); - } - else - { - rotationEnabled = true; - m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); - m_Controls.labelWarningRotation->setVisible(true); - } - - this->CreateBoundingShapeInteractor(rotationEnabled); - m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); - if (m_CroppingObjectNode != nullptr) - { - this->OnDataSelectionChanged(m_CroppingObjectNode); - m_BoundingShapeInteractor->EnableInteraction(true); - m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); - m_Controls.boundingShapeSelector->setEnabled(true); - } - - if (image->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) - { - // Might be changed with the upcoming new image statistics plugin - //(recomputation might be very expensive for large images ;) ) - auto statistics = image->GetStatistics(); - auto minPixelValue = statistics->GetScalarValueMin(); - auto maxPixelValue = statistics->GetScalarValueMax(); - - if (minPixelValue < std::numeric_limits::min()) { - minPixelValue = std::numeric_limits::min(); - } - if (maxPixelValue > std::numeric_limits::max()) { - maxPixelValue = std::numeric_limits::max(); - } - - m_Controls.spinBoxOutsidePixelValue->setEnabled(true); - m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast(maxPixelValue)); - m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast(minPixelValue)); - m_Controls.spinBoxOutsidePixelValue->setValue(static_cast(minPixelValue)); - } - else - { - m_Controls.spinBoxOutsidePixelValue->setEnabled(false); - } - - unsigned int dim = image->GetDimension(); - if (dim < 2 || dim > 4) - { - m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); - m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); - m_ParentWidget->setEnabled(false); - } - if (m_CroppingObjectNode != nullptr) - { - m_Controls.buttonCropping->setEnabled(true); - m_Controls.buttonMasking->setEnabled(true); - m_Controls.boundingShapeSelector->setEnabled(true); - m_Controls.labelWarningBB->setVisible(false); - } - else - { - m_Controls.buttonCropping->setEnabled(false); - m_Controls.buttonMasking->setEnabled(false); - m_Controls.boundingShapeSelector->setEnabled(false); - m_Controls.labelWarningBB->setVisible(true); - } - return; - } - // iterate all selected objects, adjust warning visibility - setDefaultGUI(); - m_ParentWidget->setEnabled(true); - m_Controls.labelWarningRotation->setVisible(false); - } - } -} - -void QmitkImageCropper::OnComboBoxSelectionChanged(const mitk::DataNode* node) -{ - mitk::DataNode* selectedNode = const_cast(node); - if (selectedNode != nullptr) - { - if (!m_ImageNode.IsExpired()) - selectedNode->SetDataInteractor(m_ImageNode.Lock()->GetDataInteractor()); - // m_ImageNode->GetDataInteractor()->SetDataNode(selectedNode); - m_ImageNode = selectedNode; - } -} - -void QmitkImageCropper::OnSliderValueChanged(int slidervalue) -{ - m_CropOutsideValue = slidervalue; -} - -void QmitkImageCropper::DoMasking() -{ - this->ProcessImage(true); -} - -void QmitkImageCropper::DoCropping() -{ - this->ProcessImage(false); -} - -void QmitkImageCropper::ProcessImage(bool mask) -{ - // cropping only possible if valid bounding shape as well as a valid image are loaded - QList nodes = this->GetDataManagerSelection(); - - auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); - int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); - - if (nodes.empty()) return; - - mitk::DataNode* node = nodes[0]; - - if (node == nullptr) - { - QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); - return; - } - if (m_CroppingObject == nullptr) - { - QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing."); - return; - } - - mitk::BaseData* data = node->GetData(); //get data from node - if (data != nullptr) - { - QString imageName; - if (mask) - { - imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_masked"); - } - else - { - imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_cropped"); - } - - if (m_Controls.checkBoxCropTimeStepOnly->isChecked()) - { - imageName = imageName + "_T" + QString::number(timeStep); - } - - // image and bounding shape ok, set as input - auto croppedImageNode = mitk::DataNode::New(); - auto cutter = mitk::BoundingShapeCropper::New(); - cutter->SetGeometry(m_CroppingObject); - - // adjustable in advanced settings - cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false) - cutter->SetOutsideValue(m_CropOutsideValue); - cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked()); - cutter->SetCurrentTimeStep(timeStep); - - // TODO: Add support for MultiLayer (right now only Mulitlabel support) - mitk::LabelSetImage* labelsetImageInput = dynamic_cast(data); - if (labelsetImageInput != nullptr) - { - cutter->SetInput(labelsetImageInput); - // do the actual cutting - try - { - cutter->Update(); - } - catch (const itk::ExceptionObject& e) - { - std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); - QMessageBox::warning(nullptr, - tr("Cropping not possible!"), - tr(message.c_str()), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); - return; - } - - auto labelSetImage = mitk::LabelSetImage::New(); - labelSetImage->InitializeByLabeledImage(cutter->GetOutput()); - - for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++) - { - labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i)); - } - - croppedImageNode->SetData(labelSetImage); - croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); - - //add cropping result to the current data storage as child node to the image node - if (!m_Controls.checkOverwriteImage->isChecked()) - { - if (!this->GetDataStorage()->Exists(croppedImageNode)) - { - this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); - } - } - else // original image will be overwritten by the result image and the bounding box of the result is adjusted - { - node->SetData(labelSetImage); - node->Modified(); - // Adjust coordinate system by doing a reinit on - auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); - tempDataStorage->InsertElement(0, node); - - // initialize the views to the bounding geometry - auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); - mitk::RenderingManager::GetInstance()->InitializeViews(bounds); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - else - { - mitk::Image::Pointer imageInput = dynamic_cast(data); - if (imageInput != nullptr) - { - cutter->SetInput(imageInput); - // do the actual cutting - try - { - cutter->Update(); - } - catch (const itk::ExceptionObject& e) - { - std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); - - QMessageBox::warning(nullptr, - tr("Cropping not possible!"), - tr(message.c_str()), - QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); - return; - } - - //add cropping result to the current data storage as child node to the image node - if (!m_Controls.checkOverwriteImage->isChecked()) - { - croppedImageNode->SetData(cutter->GetOutput()); - croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); - croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); - croppedImageNode->SetProperty("layer", mitk::IntProperty::New(99)); // arbitrary, copied from segmentation functionality - if (!this->GetDataStorage()->Exists(croppedImageNode)) - { - this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); - } - } - else // original image will be overwritten by the result image and the bounding box of the result is adjusted - { - node->SetData(cutter->GetOutput()); - node->Modified(); - // Adjust coordinate system by doing a reinit on - auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); - tempDataStorage->InsertElement(0, node); - - // initialize the views to the bounding geometry - auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); - mitk::RenderingManager::GetInstance()->InitializeViews(bounds); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); - } - } - } - } - else - { - QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); - } -} diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h deleted file mode 100644 index e08159b841..0000000000 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h +++ /dev/null @@ -1,168 +0,0 @@ -/*============================================================================ - -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 QmitkImageCropper_h -#define QmitkImageCropper_h - -#include - -#ifdef WIN32 -#pragma warning( disable : 4250 ) -#endif - -#include -#include "QmitkRegisterClasses.h" -#include - -#include "itkCommand.h" -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "ui_ImageCropperControls.h" - -#include "usServiceRegistration.h" - -/*! -@brief QmitkImageCropperView -\warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. - -\sa QmitkFunctionality -\ingroup ${plugin_target}_internal -*/ -class QmitkImageCropper : public QmitkAbstractView -{ - // this is needed for all Qt objects that should have a Qt meta-object - // (everything that derives from QObject and wants to have signal/slots) -private: - - Q_OBJECT - -public: - /*! - @brief Constructor. Called by SampleApp (or other apps that use functionalities) - */ - QmitkImageCropper(QObject *parent = nullptr); - - ~QmitkImageCropper() override; - - static const std::string VIEW_ID; - - void CreateQtPartControl(QWidget *parent) override; - - void SetFocus() override; - - /*! - @brief Creates the Qt connections needed - */ - - QWidget* GetControls(); - - /// @brief Called when the user clicks the GUI button - protected slots: - /*! - * @brief Creates a new bounding object - */ - virtual void DoCreateNewBoundingObject(); - /*! - * @brief Whenever Crop button is pressed, issue a cropping action - */ - void DoCropping(); - /*! - * @brief Whenever Mask button is pressed, issue a masking action - */ - void DoMasking(); - /*! - * @brief Dis- or enable the advanced setting section - */ - void OnAdvancedSettingsButtonToggled(); - /*! - * @brief Updates current selection of the bounding object - */ - void OnDataSelectionChanged(const mitk::DataNode* node); - /*! - * @brief Sets the scalar value for outside pixels in case of masking - */ - void OnSliderValueChanged(int slidervalue); - -protected: - - /*! - @brief called by QmitkFunctionality when DataManager's selection has changed - */ - void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; - /*! - @brief Sets the selected bounding object as current bounding object and set up interactor - */ - void OnComboBoxSelectionChanged(const mitk::DataNode* node); - /*! - * @brief Initializes a new bounding shape using the selected image geometry. - */ - mitk::Geometry3D::Pointer InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry); - - void CreateBoundingShapeInteractor(bool rotationEnabled); - -private: - - /*! - * The parent QWidget - */ - QWidget* m_ParentWidget; - /*! - * @brief A pointer to the node of the image to be cropped. - */ - mitk::WeakPointer m_ImageNode; - /*! - * @brief The cuboid used for cropping. - */ - mitk::GeometryData::Pointer m_CroppingObject; - - /*! - * @brief Tree node of the cuboid used for cropping. - */ - mitk::DataNode::Pointer m_CroppingObjectNode; - - /*! - * @brief Interactor for moving and scaling the cuboid - */ - mitk::BoundingShapeInteractor::Pointer m_BoundingShapeInteractor; - - void ProcessImage(bool crop); - - /*! - * @brief Resets GUI to default - */ - void setDefaultGUI(); - - QString AdaptBoundingObjectName(const QString& name) const; - - // cropping parameter - mitk::ScalarType m_CropOutsideValue; - bool m_Advanced; - bool m_Active; - bool m_ScrollEnabled; - - Ui::ImageCropperControls m_Controls; -}; - -#endif // QmitkImageCropper_h diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp new file mode 100644 index 0000000000..22e9fb3954 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.cpp @@ -0,0 +1,484 @@ +/*============================================================================ + +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 "QmitkImageCropperView.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +const std::string QmitkImageCropperView::VIEW_ID = "org.mitk.views.qmitkimagecropper"; + +QmitkImageCropperView::QmitkImageCropperView(QObject *) + : m_ParentWidget(nullptr) + , m_BoundingShapeInteractor(nullptr) + , m_CropOutsideValue(0) +{ + CreateBoundingShapeInteractor(false); +} + +QmitkImageCropperView::~QmitkImageCropperView() +{ + //disable interactor + if (m_BoundingShapeInteractor != nullptr) + { + m_BoundingShapeInteractor->SetDataNode(nullptr); + m_BoundingShapeInteractor->EnableInteraction(false); + } +} + +void QmitkImageCropperView::CreateQtPartControl(QWidget *parent) +{ + // create GUI widgets from the Qt Designer's .ui file + m_Controls.setupUi(parent); + + m_Controls.imageSelectionWidget->SetDataStorage(GetDataStorage()); + m_Controls.imageSelectionWidget->SetNodePredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); + m_Controls.imageSelectionWidget->SetSelectionIsOptional(true); + m_Controls.imageSelectionWidget->SetEmptyInfo(QString("Please select an image node")); + m_Controls.imageSelectionWidget->SetPopUpTitel(QString("Select image node")); + + connect(m_Controls.imageSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkImageCropperView::OnImageSelectionChanged); + + m_Controls.boundingBoxSelectionWidget->SetDataStorage(GetDataStorage()); + m_Controls.boundingBoxSelectionWidget->SetNodePredicate(mitk::NodePredicateAnd::New( + mitk::TNodePredicateDataType::New(), + mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); + m_Controls.boundingBoxSelectionWidget->SetSelectionIsOptional(true); + m_Controls.boundingBoxSelectionWidget->SetEmptyInfo(QString("Please select a bounding box")); + m_Controls.boundingBoxSelectionWidget->SetPopUpTitel(QString("Select bounding box node")); + + connect(m_Controls.boundingBoxSelectionWidget, &QmitkSingleNodeSelectionWidget::CurrentSelectionChanged, + this, &QmitkImageCropperView::OnBoundingBoxSelectionChanged); + + connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(OnCreateNewBoundingBox())); + connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(OnCropping())); + connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(OnMasking())); + auto lambda = [this]() + { + m_Controls.groupImageSettings->setVisible(!m_Controls.groupImageSettings->isVisible()); + }; + + connect(m_Controls.buttonAdvancedSettings, &ctkExpandButton::clicked, this, lambda); + + connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); + + SetDefaultGUI(); + + m_ParentWidget = parent; +} + +void QmitkImageCropperView::OnImageSelectionChanged(QList) +{ + bool rotationEnabled = false; + auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); + if (imageNode.IsNull()) + { + SetDefaultGUI(); + return; + } + + auto image = dynamic_cast(imageNode->GetData()); + if (nullptr != image) + { + if (image->GetDimension() < 3) + { + QMessageBox::warning(nullptr, + tr("Invalid image selected"), + tr("ImageCropper only works with 3 or more dimensions."), + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + SetDefaultGUI(); + return; + } + + m_ParentWidget->setEnabled(true); + m_Controls.buttonCreateNewBoundingBox->setEnabled(true); + + vtkSmartPointer imageMat = image->GetGeometry()->GetVtkMatrix(); + // check whether the image geometry is rotated; if so, no pixel aligned cropping or masking can be performed + if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) && + (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) && + (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0)) + { + rotationEnabled = false; + m_Controls.labelWarningRotation->setVisible(false); + } + else + { + rotationEnabled = true; + m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); + m_Controls.labelWarningRotation->setVisible(true); + } + + this->CreateBoundingShapeInteractor(rotationEnabled); + + if (itk::ImageIOBase::SCALAR == image->GetPixelType().GetPixelType()) + { + // Might be changed with the upcoming new image statistics plugin + //(recomputation might be very expensive for large images ;) ) + auto statistics = image->GetStatistics(); + auto minPixelValue = statistics->GetScalarValueMin(); + auto maxPixelValue = statistics->GetScalarValueMax(); + + if (minPixelValue < std::numeric_limits::min()) + { + minPixelValue = std::numeric_limits::min(); + } + if (maxPixelValue > std::numeric_limits::max()) + { + maxPixelValue = std::numeric_limits::max(); + } + + m_Controls.spinBoxOutsidePixelValue->setEnabled(true); + m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast(maxPixelValue)); + m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast(minPixelValue)); + m_Controls.spinBoxOutsidePixelValue->setValue(static_cast(minPixelValue)); + } + else + { + m_Controls.spinBoxOutsidePixelValue->setEnabled(false); + } + + unsigned int dim = image->GetDimension(); + if (dim < 2 || dim > 4) + { + m_ParentWidget->setEnabled(false); + } + + if (m_Controls.boundingBoxSelectionWidget->GetSelectedNode().IsNotNull()) + { + m_Controls.buttonCropping->setEnabled(true); + m_Controls.buttonMasking->setEnabled(true); + m_Controls.buttonAdvancedSettings->setEnabled(true); + m_Controls.groupImageSettings->setEnabled(true); + } + } +} + +void QmitkImageCropperView::OnBoundingBoxSelectionChanged(QList) +{ + auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode(); + if (boundingBoxNode.IsNull()) + { + SetDefaultGUI(); + + m_BoundingShapeInteractor->EnableInteraction(false); + m_BoundingShapeInteractor->SetDataNode(nullptr); + + if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull()) + { + m_Controls.buttonCreateNewBoundingBox->setEnabled(true); + } + + return; + } + + auto boundingBox = dynamic_cast(boundingBoxNode->GetData()); + if (nullptr != boundingBox) + { + // node newly selected + boundingBoxNode->SetVisibility(true); + + m_BoundingShapeInteractor->EnableInteraction(true); + m_BoundingShapeInteractor->SetDataNode(boundingBoxNode); + + mitk::RenderingManager::GetInstance()->InitializeViews(); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + + if (m_Controls.imageSelectionWidget->GetSelectedNode().IsNotNull()) + { + m_Controls.buttonCropping->setEnabled(true); + m_Controls.buttonMasking->setEnabled(true); + m_Controls.buttonAdvancedSettings->setEnabled(true); + m_Controls.groupImageSettings->setEnabled(true); + } + } +} + +void QmitkImageCropperView::OnCreateNewBoundingBox() +{ + auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); + if (imageNode.IsNull()) + { + return; + } + + + QString name = QString::fromStdString(imageNode->GetName() + " Bounding Shape"); + + auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node) + { + return 0 == node->GetName().compare(name.toStdString()); + })); + + if (nullptr != boundingShape) + { + name = this->AdaptBoundingObjectName(name); + } + + // get current timestep to support 3d+t images + auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); + int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); + auto imageGeometry = static_cast(imageNode->GetData()->GetGeometry(timeStep)); + + auto boundingBox = mitk::GeometryData::New(); + boundingBox->SetGeometry(static_cast(this->InitializeWithImageGeometry(imageGeometry))); + auto boundingBoxNode = mitk::DataNode::New(); + boundingBoxNode->SetData(boundingBox); + boundingBoxNode->SetProperty("name", mitk::StringProperty::New(name.toStdString())); + boundingBoxNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); + boundingBoxNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); + boundingBoxNode->SetProperty("layer", mitk::IntProperty::New(99)); + boundingBoxNode->AddProperty("handle size factor", mitk::DoubleProperty::New(1.0 / 40.0)); + boundingBoxNode->SetBoolProperty("pickable", true); + + if (!this->GetDataStorage()->Exists(boundingBoxNode)) + { + GetDataStorage()->Add(boundingBoxNode, imageNode); + } + + m_Controls.boundingBoxSelectionWidget->SetCurrentSelectedNode(boundingBoxNode); +} + +void QmitkImageCropperView::OnCropping() +{ + this->ProcessImage(false); +} + +void QmitkImageCropperView::OnMasking() +{ + this->ProcessImage(true); +} + +void QmitkImageCropperView::OnSliderValueChanged(int slidervalue) +{ + m_CropOutsideValue = slidervalue; +} + +void QmitkImageCropperView::CreateBoundingShapeInteractor(bool rotationEnabled) +{ + if (m_BoundingShapeInteractor.IsNull()) + { + m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New(); + m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); + m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); + } + m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled); +} + +mitk::Geometry3D::Pointer QmitkImageCropperView::InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry) +{ + // convert a BaseGeometry into a Geometry3D (otherwise IO is not working properly) + if (geometry == nullptr) + mitkThrow() << "Geometry is not valid."; + + auto boundingGeometry = mitk::Geometry3D::New(); + boundingGeometry->SetBounds(geometry->GetBounds()); + boundingGeometry->SetImageGeometry(geometry->GetImageGeometry()); + boundingGeometry->SetOrigin(geometry->GetOrigin()); + boundingGeometry->SetSpacing(geometry->GetSpacing()); + boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()); + boundingGeometry->Modified(); + return boundingGeometry; +} + +void QmitkImageCropperView::ProcessImage(bool mask) +{ + auto renderWindowPart = this->GetRenderWindowPart(mitk::WorkbenchUtil::IRenderWindowPartStrategy::OPEN); + int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); + + auto imageNode = m_Controls.imageSelectionWidget->GetSelectedNode(); + if (imageNode.IsNull()) + { + QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); + return; + } + + auto boundingBoxNode = m_Controls.boundingBoxSelectionWidget->GetSelectedNode(); + if (boundingBoxNode.IsNull()) + { + QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing."); + return; + } + + auto image = dynamic_cast(imageNode->GetData()); + auto boundingBox = dynamic_cast(boundingBoxNode->GetData()); + if (nullptr != image && nullptr != boundingBox) + { + QString imageName; + if (mask) + { + imageName = QString::fromStdString(imageNode->GetName() + "_" + boundingBoxNode->GetName() + "_masked"); + } + else + { + imageName = QString::fromStdString(imageNode->GetName() + "_" + boundingBoxNode->GetName() + "_cropped"); + } + + if (m_Controls.checkBoxCropTimeStepOnly->isChecked()) + { + imageName = imageName + "_T" + QString::number(timeStep); + } + + // image and bounding shape ok, set as input + auto croppedImageNode = mitk::DataNode::New(); + auto cutter = mitk::BoundingShapeCropper::New(); + cutter->SetGeometry(boundingBox); + + // adjustable in advanced settings + cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false) + cutter->SetOutsideValue(m_CropOutsideValue); + cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked()); + cutter->SetCurrentTimeStep(timeStep); + + // TODO: Add support for MultiLayer (right now only Mulitlabel support) + auto labelsetImageInput = dynamic_cast(image); + if (nullptr != labelsetImageInput) + { + cutter->SetInput(labelsetImageInput); + // do the actual cutting + try + { + cutter->Update(); + } + catch (const itk::ExceptionObject& e) + { + std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); + QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + return; + } + + auto labelSetImage = mitk::LabelSetImage::New(); + labelSetImage->InitializeByLabeledImage(cutter->GetOutput()); + + for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++) + { + labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i)); + } + + croppedImageNode->SetData(labelSetImage); + croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); + + //add cropping result to the current data storage as child node to the image node + if (!m_Controls.checkOverwriteImage->isChecked()) + { + if (!this->GetDataStorage()->Exists(croppedImageNode)) + { + this->GetDataStorage()->Add(croppedImageNode, imageNode); + } + } + else // original image will be overwritten by the result image and the bounding box of the result is adjusted + { + imageNode->SetData(labelSetImage); + imageNode->Modified(); + // Adjust coordinate system by doing a reinit on + auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); + tempDataStorage->InsertElement(0, imageNode); + + // initialize the views to the bounding geometry + auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); + mitk::RenderingManager::GetInstance()->InitializeViews(bounds); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } + else + { + cutter->SetInput(image); + // do the actual cutting + try + { + cutter->Update(); + } + catch (const itk::ExceptionObject& e) + { + std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); + QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), + QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); + return; + } + + //add cropping result to the current data storage as child node to the image node + if (!m_Controls.checkOverwriteImage->isChecked()) + { + croppedImageNode->SetData(cutter->GetOutput()); + croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); + croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); + croppedImageNode->SetProperty("layer", mitk::IntProperty::New(99)); // arbitrary, copied from segmentation functionality + if (!this->GetDataStorage()->Exists(croppedImageNode)) + { + this->GetDataStorage()->Add(croppedImageNode, imageNode); + } + } + else // original image will be overwritten by the result image and the bounding box of the result is adjusted + { + imageNode->SetData(cutter->GetOutput()); + imageNode->Modified(); + // Adjust coordinate system by doing a reinit on + auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); + tempDataStorage->InsertElement(0, imageNode); + + // initialize the views to the bounding geometry + auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); + mitk::RenderingManager::GetInstance()->InitializeViews(bounds); + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); + } + } + } + else + { + QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); + } +} + +void QmitkImageCropperView::SetDefaultGUI() +{ + m_Controls.labelWarningRotation->setVisible(false); + m_Controls.buttonCreateNewBoundingBox->setEnabled(false); + m_Controls.buttonCropping->setEnabled(false); + m_Controls.buttonMasking->setEnabled(false); + m_Controls.buttonAdvancedSettings->setEnabled(false); + m_Controls.groupImageSettings->setEnabled(false); + m_Controls.groupImageSettings->setVisible(false); + m_Controls.checkOverwriteImage->setChecked(false); + m_Controls.checkBoxCropTimeStepOnly->setChecked(false); +} + +QString QmitkImageCropperView::AdaptBoundingObjectName(const QString& name) const +{ + unsigned int counter = 2; + QString newName = QString("%1 %2").arg(name).arg(counter); + + while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node) + { + return 0 == node->GetName().compare(newName.toStdString()); + }))) + { + newName = QString("%1 %2").arg(name).arg(++counter); + } + + return newName; +} diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.h new file mode 100644 index 0000000000..7bd77de7de --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperView.h @@ -0,0 +1,90 @@ +/*============================================================================ + +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 QmitkImageCropperView_h +#define QmitkImageCropperView_h + +#include + +#include + +#include "ui_QmitkImageCropperViewControls.h" + +class QmitkImageCropperView : public QmitkAbstractView +{ + + Q_OBJECT + +public: + + static const std::string VIEW_ID; + + QmitkImageCropperView(QObject *parent = nullptr); + + ~QmitkImageCropperView() override; + + void CreateQtPartControl(QWidget *parent) override; + + void SetFocus() override { }; + +protected Q_SLOTS: + + /*! + * @brief Updates current selection of the image to crop + */ + void OnImageSelectionChanged(QList nodes); + /*! + * @brief Updates current selection of the bounding object + */ + void OnBoundingBoxSelectionChanged(QList nodes); + /*! + * @brief Creates a new bounding object + */ + void OnCreateNewBoundingBox(); + /*! + * @brief Whenever Crop button is pressed, issue a cropping action + */ + void OnCropping(); + /*! + * @brief Whenever Mask button is pressed, issue a masking action + */ + void OnMasking(); + /*! + * @brief Sets the scalar value for outside pixels in case of masking + */ + void OnSliderValueChanged(int slidervalue); + +private: + + void CreateBoundingShapeInteractor(bool rotationEnabled); + + // initializes a new bounding shape using the selected image geometry. + mitk::Geometry3D::Pointer InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry); + + void ProcessImage(bool crop); + + void SetDefaultGUI(); + + QString AdaptBoundingObjectName(const QString& name) const; + + QWidget* m_ParentWidget; + + // interactor for moving and scaling the cuboid + mitk::BoundingShapeInteractor::Pointer m_BoundingShapeInteractor; + + // cropping parameter + mitk::ScalarType m_CropOutsideValue; + + Ui::QmitkImageCropperViewControls m_Controls; +}; + +#endif // QmitkImageCropperView_h diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperViewControls.ui b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperViewControls.ui new file mode 100644 index 0000000000..d7e2d78d35 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropperViewControls.ui @@ -0,0 +1,311 @@ + + + QmitkImageCropperViewControls + + + + 0 + 0 + 300 + 600 + + + + + + + + 0 + 0 + + + + Data Selection + + + + + + + 0 + 0 + + + + Image + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + + + + + 0 + 0 + + + + Bounding Box + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + + + + + + 0 + 0 + + + + + 0 + 40 + + + + New + + + + + + + + + + + 0 + 0 + + + + + 0 + 90 + + + + Processing + + + + + + + 0 + 0 + + + + Mask + + + + + + + + 0 + 0 + + + + Crop + + + + + + + + + + true + + + Image geometry is rotated, result won't be pixel-aligned. You can reinit your image to get a pixel-aligned result, though. + + + Qt::PlainText + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + Advanced settings + + + false + + + 100 + + + Qt::ToolButtonTextBesideIcon + + + false + + + + + + + + 0 + 0 + + + + + 0 + 120 + + + + Output image settings + + + + + + + + + 0 + 0 + + + + Outside pixel value (masking): + + + + + + + false + + + + 0 + 0 + + + + + + + + + + + 0 + 0 + + + + Overrride original image + + + false + + + + + + + + 0 + 0 + + + + Only crop current timestep +/ cut off other timesteps + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+
+ + ctkExpandButton + QToolButton +
ctkExpandButton.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.cpp similarity index 61% rename from Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp rename to Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.cpp index 962f14838f..0902061f1c 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.cpp @@ -1,26 +1,26 @@ /*============================================================================ 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 -#include "org_mitk_gui_qt_imagecropper_Activator.h" -#include "QmitkImageCropper.h" +#include "mitkPluginActivator.h" +#include "QmitkImageCropperView.h" -void mitk::org_mitk_gui_qt_imagecropper_Activator::start(ctkPluginContext* context) +void mitk::mitkPluginActivator::start(ctkPluginContext* context) { RegisterBoundingShapeObjectFactory(); - BERRY_REGISTER_EXTENSION_CLASS(QmitkImageCropper, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkImageCropperView, context) } -void mitk::org_mitk_gui_qt_imagecropper_Activator::stop(ctkPluginContext*) +void mitk::mitkPluginActivator::stop(ctkPluginContext*) { } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.h similarity index 89% rename from Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h rename to Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.h index 565f56e693..d2be4791a3 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/mitkPluginActivator.h @@ -1,32 +1,32 @@ /*============================================================================ 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 org_mitk_gui_qt_imagecropper_Activator_h #define org_mitk_gui_qt_imagecropper_Activator_h #include namespace mitk { - class org_mitk_gui_qt_imagecropper_Activator : public QObject, public ctkPluginActivator + class mitkPluginActivator : public QObject, public ctkPluginActivator { Q_OBJECT Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_imagecropper") Q_INTERFACES(ctkPluginActivator) public: void start(ctkPluginContext* context) override; void stop(ctkPluginContext* context) override; }; } #endif