diff --git a/Modules/MyAwesomeLib/include/AwesomeImageInteractor.h b/Modules/MyAwesomeLib/include/AwesomeImageInteractor.h index d5d98885e7..c922f33e0f 100644 --- a/Modules/MyAwesomeLib/include/AwesomeImageInteractor.h +++ b/Modules/MyAwesomeLib/include/AwesomeImageInteractor.h @@ -1,50 +1,50 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef AwesomeImageInteractor_h #define AwesomeImageInteractor_h #include #include #include -namespace mitk -{ - +//namespace mitk +//{ +// // See AwesomeImageFilter.h for details on typical class declarations // in MITK. The actual functionality of this class is commented in its // implementation file. class MITKMYAWESOMELIB_EXPORT AwesomeImageInteractor final : public mitk::DataInteractor { public: mitkClassMacro(AwesomeImageInteractor, DataInteractor) itkFactorylessNewMacro(Self) private: AwesomeImageInteractor(); ~AwesomeImageInteractor(); void ConnectActionsAndFunctions() override; void DataNodeChanged() override; void Paint(mitk::StateMachineAction* action, mitk::InteractionEvent* event); itk::Index<3> m_LastPixelIndex; }; #endif -} \ No newline at end of file +//} \ No newline at end of file diff --git a/Modules/MyAwesomeLib/src/AwesomeImageInteractor.cpp b/Modules/MyAwesomeLib/src/AwesomeImageInteractor.cpp index 71fd1753bf..2cfdcfd46c 100644 --- a/Modules/MyAwesomeLib/src/AwesomeImageInteractor.cpp +++ b/Modules/MyAwesomeLib/src/AwesomeImageInteractor.cpp @@ -1,185 +1,185 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include // Helper function to get an image from a data node. static mitk::Image::Pointer GetImage(mitk::DataNode::Pointer dataNode) { if (dataNode.IsNull()) mitkThrow(); mitk::Image::Pointer image = dynamic_cast(dataNode->GetData()); if (image.IsNull()) mitkThrow(); return image; } // Helper function to get a geometry of an image for a specific time step. static mitk::BaseGeometry::Pointer GetGeometry(mitk::Image::Pointer image, unsigned int timeStep) { mitk::TimeGeometry::Pointer timeGeometry = image->GetTimeGeometry(); if (timeGeometry.IsNull()) mitkThrow(); auto geometry = timeGeometry->GetGeometryForTimeStep(timeStep); if (geometry.IsNull()) mitkThrow(); return geometry; } // The actual painting happens here. We're using a write accessor to gain safe // write access to our image. The whole image volume for a given time step is // locked. However, it's also possible - and preferable - to lock the slice of // interest only. template static void Paint(mitk::Image::Pointer image, itk::Index<3> index, unsigned int timeStep) { // As soon as the ImagePixelWriteAccessor object goes out of scope at the // end of this function, the image will be unlocked again (RAII). mitk::ImagePixelWriteAccessor writeAccessor(image, image->GetVolumeData(timeStep)); writeAccessor.SetPixelByIndex(index, std::numeric_limits::min()); // Don't forget to update the modified time stamp of the image. Otherwise, // everything downstream wouldn't recognize that the image changed, // including the rendering system. image->Modified(); } // Helper function to multiplex the actual Paint function call for different // pixel types. As it's cumbersome and ugly, you may want to avoid such // functions by using ITK for the actual painting and use the ITK access // macros like we did for the AwesomeImageFilter. static void Paint(mitk::Image::Pointer image, itk::Index<3> index, unsigned int timeStep) { switch (image->GetPixelType().GetComponentType()) { case itk::ImageIOBase::CHAR: Paint(image, index, timeStep); break; case itk::ImageIOBase::UCHAR: Paint(image, index, timeStep); break; case itk::ImageIOBase::SHORT: Paint(image, index, timeStep); break; case itk::ImageIOBase::USHORT: Paint(image, index, timeStep); break; case itk::ImageIOBase::INT: Paint(image, index, timeStep); break; case itk::ImageIOBase::UINT: Paint(image, index, timeStep); break; default: mitkThrow(); } } - mitk::AwesomeImageInteractor::AwesomeImageInteractor() + AwesomeImageInteractor::AwesomeImageInteractor() { } - mitk::AwesomeImageInteractor::~AwesomeImageInteractor() +AwesomeImageInteractor::~AwesomeImageInteractor() { } - void mitk::AwesomeImageInteractor::ConnectActionsAndFunctions() + void AwesomeImageInteractor::ConnectActionsAndFunctions() { // Wire up this interactor with the state machine that is described by // resource/Interactions/Paint.xml. CONNECT_FUNCTION("paint", Paint) } - void mitk::AwesomeImageInteractor::DataNodeChanged() + void AwesomeImageInteractor::DataNodeChanged() { // You almost always want to reset the state machine when the interactor // has been attached to another data node. this->ResetToStartState(); } // The state machine is wired up with this Paint method. We wrote a few helper // functions at the top of this files to keep this method clear and easy to // read. - void mitk::AwesomeImageInteractor::Paint(mitk::StateMachineAction* action, mitk::InteractionEvent* event) + void AwesomeImageInteractor::Paint(mitk::StateMachineAction* action, mitk::InteractionEvent* event) { try { auto renderer = event->GetSender(); auto image = GetImage(this->GetDataNode()); auto timeStep = renderer->GetTimeStep(); auto geometry = GetGeometry(image, timeStep); // This method is wired up to mouse events. Thus, we can safely assume // that the following cast will succeed and we have access to the mouse // position and the first intersection point of a ray originating at the // mouse position and shot into the scene. Convenient, isn't it? :-) auto positionEvent = dynamic_cast(event); auto position = positionEvent->GetPositionInWorld(); if (!geometry->IsInside(position)) return; // Nothing to paint, as we're not inside the image bounds. // Okay, we're safe. Convert the mouse position to the index of the pixel // we're pointing at. itk::Index<3> index; geometry->WorldToIndex<3>(position, index); // We don't need to paint over and over again while moving the mouse // pointer inside the same pixel. That's especially relevant when operating // on zoomed images. if (index != m_LastPixelIndex) { // And finally... ::Paint(image, index, timeStep); // Nearly done. We request the renderer to update the render window in // order to see the result immediately. Actually, we should update all // of the render windows by caling RequestUpdateAll() instead, as the // painted pixels are possibly visible in other render windows, too. // However, we decided to prefer performance here. mitk::RenderingManager::GetInstance()->RequestUpdate(positionEvent->GetSender()->GetRenderWindow()); MITK_INFO << index[0] << " " << index[1] << " " << index[2]; m_LastPixelIndex = index; } } catch (...) { return; } } diff --git a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/AwesomeView.cpp b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/AwesomeView.cpp index ef2ca51cec..7b5466846e 100644 --- a/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/AwesomeView.cpp +++ b/Plugins/org.mitk.gui.qt.exampleplugin/src/internal/AwesomeView.cpp @@ -1,178 +1,178 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "AwesomeView.h" #include #include #include #include #include #include #include //Helper function to create a fully set up instance of our //AwesomeImageInteractor, based on the state machine specified in Paint.xml //as well as its configuration in PaintConfig.xml. Both files are compiled //into our MyAwesomeLib module as resources. - static mitk::AwesomeImageInteractor::Pointer CreateAwesomeImageInteractor() + static AwesomeImageInteractor::Pointer CreateAwesomeImageInteractor() { auto myAwesomeLib = us::ModuleRegistry::GetModule("MitkMyAwesomeLib");//wichtig ist hier das Mitk noch dran zu schreiben - auto interactor = mitk::AwesomeImageInteractor::New(); + auto interactor = AwesomeImageInteractor::New(); interactor->LoadStateMachine("Paint.xml", myAwesomeLib); interactor->SetEventConfig("PaintConfig.xml", myAwesomeLib); return interactor; } // Don't forget to initialize the VIEW_ID. const std::string AwesomeView::VIEW_ID = "my.awesomeproject.views.awesomeview"; void AwesomeView::CreateQtPartControl(QWidget* parent) { // Setting up the UI is a true pleasure when using .ui files, isn't it? m_Controls.setupUi(parent); // Wire up the UI widgets with our functionality. connect(m_Controls.processImageButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedImage())); } void AwesomeView::SetFocus() { m_Controls.processImageButton->setFocus(); } void AwesomeView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList& dataNodes) { for (const auto& dataNode : dataNodes) { // Write robust code. Always check pointers before using them. If the // data node pointer is null, the second half of our condition isn't // even evaluated and we're safe (C++ short-circuit evaluation). if (dataNode.IsNotNull() && dynamic_cast(dataNode->GetData()) != nullptr) { m_Controls.selectImageLabel->setVisible(false); return; } } // Nothing is selected or the selection doesn't contain an image. m_Controls.selectImageLabel->setVisible(true); } void AwesomeView::ProcessSelectedImage() { MITK_INFO << "Process start"; // Before we even think about processing something, we need to make sure // that we have valid input. Don't be sloppy, this is a main reason // for application crashes if neglected. auto selectedDataNodes = this->GetDataManagerSelection(); if (selectedDataNodes.empty()) return; auto firstSelectedDataNode = selectedDataNodes.front(); if (firstSelectedDataNode.IsNull()) { QMessageBox::information(nullptr, "Awesome View", "Please load and select an image before starting image processing."); return; } MITK_INFO << "Process data"; auto data = firstSelectedDataNode->GetData(); // Something is selected, but does it contain data? if (data != nullptr) { // We don't use the auto keyword here, which would evaluate to a native // image pointer. Instead, we want a smart pointer in order to ensure that // the image isn't deleted somewhere else while we're using it. mitk::Image::Pointer image = dynamic_cast(data); // Something is selected and it contains data, but is it an image? if (image.IsNotNull()) { auto imageName = firstSelectedDataNode->GetName(); auto offset = m_Controls.offsetSpinBox->value(); MITK_INFO << "Process image \"" << imageName << "\" ..."; // We're finally using the AwesomeImageFilter from our AwesomeLib module. auto filter = AwesomeImageFilter::New(); filter->SetInput(image); filter->SetOffset(offset); filter->Update(); mitk::Image::Pointer processedImage = filter->GetOutput(); if (processedImage.IsNull() || !processedImage->IsInitialized()) return; MITK_INFO << " done"; //// Stuff the resulting image into a data node, set some properties, //// and add it to the data storage, which will eventually display the //// image in the application. auto processedImageDataNode = mitk::DataNode::New(); processedImageDataNode->SetData(processedImage); QString name = QString("%1 (Offset: %2)").arg(imageName.c_str()).arg(offset); processedImageDataNode->SetName(name.toStdString()); //// We don't really need to copy the level window, but if we wouldn't //// do it, the new level window would be initialized to display the image //// with optimal contrast in order to capture the whole range of pixel //// values. This is also true for the input image as long as one didn't //// modify its level window manually. Thus, the images would appear //// identical unless you compare the level window widget for both images. mitk::LevelWindow levelWindow; if (firstSelectedDataNode->GetLevelWindow(levelWindow)) processedImageDataNode->SetLevelWindow(levelWindow); // We also attach our AwesomeImageInteractor, which allows us to paint // on the resulting images by using the mouse as long as the CTRL key // is pressed. auto interactor = CreateAwesomeImageInteractor(); if (interactor.IsNotNull()) interactor->SetDataNode(processedImageDataNode); this->GetDataStorage()->Add(processedImageDataNode); } } // Now it's your turn. This class/method has lots of room for improvements, // for example: // // - What happens when multiple items are selected but the first one isn't // an image? - There isn't any feedback for the user at all. // - What's the front item of a selection? Does it depend on the order // of selection or the position in the Data Manager? - Isn't it // better to process all selected images? Don't forget to adjust the // titles of the UI widgets. // - In addition to the the displayed label, it's probably a good idea to // enable or disable the button depending on the selection. } diff --git a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.cpp b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.cpp index 94538a89c3..4cbc7176fe 100644 --- a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.cpp +++ b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.cpp @@ -1,147 +1,156 @@ /*========================================================================= 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 "QmitkSurfaceRegistration.h" #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK: added after using Plugin Generator #include // added for surface dynamic cast #include #include const std::string QmitkSurfaceRegistration::VIEW_ID = "org.mitk.views.qmitksurfaceregistration"; QmitkSurfaceRegistration::QmitkSurfaceRegistration(QObject *parent) : m_ParentWidget(0), m_movingSurfaceNode(nullptr), m_targetSurfaceNode(nullptr) { } QmitkSurfaceRegistration::~QmitkSurfaceRegistration() { // delete pointer objects m_movingSurfaceNode = nullptr; m_targetSurfaceNode = nullptr; } // void QmitkSurfaceRegistration::SetFocus(){ } void QmitkSurfaceRegistration::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.pushButtonExecute, SIGNAL(clicked()), this, SLOT(doExecute())); + connect(m_Controls.radioButtonMirroring, SIGNAL(clicked()), this, SLOT(doMirroring())); m_ParentWidget = parent; } void QmitkSurfaceRegistration::doExecute() { MITK_INFO << "pushButtonExecute clicked"; } +void QmitkSurfaceRegistration::doMirroring() +{ + MITK_INFO << "radioButton Mirroring clicked"; +} + + void QmitkSurfaceRegistration::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList &nodes) { MITK_INFO << "On Selection Changed"; bool rotationEnabled = false; if (nodes.empty()) { MITK_INFO << "Nothing selected yet"; m_Controls.labelSelectMovingSurface->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelSelectTargetSurface->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelMovingSurfaceName->setText(QString::fromStdString("No moving surface selected")); m_Controls.labelTargetSurfaceName->setText(QString::fromStdString("No target surface selected")); m_Controls.groupBoxMappedData->setEnabled(false); m_Controls.pushButtonExecute->setEnabled(false); return; } else { if (nodes.size() == 1) { if (nodes[0].IsNotNull() && dynamic_cast(nodes[0]->GetData())) { MITK_INFO << "There is exactly one image selected"; m_movingSurfaceNode = nodes[0]; m_Controls.labelSelectMovingSurface->setText("Selected moving surface:"); m_Controls.labelSelectMovingSurface->setStyleSheet(" QLabel { color: rgb(0, 0, 0) }"); m_Controls.labelMovingSurfaceName->setText( QString::fromStdString("File name: " + m_movingSurfaceNode->GetName())); + m_Controls.groupBoxMoving->setEnabled(true); } else { - QMessageBox::information(nullptr, "Warning", "Are you sure? - I dont think this is a Surface!"); + QMessageBox::information(nullptr, "Warning", "Are you sure? - I dont think this is a Surface! Try again!"); } } else if (nodes.size() == 2) { if (nodes[1].IsNotNull() && dynamic_cast(nodes[1]->GetData())) { MITK_INFO << "There is two images selected"; m_targetSurfaceNode = nodes[1]; m_Controls.labelSelectTargetSurface->setText("Selected target su rface:"); m_Controls.labelSelectTargetSurface->setStyleSheet(" QLabel { color: rgb(0, 0, 0) }"); m_Controls.labelTargetSurfaceName->setText( QString::fromStdString("File name: " + m_targetSurfaceNode->GetName())); m_Controls.groupBoxMappedData->setEnabled(true); m_Controls.textMappedDataName->setEnabled(true); m_Controls.pushButtonExecute->setEnabled(true); + m_Controls.groupBoxTarget->setEnabled(true); } else { QMessageBox::information(nullptr, "Warning", "Are you sure? - I dont think this is a Surface!"); } } else { QMessageBox::information(nullptr, "Warning", "You do know that it only works with two surfaces, right? If you continue to click execute, this might crash one day!"); //wie kann ich die Auswahl zurueck setzen? } } // mitk::Image::Pointer image = dynamic_cast(m_ImageNode->GetData()); // if (image != nullptr) // { // 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); // } } \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.h b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.h index be41e5096a..0ff64491c1 100644 --- a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.h +++ b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/QmitkSurfaceRegistration.h @@ -1,100 +1,102 @@ /*========================================================================= 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. =========================================================================*/ #ifndef QmitkSurfaceRegistration_h #define QmitkSurfaceRegistration_h #include #ifdef WIN32 #pragma warning( disable : 4250 ) #endif #include "QVTKWidget.h" #include "QmitkRegisterClasses.h" #include #include "ui_SurfaceRegistrationControls.h" #include "usServiceRegistration.h" /*! @brief QmitkSurfaceRegistrationView \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 QmitkSurfaceRegistration : 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) */ QmitkSurfaceRegistration(QObject *parent = 0); virtual ~QmitkSurfaceRegistration(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); virtual void SetFocus() override; ///*! //@brief Creates the Qt connections needed //*/ QWidget* GetControls(); /// @brief Called when the user clicks the GUI button protected slots: void doExecute(); + void doMirroring(); + protected: // /*! //@brief called by QmitkFunctionality when DataManager's selection has changed // */ void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; private: /*! * The parent QWidget */ QWidget* m_ParentWidget; /*! * @brief A pointer to the node of the moving surface. */ mitk::WeakPointer m_movingSurfaceNode; /*! * @brief A pointer to the node of the target surface. */ mitk::WeakPointer m_targetSurfaceNode; Ui::SurfaceRegistrationControls m_Controls; }; #endif // QmitkSurfaceRegistration_h \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/SurfaceRegistrationControls.ui b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/SurfaceRegistrationControls.ui index a41234dbc4..f86eb0a423 100644 --- a/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/SurfaceRegistrationControls.ui +++ b/Plugins/org.mitk.gui.qt.surfaceregistration/src/internal/SurfaceRegistrationControls.ui @@ -1,377 +1,453 @@ SurfaceRegistrationControls Qt::WindowModal - true + false 0 0 271 863 0 0 100 100 16777215 16777215 QmitkTemplate + + false + 0 0 0 - 75 + 95 Moving false 10 20 347 13 0 0 QLabel { color: rgb(255, 0, 0) } Select moving surface 10 40 171 20 0 0 50 20 16777215 16777215 QFrame::Box No moving surface selected + + + false + + + + 10 + 70 + 82 + 17 + + + + Mirroring + + 0 0 0 75 Target false 10 20 331 16 255 0 0 + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + 255 0 0 + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + - 120 - 120 - 120 + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + + + + + + 255 + 0 + 0 + + QLabel { color: rgb(255, 0, 0) } + Select target surface 10 40 171 20 0 0 50 20 16777215 16777215 QFrame::Box No target surface selected false 0 0 0 75 0 75 Mapped Data 10 20 331 16 0 0 0 0 0 0 120 120 120 Type mapped data name: 10 40 171 20 0 0 50 20 true false Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustIgnored true defaultMappedDataName Qt::TextEditable false Execute Qt::Vertical 20 40