diff --git a/Modules/Segmentation/CMakeLists.txt b/Modules/Segmentation/CMakeLists.txt index 51b663e44a..dc34053fc7 100644 --- a/Modules/Segmentation/CMakeLists.txt +++ b/Modules/Segmentation/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( INCLUDE_DIRS Algorithms Controllers DataManagement Interactions Rendering SegmentationUtilities/BooleanOperations SegmentationUtilities/MorphologicalOperations - DEPENDS MitkAlgorithmsExt MitkIpSegmentation MitkIpFunc MitkLegacyAdaptors MitkSurfaceInterpolation MitkGraphAlgorithms MitkContourModel MitkMultilabel + DEPENDS MitkAlgorithmsExt MitkIpSegmentation MitkIpFunc MitkLegacyAdaptors MitkSurfaceInterpolation MitkGraphAlgorithms MitkContourModel MitkMultilabel MitkDICOMReader PACKAGE_DEPENDS PUBLIC ITK|ITKBinaryMathematicalMorphology+ITKLabelVoting+ITKRegionGrowing+ITKFastMarching+ITKAnisotropicSmoothing+ITKWatersheds ) add_subdirectory(Testing) diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp index 0e28bc48b0..6455cf4e1a 100644 --- a/Modules/Segmentation/Interactions/mitkTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTool.cpp @@ -1,318 +1,571 @@ /*=================================================================== 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 "mitkTool.h" +#include "mitkAnatomicalStructureColorPresets.h" +#include "mitkDICOMProperty.h" #include "mitkDisplayInteractor.h" +#include "mitkIDICOMTagsOfInterest.h" #include "mitkImageReadAccessor.h" #include "mitkImageWriteAccessor.h" #include "mitkLabelSetImage.h" #include "mitkLevelWindowProperty.h" #include "mitkLookupTableProperty.h" #include "mitkProperties.h" -#include "mitkProperties.h" +#include "mitkPropertyNameHelper.h" #include "mitkVtkResliceInterpolationProperty.h" // us #include #include // itk #include mitk::Tool::Tool(const char *type) : m_PredicateImages(NodePredicateDataType::New("Image")) // for reference images , m_PredicateDim3(NodePredicateDimension::New(3, 1)), m_PredicateDim4(NodePredicateDimension::New(4, 1)), m_PredicateDimension(mitk::NodePredicateOr::New(m_PredicateDim3, m_PredicateDim4)), m_PredicateImage3D(NodePredicateAnd::New(m_PredicateImages, m_PredicateDimension)), m_PredicateBinary(NodePredicateProperty::New("binary", BoolProperty::New(true))), m_PredicateNotBinary(NodePredicateNot::New(m_PredicateBinary)), m_PredicateSegmentation(NodePredicateProperty::New("segmentation", BoolProperty::New(true))), m_PredicateNotSegmentation(NodePredicateNot::New(m_PredicateSegmentation)), m_PredicateHelper(NodePredicateProperty::New("helper object", BoolProperty::New(true))), m_PredicateNotHelper(NodePredicateNot::New(m_PredicateHelper)), m_PredicateImageColorful(NodePredicateAnd::New(m_PredicateNotBinary, m_PredicateNotSegmentation)), m_PredicateImageColorfulNotHelper(NodePredicateAnd::New(m_PredicateImageColorful, m_PredicateNotHelper)), m_PredicateReference(NodePredicateAnd::New(m_PredicateImage3D, m_PredicateImageColorfulNotHelper)), m_IsSegmentationPredicate( NodePredicateAnd::New(NodePredicateOr::New(m_PredicateBinary, m_PredicateSegmentation), m_PredicateNotHelper)), m_InteractorType(type), m_DisplayInteractorConfigs(), m_EventConfig("DisplayConfigMITK.xml") { } mitk::Tool::~Tool() { } bool mitk::Tool::CanHandle(BaseData *) const { return true; } void mitk::Tool::InitializeStateMachine() { if (m_InteractorType.empty()) return; m_InteractorType += ".xml"; try { LoadStateMachine(m_InteractorType, us::GetModuleContext()->GetModule()); SetEventConfig("SegmentationToolsConfig.xml", us::GetModuleContext()->GetModule()); } catch (const std::exception &e) { MITK_ERROR << "Could not load statemachine pattern " << m_InteractorType << " with exception: " << e.what(); } } void mitk::Tool::Notify(InteractionEvent *interactionEvent, bool isHandled) { // to use the state machine pattern, // the event is passed to the state machine interface to be handled if (!isHandled) { this->HandleEvent(interactionEvent, nullptr); } } void mitk::Tool::ConnectActionsAndFunctions() { } bool mitk::Tool::FilterEvents(InteractionEvent *, DataNode *) { return true; } const char *mitk::Tool::GetGroup() const { return "default"; } void mitk::Tool::SetToolManager(ToolManager *manager) { m_ToolManager = manager; } void mitk::Tool::Activated() { // As a legacy solution the display interaction of the new interaction framework is disabled here to avoid conflicts // with tools // Note: this only affects InteractionEventObservers (formerly known as Listeners) all DataNode specific interaction // will still be enabled m_DisplayInteractorConfigs.clear(); std::vector> listEventObserver = us::GetModuleContext()->GetServiceReferences(); for (std::vector>::iterator it = listEventObserver.begin(); it != listEventObserver.end(); ++it) { DisplayInteractor *displayInteractor = dynamic_cast(us::GetModuleContext()->GetService(*it)); if (displayInteractor != nullptr) { // remember the original configuration m_DisplayInteractorConfigs.insert(std::make_pair(*it, displayInteractor->GetEventConfig())); // here the alternative configuration is loaded displayInteractor->SetEventConfig(m_EventConfig.c_str()); } } } void mitk::Tool::Deactivated() { // Re-enabling InteractionEventObservers that have been previously disabled for legacy handling of Tools // in new interaction framework for (std::map::iterator it = m_DisplayInteractorConfigs.begin(); it != m_DisplayInteractorConfigs.end(); ++it) { if (it->first) { DisplayInteractor *displayInteractor = static_cast(us::GetModuleContext()->GetService(it->first)); if (displayInteractor != nullptr) { // here the regular configuration is loaded again displayInteractor->SetEventConfig(it->second); } } } m_DisplayInteractorConfigs.clear(); } itk::Object::Pointer mitk::Tool::GetGUI(const std::string &toolkitPrefix, const std::string &toolkitPostfix) { itk::Object::Pointer object; std::string classname = this->GetNameOfClass(); std::string guiClassname = toolkitPrefix + classname + toolkitPostfix; std::list allGUIs = itk::ObjectFactoryBase::CreateAllInstance(guiClassname.c_str()); for (std::list::iterator iter = allGUIs.begin(); iter != allGUIs.end(); ++iter) { if (object.IsNull()) { object = dynamic_cast(iter->GetPointer()); } else { MITK_ERROR << "There is more than one GUI for " << classname << " (several factories claim ability to produce a " << guiClassname << " ) " << std::endl; return nullptr; // people should see and fix this error } } return object; } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetReferenceDataPreference() const { return m_PredicateReference.GetPointer(); } mitk::NodePredicateBase::ConstPointer mitk::Tool::GetWorkingDataPreference() const { return m_IsSegmentationPredicate.GetPointer(); } mitk::DataNode::Pointer mitk::Tool::CreateEmptySegmentationNode(Image *original, const std::string &organName, const mitk::Color &color) { // we NEED a reference image for size etc. if (!original) return nullptr; // actually create a new empty segmentation PixelType pixelType(mitk::MakeScalarPixelType()); LabelSetImage::Pointer segmentation = LabelSetImage::New(); if (original->GetDimension() == 2) { const unsigned int dimensions[] = {original->GetDimension(0), original->GetDimension(1), 1}; segmentation->Initialize(pixelType, 3, dimensions); segmentation->AddLayer(); } else { segmentation->Initialize(original); } mitk::Label::Pointer label = mitk::Label::New(); label->SetName(organName); label->SetColor(color); label->SetValue(1); segmentation->GetActiveLabelSet()->AddLabel(label); segmentation->GetActiveLabelSet()->SetActiveLabel(1); unsigned int byteSize = sizeof(mitk::Label::PixelType); if (segmentation->GetDimension() < 4) { for (unsigned int dim = 0; dim < segmentation->GetDimension(); ++dim) { byteSize *= segmentation->GetDimension(dim); } mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(0)); memset(writeAccess.GetData(), 0, byteSize); } else { // if we have a time-resolved image we need to set memory to 0 for each time step for (unsigned int dim = 0; dim < 3; ++dim) { byteSize *= segmentation->GetDimension(dim); } for (unsigned int volumeNumber = 0; volumeNumber < segmentation->GetDimension(3); volumeNumber++) { mitk::ImageWriteAccessor writeAccess(segmentation.GetPointer(), segmentation->GetVolumeData(volumeNumber)); memset(writeAccess.GetData(), 0, byteSize); } } if (original->GetTimeGeometry()) { TimeGeometry::Pointer originalGeometry = original->GetTimeGeometry()->Clone(); segmentation->SetTimeGeometry(originalGeometry); } else { Tool::ErrorMessage("Original image does not have a 'Time sliced geometry'! Cannot create a segmentation."); return nullptr; } + // Add some DICOM Tags as properties to segmentation image + AddDICOMTagsToSegmentation(original, segmentation, organName, color); + return CreateSegmentationNode(segmentation, organName, color); } mitk::DataNode::Pointer mitk::Tool::CreateSegmentationNode(Image *image, const std::string &organName, const mitk::Color &color) { if (!image) return nullptr; // decorate the datatreenode with some properties DataNode::Pointer segmentationNode = DataNode::New(); segmentationNode->SetData(image); // name segmentationNode->SetProperty("name", StringProperty::New(organName)); // visualization properties segmentationNode->SetProperty("binary", BoolProperty::New(true)); segmentationNode->SetProperty("color", ColorProperty::New(color)); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::MULTILABEL); mitk::LookupTableProperty::Pointer lutProp = mitk::LookupTableProperty::New(); lutProp->SetLookupTable(lut); segmentationNode->SetProperty("LookupTable", lutProp); segmentationNode->SetProperty("texture interpolation", BoolProperty::New(false)); segmentationNode->SetProperty("layer", IntProperty::New(10)); segmentationNode->SetProperty("levelwindow", LevelWindowProperty::New(LevelWindow(0.5, 1))); segmentationNode->SetProperty("opacity", FloatProperty::New(0.3)); segmentationNode->SetProperty("segmentation", BoolProperty::New(true)); segmentationNode->SetProperty("reslice interpolation", VtkResliceInterpolationProperty::New()); // otherwise -> segmentation appears in 2 // slices sometimes (only visual effect, not // different data) // For MITK-3M3 release, the volume of all segmentations should be shown segmentationNode->SetProperty("showVolume", BoolProperty::New(true)); return segmentationNode; } +void mitk::Tool::AddDICOMTagsToSegmentation(Image *original, + Image *segmentation, + const std::string &organName, + const mitk::Color &color) +{ + mitk::AnatomicalStructureColorPresets::Category category; + mitk::AnatomicalStructureColorPresets::Type type; + mitk::AnatomicalStructureColorPresets *anatomicalStructureColorPresets = mitk::AnatomicalStructureColorPresets::New(); + anatomicalStructureColorPresets->LoadPreset(); + + for (const auto &preset : anatomicalStructureColorPresets->GetCategoryPresets()) + { + auto presetOrganName = preset.first; + if (organName.compare(presetOrganName) == 0) + { + category = preset.second; + break; + } + } + + for (const auto &preset : anatomicalStructureColorPresets->GetTypePresets()) + { + auto presetOrganName = preset.first; + if (organName.compare(presetOrganName) == 0) + { + type = preset.second; + break; + } + } + + // Add DICOM Tag (0008, 0060) Modality "SEG" + segmentation->SetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str(), StringProperty::New("SEG")); + // Add DICOM Tag (0008,103E) Series Description + segmentation->SetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103E).c_str(), + StringProperty::New("Segmentation")); + //------------------------------------------------------------ + // Add Segment Sequence tags (0062, 0002) + mitk::DICOMTagPath segmentSequencePath; + segmentSequencePath.AddElement(0x0062, 0x0002); + + // Segment Number:Identification number of the segment.The value of Segment Number(0062, 0004) shall be unique within + // the Segmentation instance in which it is created + mitk::DICOMTagPath segmentNumberPath; + segmentNumberPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0004); + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentNumberPath).c_str(), StringProperty::New("1")); + + // Segment Label: User-defined label identifying this segment. + mitk::DICOMTagPath segmentLabelPath; + segmentLabelPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0005); + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentLabelPath).c_str(), StringProperty::New(organName)); + + // Segment Algorithm Type: Type of algorithm used to generate the segment. AUTOMATIC SEMIAUTOMATIC MANUAL + mitk::DICOMTagPath segmentAlgorithmTypePath; + segmentAlgorithmTypePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0008); + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentAlgorithmTypePath).c_str(), + StringProperty::New("SEMIAUTOMATIC")); + //------------------------------------------------------------ + // Add Segmented Property Category Code Sequence tags (0062, 0003): Sequence defining the general category of this + // segment. + mitk::DICOMTagPath segmentSegmentedPropertyCategorySequencePath; + segmentSegmentedPropertyCategorySequencePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003); + // (0008,0100) Code Value + mitk::DICOMTagPath segmentCategoryCodeValuePath; + segmentCategoryCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0100); + if (!category.codeValue.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeValuePath).c_str(), + StringProperty::New(category.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentCategoryCodeSchemePath; + segmentCategoryCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0102); + if (!category.codeScheme.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeSchemePath).c_str(), + StringProperty::New(category.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentCategoryCodeMeaningPath; + segmentCategoryCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0104); + if (!category.codeName.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeMeaningPath).c_str(), + StringProperty::New(category.codeName)); + //------------------------------------------------------------ + // Add Segmented Property Type Code Sequence (0062, 000F): Sequence defining the specific property type of this + // segment. + mitk::DICOMTagPath segmentSegmentedPropertyTypeSequencePath; + segmentSegmentedPropertyTypeSequencePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F); + + // (0008,0100) Code Value + mitk::DICOMTagPath segmentTypeCodeValuePath; + segmentTypeCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0100); + if (!type.codeValue.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeValuePath).c_str(), + StringProperty::New(type.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentTypeCodeSchemePath; + segmentTypeCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0102); + if (!type.codeScheme.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeSchemePath).c_str(), + StringProperty::New(type.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentTypeCodeMeaningPath; + segmentTypeCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0104); + if (!type.codeName.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeMeaningPath).c_str(), + StringProperty::New(type.codeName)); + //------------------------------------------------------------ + // Add Segmented Property Type Modifier Code Sequence (0062,0011): Sequence defining the modifier of the property type + // of this segment. + mitk::DICOMTagPath segmentSegmentedPropertyModifierSequencePath; + segmentSegmentedPropertyModifierSequencePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011); + // (0008,0100) Code Value + mitk::DICOMTagPath segmentModifierCodeValuePath; + segmentModifierCodeValuePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0100); + if (!type.modifier.codeValue.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeValuePath).c_str(), + StringProperty::New(type.modifier.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentModifierCodeSchemePath; + segmentModifierCodeSchemePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0102); + if (!type.modifier.codeScheme.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeSchemePath).c_str(), + StringProperty::New(type.modifier.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentModifierCodeMeaningPath; + segmentModifierCodeMeaningPath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0104); + if (!type.modifier.codeName.empty()) + segmentation->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeMeaningPath).c_str(), + StringProperty::New(type.modifier.codeName)); + + //============================TODO: Not here:-) + mitk::IDICOMTagsOfInterest *toiService = nullptr; + + std::vector> toiRegisters = + us::GetModuleContext()->GetServiceReferences(); + if (!toiRegisters.empty()) + { + if (toiRegisters.size() > 1) + MITK_WARN << "Multiple DICOM tags of interest services found. Using just one."; + toiService = us::GetModuleContext()->GetService(toiRegisters.front()); + } + + if (toiService != nullptr) + { + toiService->AddTagOfInterest(segmentSequencePath); + + toiService->AddTagOfInterest(segmentNumberPath); + toiService->AddTagOfInterest(segmentLabelPath); + toiService->AddTagOfInterest(segmentAlgorithmTypePath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyCategorySequencePath); + toiService->AddTagOfInterest(segmentCategoryCodeValuePath); + toiService->AddTagOfInterest(segmentCategoryCodeSchemePath); + toiService->AddTagOfInterest(segmentCategoryCodeMeaningPath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyTypeSequencePath); + toiService->AddTagOfInterest(segmentTypeCodeValuePath); + toiService->AddTagOfInterest(segmentTypeCodeSchemePath); + toiService->AddTagOfInterest(segmentTypeCodeMeaningPath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyModifierSequencePath); + toiService->AddTagOfInterest(segmentModifierCodeValuePath); + toiService->AddTagOfInterest(segmentModifierCodeSchemePath); + toiService->AddTagOfInterest(segmentModifierCodeMeaningPath); + } + + //============================ + // Check if original image is a DICOM image; if so, store relevant DICOM Tags into the PropertyList of new + // segmentation image + bool parentIsDICOM = false; + + for (const auto &element : *(original->GetPropertyList()->GetMap())) + { + if (element.first.find("DICOM") == 0) + { + parentIsDICOM = true; + break; + } + } + + if (!parentIsDICOM) + return; + + //====== Patient information ====== + + // Add DICOM Tag (0010,0010) patient's name; default "No Name" + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0010, 0x0010), "NO NAME"); + // Add DICOM Tag (0010,0020) patient id; default "No Name" + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0010, 0x0020), "NO NAME"); + // Add DICOM Tag (0010,0030) patient's birth date; no default + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0010, 0x0030)); + // Add DICOM Tag (0010,0040) patient's sex; default "U" (Unknown) + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0010, 0x0040), "U"); + + //====== General study ====== + + // Add DICOM Tag (0020,000D) Study Instance UID; no default --> MANDATORY! + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0020, 0x000D)); + // Add DICOM Tag (0080,0020) Study Date; no default (think about "today") + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0080, 0x0020)); + // Add DICOM Tag (0008,0050) Accession Number; no default + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0008, 0x0050)); + // Add DICOM Tag (0008,1030) Study Description; no default + this->SetReferenceDICOMProperty(original, segmentation, DICOMTag(0x0008, 0x1030)); + + //====== Reference DICOM data ====== + + // Add reference file paths to referenced DICOM data + BaseProperty::Pointer dcmFilesProp = original->GetProperty("files"); + if (dcmFilesProp.IsNotNull()) + segmentation->SetProperty("files", dcmFilesProp); +} + +void mitk::Tool::SetReferenceDICOMProperty(Image *original, + Image *segmentation, + const DICOMTag &tag, + const std::string &defaultString) +{ + std::string tagString = GeneratePropertyNameForDICOMTag(tag.GetGroup(), tag.GetElement()); + + // Get DICOM property from referenced image + BaseProperty::Pointer originalProperty = original->GetProperty(tagString.c_str()); + + // if property exists, copy the informtaion to the segmentation + if (originalProperty.IsNotNull()) + segmentation->SetProperty(tagString.c_str(), originalProperty); + else // use the default value, if there is one + { + if (!defaultString.empty()) + segmentation->SetProperty(tagString.c_str(), StringProperty::New(defaultString).GetPointer()); + } +} + us::ModuleResource mitk::Tool::GetIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } us::ModuleResource mitk::Tool::GetCursorIconResource() const { // Each specific tool should load its own resource. This one will be invalid return us::ModuleResource(); } diff --git a/Modules/Segmentation/Interactions/mitkTool.h b/Modules/Segmentation/Interactions/mitkTool.h index 45035169e3..ee723d176d 100644 --- a/Modules/Segmentation/Interactions/mitkTool.h +++ b/Modules/Segmentation/Interactions/mitkTool.h @@ -1,269 +1,279 @@ /*=================================================================== 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 mitkTool_h_Included #define mitkTool_h_Included #include "itkObjectFactoryBase.h" #include "itkVersion.h" #include "mitkCommon.h" +#include "mitkDICOMTag.h" #include "mitkDataNode.h" #include "mitkMessage.h" #include "mitkNodePredicateAnd.h" #include "mitkNodePredicateDataType.h" #include "mitkNodePredicateDimension.h" #include "mitkNodePredicateNot.h" #include "mitkNodePredicateOr.h" #include "mitkNodePredicateProperty.h" #include "mitkToolEvents.h" #include "mitkToolFactoryMacro.h" #include #include #include #include #include #include "usServiceRegistration.h" #include "mitkEventStateMachine.h" #include "mitkInteractionEventObserver.h" #include namespace us { class ModuleResource; } namespace mitk { class ToolManager; /** \brief Base class of all tools used by mitk::ToolManager. \sa ToolManager \sa SegTool2D \ingroup Interaction \ingroup ToolManagerEtAl There is a separate page describing the \ref QmitkInteractiveSegmentationTechnicalPage. Every tool is a mitk::StateMachine, which can follow any transition pattern that it likes. One important thing to know is, that every derived tool should always call SuperClass::Deactivated() at the end of its own implementation of Deactivated, because mitk::Tool resets the StateMachine in this method. Only if you are very sure that you covered all possible things that might happen to your own tool, you should consider not to reset the StateMachine from time to time. To learn about the MITK implementation of state machines in general, have a look at \ref InteractionPage. To derive a non-abstract tool, you inherit from mitk::Tool (or some other base class further down the inheritance tree), and in your own parameterless constructor (that is called from the itkFactorylessNewMacro that you use) you pass a StateMachine pattern name to the superclass. Names for valid patterns can be found in StateMachine.xml (which might be enhanced by you). You have to implement at least GetXPM() and GetName() to provide some identification. Each Tool knows its ToolManager, which can provide the data that the tool should work on. \warning Only to be instantiated by mitk::ToolManager (because SetToolManager has to be called). All other uses are unsupported. $Author$ */ class MITKSEGMENTATION_EXPORT Tool : public EventStateMachine, public InteractionEventObserver { public: typedef mitk::Label::PixelType DefaultSegmentationDataType; /** * \brief To let GUI process new events (e.g. qApp->processEvents() ) */ Message<> GUIProcessEventsMessage; /** * \brief To send error messages (to be shown by some GUI) */ Message1 ErrorMessage; /** * \brief To send whether the tool is busy (to be shown by some GUI) */ Message1 CurrentlyBusy; /** * \brief To send general messages (to be shown by some GUI) */ Message1 GeneralMessage; mitkClassMacro(Tool, EventStateMachine); // no New(), there should only be subclasses /** \brief Returns an icon in the XPM format. This icon has to fit into some kind of button in most applications, so make it smaller than 25x25 pixels. XPM is e.g. supported by The Gimp. But if you open any XPM file in your text editor, you will see that you could also "draw" it with an editor. */ virtual const char **GetXPM() const = 0; /** * \brief Returns the path of an icon. * * This icon is preferred to the XPM icon. */ virtual std::string GetIconPath() const { return ""; } /** * \brief Returns the path of a cursor icon. * */ virtual us::ModuleResource GetCursorIconResource() const; /** * @brief Returns the tool button icon of the tool wrapped by a usModuleResource * @return a valid ModuleResource or an invalid if this function * is not reimplemented */ virtual us::ModuleResource GetIconResource() const; /** \brief Returns the name of this tool. Make it short! This name has to fit into some kind of button in most applications, so take some time to think of a good name! */ virtual const char *GetName() const = 0; /** \brief Name of a group. You can group several tools by assigning a group name. Graphical tool selectors might use this information to group tools. (What other reason could there be?) */ virtual const char *GetGroup() const; virtual void InitializeStateMachine(); /** * \brief Interface for GUI creation. * * This is the basic interface for creation of a GUI object belonging to one tool. * * Tools that support a GUI (e.g. for display/editing of parameters) should follow some rules: * * - A Tool and its GUI are two separate classes * - There may be several instances of a GUI at the same time. * - mitk::Tool is toolkit (Qt, wxWidgets, etc.) independent, the GUI part is of course dependent * - The GUI part inherits both from itk::Object and some GUI toolkit class * - The GUI class name HAS to be constructed like "toolkitPrefix" tool->GetClassName() + "toolkitPostfix", e.g. * MyTool -> wxMyToolGUI * - For each supported toolkit there is a base class for tool GUIs, which contains some convenience methods * - Tools notify the GUI about changes using ITK events. The GUI must observe interesting events. * - The GUI base class may convert all ITK events to the GUI toolkit's favoured messaging system (Qt -> signals) * - Calling methods of a tool by its GUI is done directly. * In some cases GUIs don't want to be notified by the tool when they cause a change in a tool. * There is a macro CALL_WITHOUT_NOTICE(method()), which will temporarily disable all notifications during a * method call. */ virtual itk::Object::Pointer GetGUI(const std::string &toolkitPrefix, const std::string &toolkitPostfix); virtual NodePredicateBase::ConstPointer GetReferenceDataPreference() const; virtual NodePredicateBase::ConstPointer GetWorkingDataPreference() const; DataNode::Pointer CreateEmptySegmentationNode(Image *original, const std::string &organName, const mitk::Color &color); DataNode::Pointer CreateSegmentationNode(Image *image, const std::string &organName, const mitk::Color &color); virtual bool CanHandle(BaseData *referenceData) const; protected: friend class ToolManager; virtual void SetToolManager(ToolManager *); void ConnectActionsAndFunctions() override; /** \brief Called when the tool gets activated. Derived tools should call their parents implementation at the beginning of the overriding function. */ virtual void Activated(); /** \brief Called when the tool gets deactivated. Derived tools should call their parents implementation at the end of the overriding function. */ virtual void Deactivated(); /** \brief Let subclasses change their event configuration. */ std::string m_EventConfig; Tool(); // purposely hidden Tool(const char *); // purposely hidden virtual ~Tool(); virtual void Notify(InteractionEvent *interactionEvent, bool isHandled) override; bool FilterEvents(InteractionEvent *, DataNode *) override; ToolManager *m_ToolManager; private: + void AddDICOMTagsToSegmentation(Image *original, + Image *segmentation, + const std::string &organName, + const mitk::Color &color); + void SetReferenceDICOMProperty(Image *original, + Image *segmentation, + const DICOMTag &tag, + const std::string &defaultString = ""); + // for reference data NodePredicateDataType::Pointer m_PredicateImages; NodePredicateDimension::Pointer m_PredicateDim3; NodePredicateDimension::Pointer m_PredicateDim4; NodePredicateOr::Pointer m_PredicateDimension; NodePredicateAnd::Pointer m_PredicateImage3D; NodePredicateProperty::Pointer m_PredicateBinary; NodePredicateNot::Pointer m_PredicateNotBinary; NodePredicateProperty::Pointer m_PredicateSegmentation; NodePredicateNot::Pointer m_PredicateNotSegmentation; NodePredicateProperty::Pointer m_PredicateHelper; NodePredicateNot::Pointer m_PredicateNotHelper; NodePredicateAnd::Pointer m_PredicateImageColorful; NodePredicateAnd::Pointer m_PredicateImageColorfulNotHelper; NodePredicateAnd::Pointer m_PredicateReference; // for working data NodePredicateAnd::Pointer m_IsSegmentationPredicate; std::string m_InteractorType; std::map m_DisplayInteractorConfigs; }; } // namespace #endif 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 820a80a8fb..036858380d 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,991 +1,1281 @@ /*=================================================================== 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 +#include // mitk +#include "mitkApplicationCursor.h" #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" -#include "mitkApplicationCursor.h" #include "mitkToolManagerProvider.h" //#include "mitkSegmentationObjectFactory.h" -#include "mitkSegTool2D.h" +#include "mitkDICOMTag.h" +#include "mitkDICOMTagPath.h" +#include "mitkIDICOMTagsOfInterest.h" +#include "mitkInteractionEventObserver.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" -#include "mitkInteractionEventObserver.h" +#include "mitkPropertyNameHelper.h" +#include "mitkSegTool2D.h" // Qmitk -#include "QmitkSegmentationOrganNamesHandling.cpp" -#include "QmitkRenderWindow.h" #include "QmitkNewSegmentationDialog.h" +#include "QmitkRenderWindow.h" +#include "QmitkSegmentationOrganNamesHandling.cpp" // us -#include -#include #include +#include #include +#include #include // Qt -#include -#include -#include #include +#include +#include +#include #include "tinyxml.h" #include const std::string QmitkMultiLabelSegmentationView::VIEW_ID = "org.mitk.views.multilabelsegmentation"; -QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() : - m_Parent(NULL), - m_IRenderWindowPart(NULL), - m_ReferenceNode(NULL), - m_ToolManager(NULL), - m_WorkingNode(NULL), - m_MouseCursorSet(false) +QmitkMultiLabelSegmentationView::QmitkMultiLabelSegmentationView() + : m_Parent(NULL), + m_IRenderWindowPart(NULL), + m_ReferenceNode(NULL), + m_ToolManager(NULL), + m_WorkingNode(NULL), + 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::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 isQbi = mitk::NodePredicateDataType::New("QBallImage"); mitk::NodePredicateOr::Pointer validImages = mitk::NodePredicateOr::New(); validImages->AddPredicate(isImage); validImages->AddPredicate(isDwi); validImages->AddPredicate(isDti); validImages->AddPredicate(isQbi); 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); + // 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(NULL); - //m_ToolManager->SetWorkingData(NULL); + */ + // m_ToolManager->SetReferenceData(NULL); + // m_ToolManager->SetWorkingData(NULL); - //m_ServiceRegistration.Unregister(); + // m_ServiceRegistration.Unregister(); - //Loose LabelSetConnections + // Loose LabelSetConnections OnLooseLabelSetConnection(); } -void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget* parent) +void QmitkMultiLabelSegmentationView::CreateQtPartControl(QWidget *parent) { // setup the basic GUI of this view m_Parent = parent; + m_Controls.setupUi(parent); // *------------------------ // * 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_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* ) ) ); + 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->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); - //use the same ToolManager instance for our 3D Tools + // 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_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)) ); - + 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->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 ); + 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(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()) ); - + 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; + 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(); + // 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)) ); + 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 } void QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { - us::Module* module = us::GetModuleContext()->GetModule(); + 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)) + 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); + m_ServiceRegistration = + us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } -void QmitkMultiLabelSegmentationView::SetFocus () +void QmitkMultiLabelSegmentationView::SetFocus() { } 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()); + isSameGeometry = isSameGeometry && mitk::MatrixEqualElementWise(geo1->GetIndexToWorldTransform()->GetMatrix(), + geo2->GetIndexToWorldTransform()->GetMatrix()); return isSameGeometry; } else { return false; } } -void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) +void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); - QList controllers; + 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*/) +void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart * /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = 0; m_Parent->setEnabled(false); } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { - if(!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) +int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, + int /*availableParallel*/, + int /*availablePerpendicular*/, + int preferredResult) { - if(width==false) + if (width == false) { return 100; } else { return preferredResult; } } void QmitkMultiLabelSegmentationView::UpdateControls() { - mitk::DataNode* referenceNode = m_ToolManager->GetReferenceData(0); + mitk::DataNode *referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != NULL; - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); bool hasValidWorkingNode = workingNode != NULL; 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); + m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( + QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); + m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( + QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); - if(hasValidWorkingNode) + if (hasValidWorkingNode) { // TODO adapt tool manager so that this check is done there, e.g. convenience function - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + 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; lidxGetNumberOfLayers(); ++lidx) + 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); + // MLI TODO + // m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } } - if(hasValidWorkingNode && hasReferenceNode) + if (hasValidWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { - mitk::DataNode* referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); + 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."); + 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() ); + 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; + if (!ok) + return; this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } - catch ( mitk::Exception& e ) + 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())); + workingImage->GetExteriorLabel()->SetProperty("name.parent", + mitk::StringProperty::New(referenceNode->GetName().c_str())); + workingImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newName.toStdString().c_str())); + this->AddDICOMSegmentationProperties(workingImage, referenceImage); if (!this->GetDataStorage()->Exists(workingNode)) this->GetDataStorage()->Add(workingNode, referenceNode); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); OnNewLabel(); } void QmitkMultiLabelSegmentationView::OnNewLabel() { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + 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."); + 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()); + 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."); + 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() ); + QmitkNewSegmentationDialog *dialog = new QmitkNewSegmentationDialog(m_Parent); + dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); - if ( dialogReturnValue == QDialog::Rejected ) return; + if (dialogReturnValue == QDialog::Rejected) + return; QString segName = dialog->GetSegmentationName(); - if(segName.isEmpty()) segName = "Unnamed"; + if (segName.isEmpty()) + segName = "Unnamed"; workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); + this->AddDICOMSegmentProperties(workingImage->GetActiveLabel()); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnShowLabelTable(bool value) { if (value) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } void QmitkMultiLabelSegmentationView::OnNextLayer() { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); - OnChangeLayer(workingImage->GetActiveLayer() + 1 ); + OnChangeLayer(workingImage->GetActiveLayer() + 1); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); - OnChangeLayer(workingImage->GetActiveLayer() - 1 ); + OnChangeLayer(workingImage->GetActiveLayer() - 1); } - void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + 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); + QMessageBox::StandardButton answerButton = QMessageBox::question( + m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); - if (answerButton != QMessageBox::Yes) return; + if (answerButton != QMessageBox::Yes) + return; try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } - catch ( mitk::Exception& e ) + 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"); + 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::OnAddLayer() { m_ToolManager->ActivateTool(-1); - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + 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); + QMessageBox::StandardButton answerButton = QMessageBox::question( + m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); - if (answerButton != QMessageBox::Yes) return; + if (answerButton != QMessageBox::Yes) + return; int newLabelSetId = -1; try { WaitCursorOn(); newLabelSetId = workingImage->AddLayer(); WaitCursorOff(); } - catch ( mitk::Exception& e ) + 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"); + QMessageBox::information( + m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } // Update controls and label set list for direct response m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); OnNewLabel(); UpdateControls(); } void QmitkMultiLabelSegmentationView::OnDeactivateActiveTool() { m_ToolManager->ActivateTool(-1); } void QmitkMultiLabelSegmentationView::OnLockExteriorToggled(bool checked) { - mitk::DataNode* workingNode = m_ToolManager->GetWorkingData(0); + mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); - mitk::LabelSetImage* workingImage = dynamic_cast(workingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } -void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode*) +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()); + mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); - if (workingImage->GetNumberOfLabels() > 2) - m_Controls.m_LabelSetWidget->show(); - else - m_Controls.m_LabelSetWidget->hide(); + if (workingImage->GetNumberOfLabels() > 2) + m_Controls.m_LabelSetWidget->show(); + else + m_Controls.m_LabelSetWidget->hide(); } */ } -void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode* node) +void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); - if (isHelperObject) return; + if (isHelperObject) + return; - if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) + 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))); + mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( + node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); - ctkPluginContext* context = mitk::PluginActivator::getContext(); + ctkPluginContext *context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); - mitk::PlanePositionManagerService* service = context->getService(ppmRef); + mitk::PlanePositionManagerService *service = context->getService(ppmRef); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) + 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; + unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = NULL; } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { - m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false);//OnToggleWidgetActivation(false); + 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(); } } -void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged( const mitk::DataNode* node ) +void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(const mitk::DataNode *node) { m_ToolManager->ActivateTool(-1); - m_ReferenceNode = const_cast(node); + m_ReferenceNode = const_cast(node); m_ToolManager->SetReferenceData(m_ReferenceNode); - //check match of segmentation and reference image geometries + // check match of segmentation and reference image geometries if (node && m_WorkingNode.IsNotNull()) { - mitk::Image* workingImage = dynamic_cast(m_WorkingNode->GetData()); + mitk::Image *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); - mitk::Image* refImage = dynamic_cast(node->GetData()); + mitk::Image *refImage = dynamic_cast(node->GetData()); assert(refImage); if (!this->CheckForSameGeometry(refImage, workingImage)) return; } this->UpdateControls(); - //m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); + // m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnEstablishLabelSetConnection() { MITK_INFO << "Connection Established"; if (m_WorkingNode.IsNull()) { return; } - mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); + 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()); + 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::OnSegmentationSelectionChanged(const mitk::DataNode *node) { m_ToolManager->ActivateTool(-1); - if(m_WorkingNode.IsNotNull()) + if (m_WorkingNode.IsNotNull()) { - mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); - //Loose LabelSetConnections + // Loose LabelSetConnections OnLooseLabelSetConnection(); } - m_WorkingNode = const_cast(node); + m_WorkingNode = const_cast(node); - if(m_WorkingNode.IsNotNull()) + if (m_WorkingNode.IsNotNull()) { - mitk::LabelSetImage* workingImage = dynamic_cast(m_WorkingNode->GetData()); + mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); - //Establish LabelSetConnection + // Establish LabelSetConnection OnEstablishLabelSetConnection(); } m_ToolManager->SetWorkingData(m_WorkingNode); - //check match of segmentation and reference image geometries + // check match of segmentation and reference image geometries if (node && m_ReferenceNode.IsNotNull()) { - mitk::Image* refImage = dynamic_cast(m_ReferenceNode->GetData()); + mitk::Image *refImage = dynamic_cast(m_ReferenceNode->GetData()); assert(refImage); - mitk::Image* workingImage = dynamic_cast(node->GetData()); + mitk::Image *workingImage = dynamic_cast(node->GetData()); assert(workingImage); if (!this->CheckForSameGeometry(refImage, workingImage)) return; } if (m_WorkingNode.IsNotNull()) { mitk::DataStorage::SetOfObjects::ConstPointer segNodes = this->GetDataStorage()->GetSubset(m_SegmentationPredicate); - for(mitk::DataStorage::SetOfObjects::const_iterator iter = segNodes->begin(); iter != segNodes->end(); ++iter) + for (mitk::DataStorage::SetOfObjects::const_iterator iter = segNodes->begin(); iter != segNodes->end(); ++iter) { - mitk::DataNode* _segNode = *iter; + mitk::DataNode *_segNode = *iter; _segNode->SetVisibility(false); } m_WorkingNode->SetVisibility(true); } this->UpdateControls(); if (m_WorkingNode.IsNotNull()) { m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } } 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::OnPreferencesChanged(const berry::IBerryPreferences* prefs) +void QmitkMultiLabelSegmentationView::OnPreferencesChanged(const berry::IBerryPreferences *prefs) { if (m_Parent && m_WorkingNode.IsNotNull()) { 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; + 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) + 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()); + 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 { // 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(); } } } } } void QmitkMultiLabelSegmentationView::ResetMouseCursor() { - if ( m_MouseCursorSet ) + if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } -void QmitkMultiLabelSegmentationView::SetMouseCursor( const us::ModuleResource resource, int hotspotX, int hotspotY ) +void QmitkMultiLabelSegmentationView::SetMouseCursor(const us::ModuleResource resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor - if ( m_MouseCursorSet ) + if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); } us::ModuleResourceStream cursor(resource, std::ios::binary); - mitk::ApplicationCursor::GetInstance()->PushCursor( cursor, hotspotX, hotspotY ); + mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } -void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D& pos) +void QmitkMultiLabelSegmentationView::OnGoToLabel(const mitk::Point3D &pos) { if (m_IRenderWindowPart) m_IRenderWindowPart->SetSelectedPosition(pos); } void QmitkMultiLabelSegmentationView::OnResetView() { if (m_IRenderWindowPart) m_IRenderWindowPart->ForceImmediateUpdate(); } QString QmitkMultiLabelSegmentationView::GetLastFileOpenPath() { return this->GetPreferences()->Get("LastFileOpenPath", ""); } -void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString& path) +void QmitkMultiLabelSegmentationView::SetLastFileOpenPath(const QString &path) { this->GetPreferences()->Put("LastFileOpenPath", path); this->GetPreferences()->Flush(); } + +void QmitkMultiLabelSegmentationView::AddDICOMSegmentationProperties(mitk::LabelSetImage::Pointer image, + mitk::Image::Pointer reference) +{ + // Add DICOM Tag (0008, 0060) Modality "SEG" + image->SetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str(), mitk::StringProperty::New("SEG")); + // Add DICOM Tag (0008,103E) Series Description + image->SetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103E).c_str(), + mitk::StringProperty::New("Segmentation")); + + // Check if original image is a DICOM image; if so, store relevant DICOM Tags into the PropertyList of new + // segmentation image + bool parentIsDICOM = false; + + for (const auto &element : *(reference->GetPropertyList()->GetMap())) + { + if (element.first.find("DICOM") == 0) + { + parentIsDICOM = true; + break; + } + } + + if (!parentIsDICOM) + return; + + //====== Patient information ====== + + // Add DICOM Tag (0010,0010) patient's name; default "No Name" + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0010, 0x0010), "NO NAME"); + // Add DICOM Tag (0010,0020) patient id; default "No Name" + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0010, 0x0020), "NO NAME"); + // Add DICOM Tag (0010,0030) patient's birth date; no default + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0010, 0x0030)); + // Add DICOM Tag (0010,0040) patient's sex; default "U" (Unknown) + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0010, 0x0040), "U"); + + //====== General study ====== + + // Add DICOM Tag (0020,000D) Study Instance UID; no default --> MANDATORY! + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0020, 0x000D)); + // Add DICOM Tag (0080,0020) Study Date; no default (think about "today") + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0080, 0x0020)); + // Add DICOM Tag (0008,0050) Accession Number; no default + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0008, 0x0050)); + // Add DICOM Tag (0008,1030) Study Description; no default + this->SetReferenceDICOMProperty(reference, image, mitk::DICOMTag(0x0008, 0x1030)); + + //====== Reference DICOM data ====== + + // Add reference file paths to referenced DICOM data + mitk::BaseProperty::Pointer dcmFilesProp = reference->GetProperty("files"); + if (dcmFilesProp.IsNotNull()) + image->SetProperty("files", dcmFilesProp); +} + +void QmitkMultiLabelSegmentationView::AddDICOMSegmentProperties(mitk::Label::Pointer label) +{ + mitk::AnatomicalStructureColorPresets::Category category; + mitk::AnatomicalStructureColorPresets::Type type; + mitk::AnatomicalStructureColorPresets *anatomicalStructureColorPresets = mitk::AnatomicalStructureColorPresets::New(); + anatomicalStructureColorPresets->LoadPreset(); + + for (const auto &preset : anatomicalStructureColorPresets->GetCategoryPresets()) + { + auto presetOrganName = preset.first; + if (label->GetName().compare(presetOrganName) == 0) + { + category = preset.second; + break; + } + } + + for (const auto &preset : anatomicalStructureColorPresets->GetTypePresets()) + { + auto presetOrganName = preset.first; + if (label->GetName().compare(presetOrganName) == 0) + { + type = preset.second; + break; + } + } + + // Add Segment Sequence tags (0062, 0002) + mitk::DICOMTagPath segmentSequencePath; + segmentSequencePath.AddElement(0x0062, 0x0002); + + // Segment Number:Identification number of the segment.The value of Segment Number(0062, 0004) shall be unique within + // the Segmentation instance in which it is created + mitk::DICOMTagPath segmentNumberPath; + segmentNumberPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0004); + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentNumberPath).c_str(), + mitk::StringProperty::New(std::to_string(label->GetValue()))); + + // Segment Label: User-defined label identifying this segment. + mitk::DICOMTagPath segmentLabelPath; + segmentLabelPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0005); + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentLabelPath).c_str(), + mitk::StringProperty::New(label->GetName())); + + // Segment Algorithm Type: Type of algorithm used to generate the segment. AUTOMATIC SEMIAUTOMATIC MANUAL + mitk::DICOMTagPath segmentAlgorithmTypePath; + segmentAlgorithmTypePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0008); + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentAlgorithmTypePath).c_str(), + mitk::StringProperty::New("SEMIAUTOMATIC")); + //------------------------------------------------------------ + // Add Segmented Property Category Code Sequence tags (0062, 0003): Sequence defining the general category of this + // segment. + mitk::DICOMTagPath segmentSegmentedPropertyCategorySequencePath; + segmentSegmentedPropertyCategorySequencePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003); + // (0008,0100) Code Value + mitk::DICOMTagPath segmentCategoryCodeValuePath; + segmentCategoryCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0100); + if (!category.codeValue.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeValuePath).c_str(), + mitk::StringProperty::New(category.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentCategoryCodeSchemePath; + segmentCategoryCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0102); + if (!category.codeScheme.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeSchemePath).c_str(), + mitk::StringProperty::New(category.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentCategoryCodeMeaningPath; + segmentCategoryCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0104); + if (!category.codeName.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeMeaningPath).c_str(), + mitk::StringProperty::New(category.codeName)); + //------------------------------------------------------------ + // Add Segmented Property Type Code Sequence (0062, 000F): Sequence defining the specific property type of this + // segment. + mitk::DICOMTagPath segmentSegmentedPropertyTypeSequencePath; + segmentSegmentedPropertyTypeSequencePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F); + + // (0008,0100) Code Value + mitk::DICOMTagPath segmentTypeCodeValuePath; + segmentTypeCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0100); + if (!type.codeValue.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeValuePath).c_str(), + mitk::StringProperty::New(type.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentTypeCodeSchemePath; + segmentTypeCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0102); + if (!type.codeScheme.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeSchemePath).c_str(), + mitk::StringProperty::New(type.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentTypeCodeMeaningPath; + segmentTypeCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0104); + if (!type.codeName.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeMeaningPath).c_str(), + mitk::StringProperty::New(type.codeName)); + //------------------------------------------------------------ + // Add Segmented Property Type Modifier Code Sequence (0062,0011): Sequence defining the modifier of the property type + // of this segment. + mitk::DICOMTagPath segmentSegmentedPropertyModifierSequencePath; + segmentSegmentedPropertyModifierSequencePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011); + // (0008,0100) Code Value + mitk::DICOMTagPath segmentModifierCodeValuePath; + segmentModifierCodeValuePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0100); + if (!type.modifier.codeValue.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeValuePath).c_str(), + mitk::StringProperty::New(type.modifier.codeValue)); + + // (0008,0102) Coding Scheme Designator + mitk::DICOMTagPath segmentModifierCodeSchemePath; + segmentModifierCodeSchemePath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0102); + if (!type.modifier.codeScheme.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeSchemePath).c_str(), + mitk::StringProperty::New(type.modifier.codeScheme)); + + // (0008,0104) Code Meaning + mitk::DICOMTagPath segmentModifierCodeMeaningPath; + segmentModifierCodeMeaningPath.AddElement(0x0062, 0x0002) + .AddElement(0x0062, 0x000F) + .AddElement(0x0062, 0x0011) + .AddElement(0x008, 0x0104); + if (!type.modifier.codeName.empty()) + label->SetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeMeaningPath).c_str(), + mitk::StringProperty::New(type.modifier.codeName)); + + //============================TODO: Not here:-) + mitk::IDICOMTagsOfInterest *toiService = nullptr; + + std::vector> toiRegisters = + us::GetModuleContext()->GetServiceReferences(); + if (!toiRegisters.empty()) + { + if (toiRegisters.size() > 1) + MITK_WARN << "Multiple DICOM tags of interest services found. Using just one."; + toiService = us::GetModuleContext()->GetService(toiRegisters.front()); + } + + if (toiService != nullptr) + { + toiService->AddTagOfInterest(segmentSequencePath); + + toiService->AddTagOfInterest(segmentNumberPath); + toiService->AddTagOfInterest(segmentLabelPath); + toiService->AddTagOfInterest(segmentAlgorithmTypePath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyCategorySequencePath); + toiService->AddTagOfInterest(segmentCategoryCodeValuePath); + toiService->AddTagOfInterest(segmentCategoryCodeSchemePath); + toiService->AddTagOfInterest(segmentCategoryCodeMeaningPath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyTypeSequencePath); + toiService->AddTagOfInterest(segmentTypeCodeValuePath); + toiService->AddTagOfInterest(segmentTypeCodeSchemePath); + toiService->AddTagOfInterest(segmentTypeCodeMeaningPath); + + toiService->AddTagOfInterest(segmentSegmentedPropertyModifierSequencePath); + toiService->AddTagOfInterest(segmentModifierCodeValuePath); + toiService->AddTagOfInterest(segmentModifierCodeSchemePath); + toiService->AddTagOfInterest(segmentModifierCodeMeaningPath); + } +} + +void QmitkMultiLabelSegmentationView::SetReferenceDICOMProperty(mitk::Image *original, + mitk::Image *segmentation, + const mitk::DICOMTag &tag, + const std::string &defaultString) +{ + std::string tagString = mitk::GeneratePropertyNameForDICOMTag(tag.GetGroup(), tag.GetElement()); + + // Get DICOM property from referenced image + mitk::BaseProperty::Pointer originalProperty = original->GetProperty(tagString.c_str()); + + // if property exists, copy the informtaion to the segmentation + if (originalProperty.IsNotNull()) + segmentation->SetProperty(tagString.c_str(), originalProperty); + else // use the default value, if there is one + { + if (!defaultString.empty()) + segmentation->SetProperty(tagString.c_str(), mitk::StringProperty::New(defaultString).GetPointer()); + } +} 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 a5d124d8af..acbebcb3ef 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.h @@ -1,173 +1,183 @@ /*=================================================================== 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 #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; + typedef std::map NodeTagMapType; // GUI setup - void CreateQtPartControl(QWidget* parent); + 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); + virtual int ComputePreferredSize(bool width, + int /*availableParallel*/, + int /*availablePerpendicular*/, + int preferredResult); protected slots: /// \brief reaction to the selection of a new patient (reference) image in the DataStorage combobox - void OnReferenceSelectionChanged(const mitk::DataNode* node); + void OnReferenceSelectionChanged(const mitk::DataNode *node); /// \brief reaction to the selection of a new Segmentation (working) image in the DataStorage combobox void OnSegmentationSelectionChanged(const mitk::DataNode *node); /// \brief reaction to ... void OnInterpolationSelectionChanged(int); /// \brief reaction to the selection of any 2D segmentation tool void OnManualTool2DSelected(int id); /// \brief reaction to button "New Label" void OnNewLabel(); /// \brief reaction to button "Show Label Table" void OnShowLabelTable(bool value); /// \brief reaction to button "New Segmentation Session" void OnNewSegmentationSession(); /// \brief reaction to signal "goToLabel" from labelset widget - void OnGoToLabel(const mitk::Point3D& pos); + 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); protected: - // invoked when the preferences were changed - void OnPreferencesChanged(const berry::IBerryPreferences* prefs) override; + void OnPreferencesChanged(const berry::IBerryPreferences *prefs) 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 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; /// \brief Reimplemented from QmitkAbstractView - virtual void NodeAdded(const mitk::DataNode* node); + virtual void NodeAdded(const mitk::DataNode *node); /// \brief Reimplemented from QmitkAbstractView - virtual void NodeRemoved(const mitk::DataNode* node); + virtual void NodeRemoved(const mitk::DataNode *node); QString GetLastFileOpenPath(); - void SetLastFileOpenPath(const QString& path); + void SetLastFileOpenPath(const QString &path); + + void AddDICOMSegmentationProperties(mitk::LabelSetImage::Pointer image, mitk::Image::Pointer reference); + + void AddDICOMSegmentProperties(mitk::Label::Pointer label); + + void SetReferenceDICOMProperty(mitk::Image *original, + mitk::Image *segmentation, + const mitk::DICOMTag &tag, + const std::string &defaultString = ""); /// \brief the Qt parent of our GUI (NOT of this object) - QWidget* m_Parent; + QWidget *m_Parent; /// \brief Qt GUI file Ui::QmitkMultiLabelSegmentationControls m_Controls; - mitk::IRenderWindowPart* m_IRenderWindowPart; + mitk::IRenderWindowPart *m_IRenderWindowPart; - mitk::ToolManager* m_ToolManager; + 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_MouseCursorSet; mitk::SegmentationInteractor::Pointer m_Interactor; /** - * Reference to the service registration of the observer, - * it is needed to unregister the observer on unload. - */ + * Reference to the service registration of the observer, + * it is needed to unregister the observer on unload. + */ us::ServiceRegistration m_ServiceRegistration; }; #endif // QmitkMultiLabelSegmentationView_h