diff --git a/Modules/Multilabel/mitkLabelSet.cpp b/Modules/Multilabel/mitkLabelSet.cpp index b6cc3b9248..0f3eb84f93 100644 --- a/Modules/Multilabel/mitkLabelSet.cpp +++ b/Modules/Multilabel/mitkLabelSet.cpp @@ -1,345 +1,368 @@ /*=================================================================== 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 "mitkLabelSet.h" #include "mitkDICOMSegmentationPropertyHelper.h" #include mitk::LabelSet::LabelSet() : m_ActiveLabelValue(0), m_Layer(0) { m_LookupTable = mitk::LookupTable::New(); m_LookupTable->SetType(mitk::LookupTable::MULTILABEL); } mitk::LabelSet::~LabelSet() { m_LabelContainer.clear(); } mitk::LabelSet::LabelSet(const LabelSet &other) : itk::Object(), m_LookupTable(other.GetLookupTable()->Clone()), m_ActiveLabelValue(other.GetActiveLabel()->GetValue()), m_Layer(other.GetLayer()) { // clone Labels auto otherIt = other.IteratorConstBegin(); for (; otherIt != other.IteratorConstEnd(); ++otherIt) { m_LabelContainer[otherIt->first] = otherIt->second->Clone(); itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &LabelSet::OnLabelModified); m_LabelContainer[otherIt->first]->AddObserver(itk::ModifiedEvent(), command); } } void mitk::LabelSet::OnLabelModified() { ModifyLabelEvent.Send(); Superclass::Modified(); } mitk::LabelSet::LabelContainerConstIteratorType mitk::LabelSet::IteratorConstEnd() const { return m_LabelContainer.end(); } mitk::LabelSet::LabelContainerConstIteratorType mitk::LabelSet::IteratorConstBegin() const { return m_LabelContainer.begin(); } mitk::LabelSet::LabelContainerIteratorType mitk::LabelSet::IteratorEnd() { return m_LabelContainer.end(); } mitk::LabelSet::LabelContainerIteratorType mitk::LabelSet::IteratorBegin() { return m_LabelContainer.begin(); } unsigned int mitk::LabelSet::GetNumberOfLabels() const { return m_LabelContainer.size(); } void mitk::LabelSet::SetLayer(unsigned int layer) { m_Layer = layer; Modified(); } void mitk::LabelSet::SetActiveLabel(PixelType pixelValue) { m_ActiveLabelValue = pixelValue; ActiveLabelEvent.Send(pixelValue); Modified(); } bool mitk::LabelSet::ExistLabel(PixelType pixelValue) { return m_LabelContainer.count(pixelValue) > 0 ? true : false; } // TODO Parameter as Smartpointer void mitk::LabelSet::AddLabel(mitk::Label *label) { unsigned int max_size = mitk::Label::MAX_LABEL_VALUE + 1; if (m_LabelContainer.size() >= max_size) return; mitk::Label::Pointer newLabel(label->Clone()); // TODO use layer of label parameter newLabel->SetLayer(m_Layer); PixelType pixelValue; if (m_LabelContainer.empty()) { pixelValue = newLabel->GetValue(); } else { pixelValue = m_LabelContainer.rbegin()->first; if (pixelValue >= newLabel->GetValue() && m_LabelContainer.find(newLabel->GetValue()) != m_LabelContainer.end()) { ++pixelValue; newLabel->SetValue(pixelValue); } else { pixelValue = newLabel->GetValue(); } } // new map entry m_LabelContainer[pixelValue] = newLabel; UpdateLookupTable(pixelValue); // add DICOM information of the label DICOMSegmentationPropertyHandler::SetDICOMSegmentProperties(newLabel); itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &LabelSet::OnLabelModified); newLabel->AddObserver(itk::ModifiedEvent(), command); // newLabel->AddObserver(itk::ModifiedEvent(),command); SetActiveLabel(newLabel->GetValue()); AddLabelEvent.Send(); Modified(); } void mitk::LabelSet::AddLabel(const std::string &name, const mitk::Color &color) { if (m_LabelContainer.size() > 255) return; mitk::Label::Pointer newLabel = mitk::Label::New(); newLabel->SetName(name); newLabel->SetColor(color); AddLabel(newLabel); } void mitk::LabelSet::RenameLabel(PixelType pixelValue, const std::string &name, const mitk::Color &color) { mitk::Label *label = GetLabel(pixelValue); label->SetName(name); label->SetColor(color); // change DICOM information of the label DICOMSegmentationPropertyHandler::SetDICOMSegmentProperties(label); } void mitk::LabelSet::SetLookupTable(mitk::LookupTable *lut) { m_LookupTable = lut; Modified(); } void mitk::LabelSet::PrintSelf(std::ostream & /*os*/, itk::Indent /*indent*/) const { } void mitk::LabelSet::RemoveLabel(PixelType pixelValue) { auto it = m_LabelContainer.rbegin(); PixelType nextActivePixelValue = it->first; - for (; it != m_LabelContainer.rend(); it++) + for (; it != m_LabelContainer.rend(); ++it) { if (it->first == pixelValue) { it->second->RemoveAllObservers(); m_LabelContainer.erase(pixelValue); break; } nextActivePixelValue = it->first; } if (m_ActiveLabelValue == pixelValue) { if (ExistLabel(nextActivePixelValue)) SetActiveLabel(nextActivePixelValue); else SetActiveLabel(m_LabelContainer.rbegin()->first); } RemoveLabelEvent.Send(); Modified(); } void mitk::LabelSet::RemoveAllLabels() { auto _it = IteratorBegin(); for (; _it != IteratorConstEnd();) { RemoveLabelEvent.Send(); m_LabelContainer.erase(_it++); } AllLabelsModifiedEvent.Send(); } +void mitk::LabelSet::SetNextActiveLabel() +{ + auto it = m_LabelContainer.begin(); + PixelType nextActivePixelValue = it->first; + + for (; it != m_LabelContainer.end(); ++it) + { + if (it->first == m_ActiveLabelValue) + { + // go to next label + ++it; + if (it == m_LabelContainer.end()) + { + // end of container; next label is first label + it = m_LabelContainer.begin(); + } + break; // found the active label; finish loop + } + } + + SetActiveLabel(it->first); +} + void mitk::LabelSet::SetAllLabelsLocked(bool value) { auto _end = m_LabelContainer.end(); auto _it = m_LabelContainer.begin(); for (; _it != _end; ++_it) _it->second->SetLocked(value); AllLabelsModifiedEvent.Send(); Modified(); } void mitk::LabelSet::SetAllLabelsVisible(bool value) { auto _end = m_LabelContainer.end(); auto _it = m_LabelContainer.begin(); for (; _it != _end; ++_it) { _it->second->SetVisible(value); UpdateLookupTable(_it->first); } AllLabelsModifiedEvent.Send(); Modified(); } void mitk::LabelSet::UpdateLookupTable(PixelType pixelValue) { const mitk::Color &color = GetLabel(pixelValue)->GetColor(); double rgba[4]; m_LookupTable->GetTableValue(static_cast(pixelValue), rgba); rgba[0] = color.GetRed(); rgba[1] = color.GetGreen(); rgba[2] = color.GetBlue(); if (GetLabel(pixelValue)->GetVisible()) rgba[3] = GetLabel(pixelValue)->GetOpacity(); else rgba[3] = 0.0; m_LookupTable->SetTableValue(static_cast(pixelValue), rgba); } mitk::Label *mitk::LabelSet::GetLabel(PixelType pixelValue) { if (m_LabelContainer.find(pixelValue) == m_LabelContainer.end()) return nullptr; return m_LabelContainer[pixelValue]; } const mitk::Label *mitk::LabelSet::GetLabel(PixelType pixelValue) const { auto it = m_LabelContainer.find(pixelValue); if (it == m_LabelContainer.end()) return nullptr; return it->second.GetPointer(); } bool mitk::Equal(const mitk::LabelSet &leftHandSide, const mitk::LabelSet &rightHandSide, ScalarType eps, bool verbose) { bool returnValue = true; // LabelSetmembers MITK_INFO(verbose) << "--- LabelSet Equal ---"; // m_LookupTable; const mitk::LookupTable *lhsLUT = leftHandSide.GetLookupTable(); const mitk::LookupTable *rhsLUT = rightHandSide.GetLookupTable(); returnValue = *lhsLUT == *rhsLUT; if (!returnValue) { MITK_INFO(verbose) << "Lookup tabels not equal."; return returnValue; ; } // m_ActiveLabel; returnValue = mitk::Equal(*leftHandSide.GetActiveLabel(), *rightHandSide.GetActiveLabel(), eps, verbose); if (!returnValue) { MITK_INFO(verbose) << "Active label not equal."; return returnValue; ; } // m_Layer; returnValue = leftHandSide.GetLayer() == rightHandSide.GetLayer(); if (!returnValue) { MITK_INFO(verbose) << "Layer index not equal."; return returnValue; ; } // container size; returnValue = leftHandSide.GetNumberOfLabels() == rightHandSide.GetNumberOfLabels(); if (!returnValue) { MITK_INFO(verbose) << "Number of labels not equal."; return returnValue; ; } // Label container (map) // m_LabelContainer; auto lhsit = leftHandSide.IteratorConstBegin(); auto rhsit = rightHandSide.IteratorConstBegin(); for (; lhsit != leftHandSide.IteratorConstEnd(); ++lhsit, ++rhsit) { returnValue = rhsit->first == lhsit->first; if (!returnValue) { MITK_INFO(verbose) << "Label in label container not equal."; return returnValue; ; } returnValue = mitk::Equal(*(rhsit->second), *(lhsit->second), eps, verbose); if (!returnValue) { MITK_INFO(verbose) << "Label in label container not equal."; return returnValue; ; } } return returnValue; } diff --git a/Modules/Multilabel/mitkLabelSet.h b/Modules/Multilabel/mitkLabelSet.h index a542d89f78..11360c87ef 100644 --- a/Modules/Multilabel/mitkLabelSet.h +++ b/Modules/Multilabel/mitkLabelSet.h @@ -1,237 +1,239 @@ /*=================================================================== 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 __mitkLabelSet_H_ #define __mitkLabelSet_H_ #include "MitkMultilabelExports.h" #include #include #include #include #include namespace mitk { // // Documentation // @brief LabelSet containing the labels corresponding to a segmentation session. // @ingroup Data // class MITKMULTILABEL_EXPORT LabelSet : public itk::Object { public: mitkClassMacroItkParent(LabelSet, itk::Object); itkNewMacro(Self); typedef mitk::Label::PixelType PixelType; typedef std::map LabelContainerType; typedef LabelContainerType::const_iterator LabelContainerConstIteratorType; typedef LabelContainerType::iterator LabelContainerIteratorType; /** * \brief AddLabelEvent is emitted whenever a new label has been added to the LabelSet. * * Observers should register to this event by calling myLabelSet->AddLabelEvent.AddListener(myObject, * MyObject::MyMethod). * After registering, myObject->MyMethod() will be called every time a new label has been added to the LabelSet. * Observers should unregister by calling myLabelSet->AddLabelEvent.RemoveListener(myObject, MyObject::MyMethod). * * member variable is not needed to be locked in multi-threaded scenarios since the LabelSetEvent is a typedef for * a Message1 object which is thread safe */ Message<> AddLabelEvent; /** * \brief RemoveLabelEvent is emitted whenever a new label has been removed from the LabelSet. * * Observers should register to this event by calling myLabelSet->RemoveLabelEvent.AddListener(myObject, * MyObject::MyMethod). * After registering, myObject->MyMethod() will be called every time a new label has been removed from the LabelSet. * Observers should unregister by calling myLabelSet->RemoveLabelEvent.RemoveListener(myObject, MyObject::MyMethod). * * member variable is not needed to be locked in multi-threaded scenarios since the LabelSetEvent is a typedef for * a Message object which is thread safe */ Message<> RemoveLabelEvent; /** * \brief ModifyLabelEvent is emitted whenever a label has been modified from the LabelSet. * * Observers should register to this event by calling myLabelSet->ModifyLabelEvent.AddListener(myObject, * MyObject::MyMethod). * After registering, myObject->MyMethod() will be called every time a new label has been removed from the LabelSet. * Observers should unregister by calling myLabelSet->ModifyLabelEvent.RemoveListener(myObject, MyObject::MyMethod). * * member variable is not needed to be locked in multi-threaded scenarios since the LabelSetEvent is a typedef for * a Message object which is thread safe */ Message<> ModifyLabelEvent; /** * \brief ActiveLabelEvent is emitted whenever a label has been set as active in the LabelSet. */ Message1 ActiveLabelEvent; /** * \brief AllLabelsModifiedEvent is emitted whenever a new label has been removed from the LabelSet. * * Observers should register to this event by calling myLabelSet->AllLabelsModifiedEvent.AddListener(myObject, * MyObject::MyMethod). * After registering, myObject->MyMethod() will be called every time a new label has been removed from the LabelSet. * Observers should unregister by calling myLabelSet->AllLabelsModifiedEvent.RemoveListener(myObject, * MyObject::MyMethod). * * member variable is not needed to be locked in multi-threaded scenarios since the LabelSetEvent is a typedef for * a Message object which is thread safe */ Message<> AllLabelsModifiedEvent; /** \brief Returns a const iterator poiting to the begining of the container. */ LabelContainerConstIteratorType IteratorConstBegin() const; /** \brief Returns a const iterator pointing to the end of the container. */ LabelContainerConstIteratorType IteratorConstEnd() const; /** \brief Returns a iterator poiting to the begining of the container. */ LabelContainerIteratorType IteratorBegin(); /** \brief Returns a iterator pointing to the end of the container. */ LabelContainerIteratorType IteratorEnd(); /** \brief * Recall itk::Object::Modified event from a label and send a ModifyLabelEvent */ void OnLabelModified(); /** \brief */ void SetLayer(unsigned int); /** \brief */ void SetActiveLabel(PixelType); /** \brief */ void RemoveLabel(PixelType); /** \brief */ bool ExistLabel(PixelType); /** \brief */ void AddLabel(mitk::Label *label); /** \brief */ void AddLabel(const std::string &name, const Color &color); /** \brief */ void RenameLabel(PixelType, const std::string &, const Color &); /** \brief */ unsigned int GetNumberOfLabels() const; /** \brief */ void SetAllLabelsVisible(bool); /** \brief */ void SetAllLabelsLocked(bool); /** \brief */ void RemoveAllLabels(); + void SetNextActiveLabel(); + /** \brief */ Label *GetActiveLabel() { return GetLabel(m_ActiveLabelValue); } /** \brief */ const Label *GetActiveLabel() const { return GetLabel(m_ActiveLabelValue); } /** \brief */ Label *GetLabel(PixelType pixelValue); /** \brief */ const Label *GetLabel(PixelType pixelValue) const; itkGetMacro(Layer, int) itkGetConstMacro(Layer, int) itkGetModifiableObjectMacro(LookupTable, mitk::LookupTable) /** \brief */ void SetLookupTable(LookupTable *lut); /** \brief */ void UpdateLookupTable(PixelType pixelValue); protected: LabelSet(); LabelSet(const LabelSet &); mitkCloneMacro(Self) ~LabelSet() override; void PrintSelf(std::ostream &os, itk::Indent indent) const override; LabelContainerType m_LabelContainer; LookupTable::Pointer m_LookupTable; PixelType m_ActiveLabelValue; unsigned int m_Layer; }; /** * @brief Equal A function comparing two label sets for beeing equal in data * * @ingroup MITKTestingAPI * * Following aspects are tested for equality: * - LabelSetmembers * - Label container (map) * * @param rightHandSide An image to be compared * @param leftHandSide An image to be compared * @param eps Tolarence for comparison. You can use mitk::eps in most cases. * @param verbose Flag indicating if the user wants detailed console output or not. * @return true, if all subsequent comparisons are true, false otherwise */ MITKMULTILABEL_EXPORT bool Equal(const mitk::LabelSet &leftHandSide, const mitk::LabelSet &rightHandSide, ScalarType eps, bool verbose); } // namespace mitk #endif // __mitkLabelSet_H_ diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp index b4038a9da9..6be1fbbcd6 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,1129 +1,1166 @@ /*=================================================================== 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 "QmitkMultiLabelSegmentationView.h" // blueberry #include #include // mitk #include "mitkApplicationCursor.h" #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" #include "mitkToolManagerProvider.h" //#include "mitkSegmentationObjectFactory.h" #include "mitkInteractionEventObserver.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" #include "mitkSegTool2D.h" // Qmitk #include "QmitkNewSegmentationDialog.h" #include "QmitkRenderWindow.h" #include "QmitkSegmentationOrganNamesHandling.cpp" // us #include #include #include #include #include // Qt #include #include #include #include +#include #include "tinyxml.h" #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : m_Parent(nullptr), m_IRenderWindowPart(nullptr), m_ToolManager(nullptr), m_ReferenceNode(nullptr), m_WorkingNode(nullptr), m_AutoSelectionEnabled(false), m_MouseCursorSet(false) { m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer isOdf = mitk::NodePredicateDataType::New("OdfImage"); auto isSegment = mitk::NodePredicateDataType::New("Segment"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(mitk::NodePredicateAnd::New(isImage, mitk::NodePredicateNot::New(isSegment))); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isOdf); m_ReferencePredicate = mitk::NodePredicateAnd::New(); m_ReferencePredicate->AddPredicate(validImages); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(m_SegmentationPredicate)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(isMask)); m_ReferencePredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); } QmitkMultiLabelSegmentationView::~QmitkMultiLabelSegmentationView() { // m_ToolManager->ActivateTool(-1); /* todo: check this m_Controls.m_SliceBasedInterpolatorWidget->EnableInterpolation(false); ctkPluginContext* context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService* service = context->getService(ppmRef); service->RemoveAllPlanePositions(); context->ungetService(ppmRef); */ // m_ToolManager->SetReferenceData(nullptr); // m_ToolManager->SetWorkingData(nullptr); // m_ServiceRegistration.Unregister(); // Loose LabelSetConnections OnLooseLabelSetConnection(); } void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) { // setup the basic GUI of this view m_Parent = parent; m_Controls.setupUi(parent); + // *------------------------ + // * Shortcuts + // *------------------------ + QShortcut* visibilityShortcut = new QShortcut(QKeySequence("CTRL+H"), parent); + connect(visibilityShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated); + QShortcut* labelToggleShortcut = new QShortcut(QKeySequence("CTRL+L"), parent); + connect(labelToggleShortcut, &QShortcut::activated, this, &QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated); + // *------------------------ // * DATA SELECTION WIDGETS // *------------------------ m_Controls.m_cbReferenceNodeSelector->SetAutoSelectNewItems(true); m_Controls.m_cbReferenceNodeSelector->SetPredicate(m_ReferencePredicate); m_Controls.m_cbReferenceNodeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.m_cbWorkingNodeSelector->SetAutoSelectNewItems(true); m_Controls.m_cbWorkingNodeSelector->SetPredicate(m_SegmentationPredicate); m_Controls.m_cbWorkingNodeSelector->SetDataStorage(this->GetDataStorage()); connect(m_Controls.m_cbReferenceNodeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnReferenceSelectionChanged(const mitk::DataNode *))); connect(m_Controls.m_cbWorkingNodeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSegmentationSelectionChanged(const mitk::DataNode *))); // *------------------------ // * ToolManager // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); // use the same ToolManager instance for our 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); // *------------------------ // * LabelSetWidget // *------------------------ m_Controls.m_LabelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls.m_LabelSetWidget->SetOrganColors(mitk::OrganNamesHandling::GetDefaultOrganColorString()); m_Controls.m_LabelSetWidget->hide(); // *------------------------ // * Interpolation // *------------------------ m_Controls.m_SurfaceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); m_Controls.m_SliceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); connect(m_Controls.m_cbInterpolation, SIGNAL(activated(int)), this, SLOT(OnInterpolationSelectionChanged(int))); m_Controls.m_cbInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->hide(); // *------------------------ // * ToolSelection 2D // *------------------------ m_Controls.m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer2D); m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups( "Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D Correction 'Live Wire'"); // todo: "Correction // 'Live Wire'" m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls.m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int))); // *------------------------ // * ToolSelection 3D // *------------------------ m_Controls.m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer3D); m_Controls.m_ManualToolSelectionBox3D->SetDisplayedToolGroups( "Threshold 'Two Thresholds' 'Auto Threshold' 'Multiple Otsu'"); // todo add : FastMarching3D RegionGrowing Watershed m_Controls.m_ManualToolSelectionBox3D->SetLayoutColumns(2); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); // *------------------------* // * Connect PushButtons (pb) // *------------------------* connect(m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT(OnNewLabel())); connect(m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT(OnNewSegmentationSession())); connect(m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT(OnShowLabelTable(bool))); // *------------------------* // * Connect LabelSetWidget // *------------------------* connect(m_Controls.m_LabelSetWidget, SIGNAL(goToLabel(const mitk::Point3D &)), this, SLOT(OnGoToLabel(const mitk::Point3D &))); connect(m_Controls.m_LabelSetWidget, SIGNAL(resetView()), this, SLOT(OnResetView())); // *------------------------* // * DATA SLECTION WIDGET // *------------------------* m_IRenderWindowPart = this->GetRenderWindowPart(); if (m_IRenderWindowPart) { QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); // m_Controls.m_LabelSetWidget->SetRenderWindowPart(this->m_IRenderWindowPart); } // this->InitializeListeners(); connect(m_Controls.m_btAddLayer, SIGNAL(clicked()), this, SLOT(OnAddLayer())); connect(m_Controls.m_btDeleteLayer, SIGNAL(clicked()), this, SLOT(OnDeleteLayer())); connect(m_Controls.m_btPreviousLayer, SIGNAL(clicked()), this, SLOT(OnPreviousLayer())); connect(m_Controls.m_btNextLayer, SIGNAL(clicked()), this, SLOT(OnNextLayer())); connect(m_Controls.m_btLockExterior, SIGNAL(toggled(bool)), this, SLOT(OnLockExteriorToggled(bool))); connect(m_Controls.m_cbActiveLayer, SIGNAL(currentIndexChanged(int)), this, SLOT(OnChangeLayer(int))); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setEnabled(false); // Make sure the GUI notices if appropriate data is already present on creation this->OnReferenceSelectionChanged(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); this->OnSegmentationSelectionChanged(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Activated() { m_ToolManager->SetReferenceData(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); m_ToolManager->SetWorkingData(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Deactivated() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Visible() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Hidden() { // Not yet implemented } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { if (!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if (width == false) { return 100; } else { return preferredResult; } } /************************************************************************/ /* protected slots */ /************************************************************************/ +void QmitkMultiLabelSegmentationView::OnVisibilityShortcutActivated() +{ + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + assert(workingNode); + + bool isVisible = false; + workingNode->GetBoolProperty("visible", isVisible); + workingNode->SetVisibility(!isVisible); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + +void QmitkMultiLabelSegmentationView::OnLabelToggleShortcutActivated() +{ + mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + assert(workingNode); + + mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + assert(workingImage); + + WaitCursorOn(); + workingImage->GetActiveLabelSet()->SetNextActiveLabel(); + workingImage->Modified(); + WaitCursorOff(); + + mitk::RenderingManager::GetInstance()->RequestUpdateAll(); +} + void QmitkMultiLabelSegmentationView::OnManualTool2DSelected(int id) { this->ResetMouseCursor(); mitk::StatusBar::GetInstance()->DisplayText(""); if (id >= 0) { std::string text = "Active Tool: \""; text += m_ToolManager->GetToolById(id)->GetName(); text += "\""; mitk::StatusBar::GetInstance()->DisplayText(text.c_str()); us::ModuleResource resource = m_ToolManager->GetToolById(id)->GetCursorIconResource(); if (resource.IsValid()) this->SetMouseCursor(resource, 0, 0); } } void QmitkMultiLabelSegmentationView::OnNewLabel() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); if (!workingNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); if (!workingImage) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } QmitkNewSegmentationDialog* dialog = new QmitkNewSegmentationDialog(m_Parent); dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) { return; } QString segName = dialog->GetSegmentationName(); if (segName.isEmpty()) { segName = "Unnamed"; } workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(workingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } void QmitkMultiLabelSegmentationView::OnShowLabelTable(bool value) { if (value) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { mitk::DataNode *referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); if (!referenceNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } m_ToolManager->ActivateTool(-1); mitk::Image* referenceImage = dynamic_cast(referenceNode->GetData()); assert(referenceImage); QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); if (!ok) { return; } this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "New Segmentation Session", "Could not create a new segmentation session.\n"); return; } this->WaitCursorOff(); mitk::DataNode::Pointer workingNode = mitk::DataNode::New(); workingNode->SetData(workingImage); workingNode->SetName(newName.toStdString()); workingImage->GetExteriorLabel()->SetProperty("name.parent", mitk::StringProperty::New(referenceNode->GetName().c_str())); workingImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newName.toStdString().c_str())); if (!GetDataStorage()->Exists(workingNode)) { GetDataStorage()->Add(workingNode, referenceNode); } OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D& pos) { if (m_IRenderWindowPart) m_IRenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { if (m_IRenderWindowPart) m_IRenderWindowPart->ForceImmediateUpdate(); } void QmitkMultiLabelSegmentationView::OnAddLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QString question = "Do you really want to add a layer to the current segmentation session?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; try { WaitCursorOn(); workingImage->AddLayer(); WaitCursorOff(); } catch ( mitk::Exception& e ) { WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information( m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); if (workingImage->GetNumberOfLayers() < 2) return; QString question = "Do you really want to delete the current layer?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) { return; } try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } catch (mitk::Exception& e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Delete Layer", "Could not delete the currently active layer. See error log for details.\n"); return; } UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() - 1); } void QmitkMultiLabelSegmentationView::OnNextLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() + 1); } void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeactivateActiveTool() { m_ToolManager->ActivateTool(-1); } void QmitkMultiLabelSegmentationView::OnLockExteriorToggled(bool checked) { mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(const mitk::DataNode* node) { m_ToolManager->ActivateTool(-1); m_ReferenceNode = const_cast(node); m_ToolManager->SetReferenceData(m_ReferenceNode); if (m_ReferenceNode.IsNotNull()) { if (m_AutoSelectionEnabled) { // if an image is selected find a possible working / segmentation image mitk::DataStorage::SetOfObjects::ConstPointer derivations = this->GetDataStorage()->GetDerivations(m_ReferenceNode, m_SegmentationPredicate); if (derivations->Size() != 0) { // use the first segmentation child node m_WorkingNode = derivations->ElementAt(0); m_ToolManager->SetWorkingData(m_WorkingNode); m_Controls.m_cbWorkingNodeSelector->blockSignals(true); m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(m_WorkingNode); m_Controls.m_cbWorkingNodeSelector->blockSignals(false); } else if (derivations->size() == 0) { m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); } // hide all image and segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) { (*iter)->SetVisibility(false); } mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_ReferenceNode->SetVisibility(true); // check match of segmentation and reference image geometries if (m_WorkingNode.IsNotNull()) { mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); mitk::Image* referenceImage = dynamic_cast(node->GetData()); assert(referenceImage); if (!this->CheckForSameGeometry(referenceImage, workingImage)) { return; } m_WorkingNode->SetVisibility(true); } } UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(const mitk::DataNode* node) { m_ToolManager->ActivateTool(-1); if (m_WorkingNode.IsNotNull()) OnLooseLabelSetConnection(); m_WorkingNode = const_cast(node); m_ToolManager->SetWorkingData(m_WorkingNode); if (m_WorkingNode.IsNotNull()) { OnEstablishLabelSetConnection(); if (m_AutoSelectionEnabled) { // if a segmentation is selected find a possible reference image mitk::DataStorage::SetOfObjects::ConstPointer sources = this->GetDataStorage()->GetSources(m_WorkingNode, m_ReferencePredicate); if (sources->Size() != 0) { m_ReferenceNode = sources->ElementAt(0); m_ToolManager->SetReferenceData(m_ReferenceNode); m_Controls.m_cbReferenceNodeSelector->blockSignals(true); m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(m_ReferenceNode); m_Controls.m_cbReferenceNodeSelector->blockSignals(false); } else if(sources->size() == 0) { m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); } // hide all image and segmentation nodes to later show only the automatically selected ones mitk::DataStorage::SetOfObjects::ConstPointer patientNodes = GetDataStorage()->GetSubset(m_ReferencePredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = patientNodes->begin(); iter != patientNodes->end(); ++iter) { (*iter)->SetVisibility(false); } mitk::DataStorage::SetOfObjects::ConstPointer segmentationNodes = GetDataStorage()->GetSubset(m_SegmentationPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator iter = segmentationNodes->begin(); iter != segmentationNodes->end(); ++iter) { (*iter)->SetVisibility(false); } } m_WorkingNode->SetVisibility(true); // check match of segmentation and reference image geometries if (m_ReferenceNode.IsNotNull()) { mitk::Image* referenceImage = dynamic_cast(m_ReferenceNode->GetData()); assert(referenceImage); mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); if (!this->CheckForSameGeometry(referenceImage, workingImage)) { return; } m_ReferenceNode->SetVisibility(true); } } UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); mitk::RenderingManager::GetInstance()->InitializeViews(m_WorkingNode->GetData()->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); m_Controls.m_swInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->show(); } else if (index == 2) { m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(1); m_Controls.m_swInterpolation->show(); } else { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(2); m_Controls.m_swInterpolation->hide(); } } /************************************************************************/ /* protected */ /************************************************************************/ void QmitkMultiLabelSegmentationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer, const QList &nodes) { if (m_AutoSelectionEnabled) { // automatically set the reference node and the working node of the multi label plugin if (1 == nodes.size()) { mitk::DataNode::Pointer selectedNode = nodes.at(0); if (selectedNode.IsNull()) { return; } // check selected node mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(selectedNode->GetData()); if (labelSetImage.IsNotNull()) { // reset the image / reference node selector in case the current selected segmentation has no image parent m_Controls.m_cbReferenceNodeSelector->setCurrentIndex(-1); // selected a label set image (a segmentation ( working node) m_Controls.m_cbWorkingNodeSelector->SetSelectedNode(selectedNode); return; } mitk::Image::Pointer selectedImage = dynamic_cast(selectedNode->GetData()); if (selectedImage.IsNotNull()) { // reset the segmentation / working node selector in case the current selected image has no segmentation child m_Controls.m_cbWorkingNodeSelector->setCurrentIndex(-1); // selected an image (a reference node) m_Controls.m_cbReferenceNodeSelector->SetSelectedNode(selectedNode); return; } } } } void QmitkMultiLabelSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences* prefs) { if (m_Parent && m_WorkingNode.IsNotNull()) { m_AutoSelectionEnabled = prefs->GetBool("auto selection", false); mitk::BoolProperty::Pointer drawOutline = mitk::BoolProperty::New(prefs->GetBool("draw outline", true)); mitk::BoolProperty::Pointer volumeRendering = mitk::BoolProperty::New(prefs->GetBool("volume rendering", false)); mitk::LabelSetImage* labelSetImage; mitk::DataNode* segmentation; // iterate all segmentations (binary (single label) and LabelSetImages) mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateOr::Pointer allSegmentationsPredicate = mitk::NodePredicateOr::New(isBinaryPredicate, m_SegmentationPredicate); mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(allSegmentationsPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator it = allSegmentations->begin(); it != allSegmentations->end(); ++it) { segmentation = *it; labelSetImage = dynamic_cast(segmentation->GetData()); if (nullptr != labelSetImage) { // segmentation node is a multi label segmentation segmentation->SetProperty("labelset.contour.active", drawOutline); segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } else if (nullptr != segmentation->GetData()) { // node is actually a 'single label' segmentation, // but its outline property can be set in the 'multi label' segmentation preference page as well bool isBinary = false; segmentation->GetBoolProperty("binary", isBinary); if (isBinary) { segmentation->SetProperty("outline binary", drawOutline); segmentation->SetProperty("outline width", mitk::FloatProperty::New(2.0)); segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } } else { // "interpolation feedback" data nodes have binary flag but don't have a data set. So skip them for now. MITK_INFO << "DataNode " << segmentation->GetName() << " doesn't contain a base data."; } } } } void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode *) { /* bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) return; if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); if (workingImage->GetNumberOfLabels() > 2) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } */ } void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) { return; } if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext *context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService *service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = nullptr; } } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { MITK_INFO << "Connection Established"; if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { MITK_INFO << "Connection Lost"; if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Reset LabelSetWidget Events workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::SetFocus() { } void QmitkMultiLabelSegmentationView::UpdateControls() { mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != nullptr; mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); bool hasValidWorkingNode = workingNode != nullptr; m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_gbInterpolation->setEnabled(false); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(false); m_Controls.m_LabelSetWidget->setEnabled(false); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btLockExterior->setChecked(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setChecked(false); m_Controls.m_pbShowLabelTable->setEnabled(false); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); if (hasValidWorkingNode) { // TODO adapt tool manager so that this check is done there, e.g. convenience function mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); hasValidWorkingNode = workingImage != nullptr; if (hasValidWorkingNode) { m_Controls.m_pbNewLabel->setEnabled(true); m_Controls.m_btLockExterior->setEnabled(true); m_Controls.m_pbShowLabelTable->setEnabled(true); m_Controls.m_gbInterpolation->setEnabled(true); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_btAddLayer->setEnabled(true); int activeLayer = workingImage->GetActiveLayer(); int numberOfLayers = workingImage->GetNumberOfLayers(); m_Controls.m_cbActiveLayer->blockSignals(true); m_Controls.m_cbActiveLayer->clear(); for (unsigned int lidx = 0; lidx < workingImage->GetNumberOfLayers(); ++lidx) { m_Controls.m_cbActiveLayer->addItem(QString::number(lidx)); } m_Controls.m_cbActiveLayer->setCurrentIndex(activeLayer); m_Controls.m_cbActiveLayer->blockSignals(false); m_Controls.m_cbActiveLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btDeleteLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btPreviousLayer->setEnabled(activeLayer > 0); m_Controls.m_btNextLayer->setEnabled(activeLayer != numberOfLayers - 1); m_Controls.m_btLockExterior->setChecked(workingImage->GetLabel(0, activeLayer)->GetLocked()); m_Controls.m_pbShowLabelTable->setChecked(workingImage->GetNumberOfLabels() > 1 /*1st is exterior*/); //MLI TODO //m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } } if (hasValidWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); } } void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = 0; m_Parent->setEnabled(false); } void QmitkMultiLabelSegmentationView::ResetMouseCursor() { if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkMultiLabelSegmentationView::SetMouseCursor(const us::ModuleResource resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); } us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } void QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { us::Module* module = us::GetModuleContext()->GetModule(); std::vector resources = module->FindResources("/", "*", true); for (std::vector::iterator iter = resources.begin(); iter != resources.end(); ++iter) { MITK_INFO << iter->GetResourcePath(); } m_Interactor = mitk::SegmentationInteractor::New(); if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) { MITK_WARN << "Error loading state machine"; } if (!m_Interactor->SetEventConfig("ConfigSegmentation.xml", module)) { MITK_WARN << "Error loading state machine configuration"; } // Register as listener via micro services us::ServiceProperties props; props["name"] = std::string("SegmentationInteraction"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } bool QmitkMultiLabelSegmentationView::CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const { bool isSameGeometry(true); if (image1 && image2) { mitk::BaseGeometry::Pointer geo1 = image1->GetGeometry(); mitk::BaseGeometry::Pointer geo2 = image2->GetGeometry(); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetOrigin(), geo2->GetOrigin()); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(0), geo2->GetExtent(0)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(1), geo2->GetExtent(1)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetExtent(2), geo2->GetExtent(2)); isSameGeometry = isSameGeometry && mitk::Equal(geo1->GetSpacing(), geo2->GetSpacing()); isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } QString QmitkMultiLabelSegmentationView::GetLastFileOpenPath() { return this->GetPreferences()->Get("LastFileOpenPath", ""); } void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString &path) { this->GetPreferences()->Put("LastFileOpenPath", path); this->GetPreferences()->Flush(); } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h index 78bdc3abbb..95d975b91c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h @@ -1,180 +1,186 @@ /*=================================================================== 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 QmitkMultiLabelSegmentationView_h #define QmitkMultiLabelSegmentationView_h #include #include "mitkSegmentationInteractor.h" #include #include "ui_QmitkMultiLabelSegmentationControls.h" // berry #include class QmitkRenderWindow; /** * \ingroup ToolManagerEtAl * \ingroup org_mitk_gui_qt_multilabelsegmentation_internal */ class QmitkMultiLabelSegmentationView : public QmitkAbstractView, public mitk::ILifecycleAwarePart { Q_OBJECT public: static const std::string VIEW_ID; QmitkMultiLabelSegmentationView(); virtual ~QmitkMultiLabelSegmentationView(); typedef std::map NodeTagMapType; // GUI setup void CreateQtPartControl(QWidget *parent); // ILifecycleAwarePart interface public: void Activated(); void Deactivated(); void Visible(); void Hidden(); virtual int GetSizeFlags(bool width); virtual int ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult); protected slots: - /// \brief reaction to the selection of any 2D segmentation tool + // reaction to the shortcut for toggling the visibility of the working node + void OnVisibilityShortcutActivated(); + + // reaction to the shortcut for iterating over all labels + void OnLabelToggleShortcutActivated(); + + // reaction to the selection of any 2D segmentation tool void OnManualTool2DSelected(int id); - /// \brief reaction to button "New Label" + // reaction to button "New Label" void OnNewLabel(); - /// \brief reaction to button "Show Label Table" + // reaction to button "Show Label Table" void OnShowLabelTable(bool value); - /// \brief reaction to button "New Segmentation Session" + // reaction to button "New Segmentation Session" void OnNewSegmentationSession(); - /// \brief reaction to signal "goToLabel" from labelset widget + // reaction to signal "goToLabel" from labelset widget void OnGoToLabel(const mitk::Point3D &pos); void OnResetView(); // reaction to the button "Add Layer" void OnAddLayer(); // reaction to the button "Delete Layer" void OnDeleteLayer(); // reaction to the button "Previous Layer" void OnPreviousLayer(); // reaction to the button "Next Layer" void OnNextLayer(); // reaction to the combobox change "Change Layer" void OnChangeLayer(int); // reaction to the button "Deactive Active Tool" void OnDeactivateActiveTool(); // reaction to the button "Lock exterior" void OnLockExteriorToggled(bool); - /// \brief reaction to the selection of a new patient (reference) image in the DataStorage combobox + // reaction to the selection of a new patient (reference) image in the DataStorage combobox void OnReferenceSelectionChanged(const mitk::DataNode* node); - /// \brief reaction to the selection of a new Segmentation (working) image in the DataStorage combobox + // reaction to the selection of a new Segmentation (working) image in the DataStorage combobox void OnSegmentationSelectionChanged(const mitk::DataNode* node); - /// \brief reaction to ... + // reaction to ... void OnInterpolationSelectionChanged(int); protected: // reimplemented from QmitkAbstractView void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) override; // reimplemented from QmitkAbstractView void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; // reimplemented from QmitkAbstractView void NodeAdded(const mitk::DataNode* node) override; // reimplemented from QmitkAbstractView void NodeRemoved(const mitk::DataNode* node) override; void OnEstablishLabelSetConnection(); void OnLooseLabelSetConnection(); void SetFocus(); void UpdateControls(); void RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart); void RenderWindowPartDeactivated(mitk::IRenderWindowPart *renderWindowPart); void ResetMouseCursor(); void SetMouseCursor(const us::ModuleResource, int hotspotX, int hotspotY); void InitializeListeners(); /// \brief Checks if two images have the same size and geometry bool CheckForSameGeometry(const mitk::Image *image1, const mitk::Image *image2) const; QString GetLastFileOpenPath(); void SetLastFileOpenPath(const QString &path); /// \brief the Qt parent of our GUI (NOT of this object) QWidget *m_Parent; /// \brief Qt GUI file Ui::QmitkMultiLabelSegmentationControls m_Controls; mitk::IRenderWindowPart *m_IRenderWindowPart; mitk::ToolManager *m_ToolManager; mitk::DataNode::Pointer m_ReferenceNode; mitk::DataNode::Pointer m_WorkingNode; mitk::NodePredicateAnd::Pointer m_ReferencePredicate; mitk::NodePredicateAnd::Pointer m_SegmentationPredicate; bool m_AutoSelectionEnabled; bool m_MouseCursorSet; mitk::SegmentationInteractor::Pointer m_Interactor; /** * Reference to the service registration of the observer, * it is needed to unregister the observer on unload. */ us::ServiceRegistration m_ServiceRegistration; }; #endif // QmitkMultiLabelSegmentationView_h