diff --git a/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp b/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp index c460bbdd6d..432e4606fe 100644 --- a/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp +++ b/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp @@ -1,498 +1,433 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 14134 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include #include "QmitkImageCropper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkUndoController.h" #include "mitkBoundingObjectCutter.h" #include "mitkImageAccessByItk.h" #include "mitkITKImageImport.h" #include "mitkIDataStorageService.h" #include "mitkNodePredicateDataType.h" #include //to be moved to mitkInteractionConst.h by StateMachineEditor const mitk::OperationType QmitkImageCropper::OP_EXCHANGE = 717; // constructors for operation classes QmitkImageCropper::opExchangeNodes::opExchangeNodes( mitk::OperationType type, mitk::DataNode* node, mitk::BaseData* oldData, mitk::BaseData* newData ) :mitk::Operation(type),m_Node(node),m_OldData(oldData),m_NewData(newData), m_NodeDeletedObserverTag(0), m_OldDataDeletedObserverTag(0), m_NewDataDeletedObserverTag(0) { // listen to the node the image is hold itk::MemberCommand::Pointer nodeDeletedCommand = itk::MemberCommand::New(); nodeDeletedCommand->SetCallbackFunction(this, &opExchangeNodes::NodeDeleted); m_NodeDeletedObserverTag = m_Node->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); m_OldDataDeletedObserverTag = m_OldData->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); m_NewDataDeletedObserverTag = m_NewData->AddObserver(itk::DeleteEvent(), nodeDeletedCommand); } // destructor for operation class QmitkImageCropper::opExchangeNodes::~opExchangeNodes() { if (m_Node != NULL) { m_Node->RemoveObserver(m_NodeDeletedObserverTag); m_Node=NULL; } if (m_OldData.IsNotNull()) { m_OldData->RemoveObserver(m_OldDataDeletedObserverTag); m_OldData=NULL; } if (m_NewData.IsNotNull()) { m_NewData->RemoveObserver(m_NewDataDeletedObserverTag); m_NewData=NULL; } } void QmitkImageCropper::opExchangeNodes::NodeDeleted(const itk::Object * /*caller*/, const itk::EventObject &/*event*/) { m_Node = NULL; m_OldData = NULL; m_NewData = NULL; } QmitkImageCropper::QmitkImageCropper(QObject *parent) : m_Controls(NULL), m_ParentWidget(0) { m_Interface = new mitk::ImageCropperEventInterface; m_Interface->SetImageCropper( this ); } QmitkImageCropper::~QmitkImageCropper() { //delete smart pointer objects m_CroppingObjectNode = NULL; m_CroppingObject = NULL; m_Interface->Delete(); } void QmitkImageCropper::CreateQtPartControl(QWidget* parent) { if (!m_Controls) { m_ParentWidget = parent; // build ui elements m_Controls = new Ui::QmitkImageCropperControls; m_Controls->setupUi(parent); // setup ui elements m_Controls->groupInfo->hide(); m_Controls->m_SurroundingSlider->hide(); m_Controls->m_SurroundingSpin->hide(); m_Controls->m_NewBoxButton->setEnabled(true); // create ui element connections this->CreateConnections(); } } void QmitkImageCropper::CreateConnections() { if ( m_Controls ) { connect( m_Controls->btnCrop, SIGNAL(clicked()), this, SLOT(CropImage())); // click on the crop button connect( m_Controls->m_NewBoxButton, SIGNAL(clicked()), this, SLOT(CreateNewBoundingObject()) ); connect( m_Controls->m_EnableSurroundingCheckBox, SIGNAL(toggled(bool)), this, SLOT(SurroundingCheck(bool)) ); connect( m_Controls->chkInformation, SIGNAL(toggled(bool)), this, SLOT(ChkInformationToggled(bool)) ); } } void QmitkImageCropper::Activated() { QmitkFunctionality::Activated(); // just call the inherited function } void QmitkImageCropper::Deactivated() { RemoveBoundingObjectFromNode(); QmitkFunctionality::Deactivated(); // just call the inherited function mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } /*! When called with an opExchangeNodes, it changes the content of a node from one data set to another */ void QmitkImageCropper::ExecuteOperation (mitk::Operation *operation) { if (!operation) return; switch (operation->GetOperationType()) { case OP_EXCHANGE: { //RemoveBoundingObjectFromNode(); opExchangeNodes* op = static_cast(operation); op->GetNode()->SetData(op->GetNewData()); mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); break; } default:; } } void QmitkImageCropper::CreateNewBoundingObject() { // attach the cuboid to the image and update the views if (this->IsVisible()) { if (m_ImageNode.IsNotNull()) { m_ImageToCrop = dynamic_cast(m_ImageNode->GetData()); if(m_ImageToCrop.IsNotNull()) { if (this->GetDefaultDataStorage()->GetNamedDerivedNode("CroppingObject", m_ImageNode)) { // We are in "Reset bounding box!" mode m_CroppingObject->FitGeometry(m_ImageToCrop->GetTimeSlicedGeometry()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); return; } bool fitCroppingObject = false; if(m_CroppingObject.IsNull()) { CreateBoundingObject(); fitCroppingObject = true; } if (m_CroppingObject.IsNull()) return; AddBoundingObjectToNode( m_ImageNode, fitCroppingObject ); m_ImageNode->SetVisibility(true); mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_Controls->m_NewBoxButton->setText("Reset bounding box!"); m_Controls->btnCrop->setEnabled(true); } } else QMessageBox::information(NULL, "Image cropping functionality", "Load an image first!"); } } void QmitkImageCropper::SurroundingCheck(bool value) { if(value) { if(m_ImageNode.IsNotNull()) { mitk::DataNode *imageNode = m_ImageNode.GetPointer(); if (imageNode) { mitk::BaseData* data = imageNode->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { float min = 10000.0; float max = -10000.0; min = image->GetScalarValueMin(); max = image->GetScalarValueMax(); m_Controls->m_SurroundingSlider->setRange((int)min,(int)max); m_Controls->m_SurroundingSpin->setRange((int)min,(int)max); } } } m_Controls->m_SurroundingSlider->show(); m_Controls->m_SurroundingSpin->show(); } else m_Controls->m_EnableSurroundingCheckBox->setChecked(false); } else { m_Controls->m_SurroundingSlider->hide(); m_Controls->m_SurroundingSpin->hide(); } } void QmitkImageCropper::CropImage() { // test, if image is selected if (m_ImageToCrop.IsNull()) return; // test, if bounding box is visible if (m_CroppingObjectNode.IsNull()) { QMessageBox::information(NULL, "Image cropping functionality", "Generate a new bounding object first!"); return; } // image and bounding object ok mitk::BoundingObjectCutter::Pointer cutter = mitk::BoundingObjectCutter::New(); cutter->SetBoundingObject( m_CroppingObject ); cutter->SetInput( m_ImageToCrop ); cutter->AutoOutsideValueOff(); + if (m_Controls->m_EnableSurroundingCheckBox->isChecked()) + { + cutter->SetOutsideValue(m_Controls->m_SurroundingSpin->value()); + } + // do the actual cutting try { cutter->Update(); //cutter->UpdateLargestPossibleRegion(); } catch(itk::ExceptionObject&) { QMessageBox::warning ( NULL, tr("Cropping not possible"), tr("Sorry, the bounding box has to be completely inside the image.\n\n" "The possibility to drag it larger than the image is a bug and has to be fixed."), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton ); return; } // cutting successful mitk::Image::Pointer resultImage = cutter->GetOutput(); resultImage->DisconnectPipeline(); - if(m_Controls->m_EnableSurroundingCheckBox->isChecked()) - { - AccessByItk_1( resultImage, AddSurrounding, resultImage); - resultImage = m_surrImage; - } - RemoveBoundingObjectFromNode(); { opExchangeNodes* doOp = new opExchangeNodes(OP_EXCHANGE, m_ImageNode.GetPointer(), m_ImageNode->GetData(), resultImage); opExchangeNodes* undoOp = new opExchangeNodes(OP_EXCHANGE, m_ImageNode.GetPointer(), resultImage, m_ImageNode->GetData()); // TODO: MITK doesn't recognize that a new event happens in the next line, // because nothing happens in the render window. // As a result the undo action will happen together with the last action // recognized by MITK. mitk::OperationEvent* operationEvent = new mitk::OperationEvent( m_Interface, doOp, undoOp, "Crop image"); mitk::UndoController::GetCurrentUndoModel()->SetOperationEvent( operationEvent ); // tell the undo controller about the action ExecuteOperation(doOp); // execute action } m_Controls->m_NewBoxButton->setEnabled(true); m_Controls->btnCrop->setEnabled(false); } -template < typename TPixel, unsigned int VImageDimension > -void QmitkImageCropper::AddSurrounding( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Image::Pointer image) -{ - typedef itk::Image< TPixel, VImageDimension > InputImageType; - - typename InputImageType::Pointer extended = InputImageType::New(); - typename InputImageType::IndexType start; - start[0]=0; - start[1]=0; - start[2]=0; - - unsigned int *dims = image->GetDimensions(); - typename InputImageType::SizeType size; - - size[0]=dims[0]; - size[1]=dims[1]; - size[2]=dims[2]; - - typename InputImageType::RegionType region; - region.SetSize(size); - region.SetIndex(start); - - extended->SetRegions(region); - extended->SetDirection(itkImage->GetDirection()); - extended->SetOrigin(itkImage->GetOrigin()); - extended->Allocate(); - - extended->SetSpacing(itkImage->GetSpacing()); - - typename InputImageType::IndexType idx; - - progress = new QProgressDialog( "Adding surrounding...", "Abort", 0, (size[0]-1), m_Parent); - progress->setLabelText("Image cropper"); - progress->show(); - - for (unsigned int i=0;iSetPixel(idx, m_Controls->m_SurroundingSpin->value()); - } - else - { - extended->SetPixel(idx, itkImage->GetPixel(idx)); - } - } - } - progress->setValue(i); - if ( progress->wasCanceled() ) - break; - } - m_surrImage = mitk::Image::New(); - m_surrImage = mitk::ImportItkImage(extended); - -} - void QmitkImageCropper::CreateBoundingObject() { QStringList items; items << tr("Cuboid") << tr("Ellipsoid") << tr("Cylinder") << tr("Cone"); bool ok; QString item = QInputDialog::getItem(m_Parent, tr("Select Bounding Object"), tr("Type of Bounding Object:"), items, 0, false, &ok); if (!ok) return; if (item == "Ellipsoid") m_CroppingObject = mitk::Ellipsoid::New(); else if(item == "Cylinder") m_CroppingObject = mitk::Cylinder::New(); else if (item == "Cone") m_CroppingObject = mitk::Cone::New(); else if (item == "Cuboid") m_CroppingObject = mitk::Cuboid::New(); else return; m_CroppingObjectNode = mitk::DataNode::New(); m_CroppingObjectNode->SetData( m_CroppingObject ); m_CroppingObjectNode->SetProperty( "name", mitk::StringProperty::New( "CroppingObject" ) ); m_CroppingObjectNode->SetProperty( "color", mitk::ColorProperty::New(1.0, 1.0, 0.0) ); m_CroppingObjectNode->SetProperty( "opacity", mitk::FloatProperty::New(0.4) ); m_CroppingObjectNode->SetProperty( "layer", mitk::IntProperty::New(99) ); // arbitrary, copied from segmentation functionality m_CroppingObjectNode->SetProperty( "helper object", mitk::BoolProperty::New(true) ); m_AffineInteractor = mitk::AffineInteractor::New("AffineInteractions ctrl-drag", m_CroppingObjectNode); } void QmitkImageCropper::OnSelectionChanged(std::vector nodes) { this->RemoveBoundingObjectFromNode(); if (nodes.size() != 1 || dynamic_cast(nodes[0]->GetData()) == 0) { m_ParentWidget->setEnabled(false); return; } m_ImageNode = nodes[0]; m_ParentWidget->setEnabled(true); } void QmitkImageCropper::AddBoundingObjectToNode(mitk::DataNode* node, bool fit) { m_ImageToCrop = dynamic_cast(node->GetData()); if(!this->GetDefaultDataStorage()->Exists(m_CroppingObjectNode)) { this->GetDefaultDataStorage()->Add(m_CroppingObjectNode, node); if (fit) { m_CroppingObject->FitGeometry(m_ImageToCrop->GetTimeSlicedGeometry()); } mitk::GlobalInteraction::GetInstance()->AddInteractor( m_AffineInteractor ); } m_CroppingObjectNode->SetVisibility(true); } void QmitkImageCropper::RemoveBoundingObjectFromNode() { if (m_CroppingObjectNode.IsNotNull()) { if(this->GetDefaultDataStorage()->Exists(m_CroppingObjectNode)) { this->GetDefaultDataStorage()->Remove(m_CroppingObjectNode); mitk::GlobalInteraction::GetInstance()->RemoveInteractor(m_AffineInteractor); } m_Controls->m_NewBoxButton->setText("New bounding box!"); } } void QmitkImageCropper::ChkInformationToggled( bool on ) { if (on) m_Controls->groupInfo->show(); else m_Controls->groupInfo->hide(); } void QmitkImageCropper::StdMultiWidgetAvailable( QmitkStdMultiWidget& stdMultiWidget ) { m_MultiWidget = &stdMultiWidget; } void QmitkImageCropper::StdMultiWidgetNotAvailable() { m_MultiWidget = NULL; } void QmitkImageCropper::NodeRemoved(const mitk::DataNode *node) { std::string name = node->GetName(); if (strcmp(name.c_str(), "CroppingObject")==0) { m_Controls->btnCrop->setEnabled(false); m_Controls->m_NewBoxButton->setEnabled(true); } } diff --git a/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h b/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h index e0c09f9aa6..89b2fdd1d1 100644 --- a/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h +++ b/Modules/Bundles/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h @@ -1,219 +1,213 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision: 13136 $ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #if !defined(QMITK_IMAGECROPPER_H__INCLUDED) #define QMITK_IMAGECROPPER_H__INCLUDED #ifdef WIN32 #pragma warning( disable : 4250 ) #endif #include "QmitkFunctionality.h" #include #include #include #include #include "mitkWeakPointer.h" #include #include #include "mitkImageCropperEventInterface.h" #include "ui_QmitkImageCropperControls.h" /*! \ingroup org_mitk_gui_qt_imagecropper_internal \brief Functionality for cropping images with a cuboid This functionality lets the user select an image from the data tree, select an area of interest by placing a cuboid object, and then crop the image, so that pixels from outside the cuboid will remove. The image size is automatically reduced, if the cuboid is not rotated but parallel to the image axes. \b Implementation The functionality owns a cuboid (m_CroppingObject) and the associated interactor (m_AffineInteractor), which implements moving and scaling the cuboid. */ class QmitkImageCropper : public QmitkFunctionality, public mitk::OperationActor { /// Operation base class, which holds pointers to a node of the data tree (mitk::DataNode) /// and to two data sets (mitk::BaseData) instances class opExchangeNodes: public mitk::Operation { public: opExchangeNodes( mitk::OperationType type, mitk::DataNode* node, mitk::BaseData* oldData, mitk::BaseData* newData ); ~opExchangeNodes(); mitk::DataNode* GetNode() { return m_Node; } mitk::BaseData* GetOldData() { return m_OldData; } mitk::BaseData* GetNewData() { return m_NewData; } protected: void NodeDeleted(const itk::Object * /*caller*/, const itk::EventObject & /*event*/); private: mitk::DataNode* m_Node; mitk::BaseData::Pointer m_OldData; mitk::BaseData::Pointer m_NewData; long m_NodeDeletedObserverTag; long m_OldDataDeletedObserverTag; long m_NewDataDeletedObserverTag; }; private: Q_OBJECT public: /*! \brief Constructor. Called by SampleApp (or other apps that use functionalities) */ QmitkImageCropper(QObject *parent=0); /*! \brief Destructor */ virtual ~QmitkImageCropper(); /*! \brief Creates the Qt widget containing the functionality controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget* parent); /*! \brief Creates the Qt connections needed */ virtual void CreateConnections(); /*! \brief Invoked when this functionality is selected by the application */ virtual void Activated(); /*! \brief Invoked when the user leaves this functionality */ virtual void Deactivated(); /// /// Called when a StdMultiWidget is available. /// virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget); /// /// Called when no StdMultiWidget is available. /// virtual void StdMultiWidgetNotAvailable(); /* \brief Interface of a mitk::StateMachine (for undo/redo) */ virtual void ExecuteOperation (mitk::Operation*); QWidget* GetControls(); public slots: virtual void CropImage(); virtual void SurroundingCheck(bool value); virtual void CreateNewBoundingObject(); virtual void ChkInformationToggled( bool on ); protected: /*! * Default main widget containing 4 windows showing 3 * orthogonal slices of the volume and a 3d render window */ QmitkStdMultiWidget* m_MultiWidget; /*! * Controls containing an image selection drop down, some usage information and a "crop" button */ Ui::QmitkImageCropperControls * m_Controls; /*! * The parent QWidget */ QWidget* m_ParentWidget; /*! * \brief A pointer to the node of the image to be croped. */ mitk::WeakPointer m_ImageNode; /*! * \brief A pointer to the image to be cropped. */ mitk::WeakPointer m_ImageToCrop; /*! * \brief The cuboid used for cropping. */ mitk::BoundingObject::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::AffineInteractor::Pointer m_AffineInteractor; /*! * \brief Creates the cuboid and its data tree node. */ virtual void CreateBoundingObject(); /*! * \brief Called from superclass, handles selection changes. */ virtual void OnSelectionChanged(std::vector nodes); /*! * \brief Finds the given node in the data tree and optionally fits the cuboid to it */ virtual void AddBoundingObjectToNode(mitk::DataNode* node, bool fit); /*! * \brief Removes the cuboid from any node and hides it from the user. */ virtual void RemoveBoundingObjectFromNode(); - template < typename TPixel, unsigned int VImageDimension > - void AddSurrounding( itk::Image< TPixel, VImageDimension >* itkImage, mitk::Image::Pointer image); - virtual void NodeRemoved(const mitk::DataNode* node); private: // operation constant static const mitk::OperationType OP_EXCHANGE; - QProgressDialog *progress; - mitk::Image::Pointer m_surrImage; - //Interface class for undo redo mitk::ImageCropperEventInterface* m_Interface; }; #endif // !defined(QMITK_IMAGECROPPER_H__INCLUDED) diff --git a/Modules/MitkExt/DataManagement/mitkCylinder.cpp b/Modules/MitkExt/DataManagement/mitkCylinder.cpp index 9869006f61..fb909c0960 100644 --- a/Modules/MitkExt/DataManagement/mitkCylinder.cpp +++ b/Modules/MitkExt/DataManagement/mitkCylinder.cpp @@ -1,69 +1,69 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "mitkCylinder.h" #include "vtkLinearTransform.h" #include "mitkVector.h" #include "vtkCylinderSource.h" mitk::Cylinder::Cylinder() : BoundingObject() { vtkCylinderSource* cylinder = vtkCylinderSource::New(); cylinder->SetRadius(1.0); cylinder->SetHeight(2.0); cylinder->SetCenter(0.0, 0.0, 0.0); - cylinder->SetResolution(20); + cylinder->SetResolution(100); cylinder->CappingOn(); cylinder->Update(); SetVtkPolyData(cylinder->GetOutput()); cylinder->Delete(); } mitk::Cylinder::~Cylinder() { } bool mitk::Cylinder::IsInside(const Point3D& worldPoint) const { // transform point from world to object coordinates ScalarType p[4]; p[0] = worldPoint[0]; p[1] = worldPoint[1]; p[2] = worldPoint[2]; p[3] = 1; GetGeometry()->GetVtkTransform()->GetInverse()->TransformPoint(p, p); mitk::ScalarType v = pow(p[0], 2) + pow(p[2], 2); bool retval = (v <= 1) && (p[1] >= -1) && (p[1] <= 1); return retval; } mitk::ScalarType mitk::Cylinder::GetVolume() { Geometry3D* geometry = GetTimeSlicedGeometry(); return geometry->GetExtentInMM(0) * 0.5 * geometry->GetExtentInMM(2) * 0.5 * vnl_math::pi * geometry->GetExtentInMM(1); }