diff --git a/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp index 85d9dffcf0..13eba8fb5b 100644 --- a/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp +++ b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp @@ -1,487 +1,488 @@ /*=================================================================== 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 __mitkDICOMSegmentationIO__cpp #define __mitkDICOMSegmentationIO__cpp #include "mitkDICOMSegmentationIO.h" #include #include #include #include #include // itk #include // dcmqi #include #include namespace mitk { DICOMSegmentationIO::DICOMSegmentationIO() : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::DICOM_MIMETYPE(), "DICOM Segmentation") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel DICOMSegmentationIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const LabelSetImage *input = static_cast(this->GetInput()); if (input) return Supported; else return Unsupported; } void DICOMSegmentationIO::Write() { ValidateOutputLocation(); mitk::LocaleSwitch localeSwitch("C"); LocalFile localFile(this); const std::string path = localFile.GetFileName(); auto input = dynamic_cast(this->GetInput()); if (input == nullptr) mitkThrow() << "Cannot write non-image data"; // Get DICOM information from referenced image vector dcmDatasets; DcmFileFormat *readFileFormat = new DcmFileFormat(); try { // TODO: Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the // property list mitk::StringLookupTableProperty::Pointer filesProp = dynamic_cast(input->GetProperty("files").GetPointer()); if (filesProp.IsNull()) { mitkThrow() << "No property with dicom file path."; return; } StringLookupTable filesLut = filesProp->GetValue(); const StringLookupTable::LookupTableType &lookUpTableMap = filesLut.GetLookupTable(); for (auto it : lookUpTableMap) { const char *fileName = (it.second).c_str(); if (readFileFormat->loadFile(fileName, EXS_Unknown).good()) dcmDatasets.push_back(readFileFormat->getAndRemoveDataset()); } } catch (const std::exception &e) { MITK_ERROR << "An error occurred while getting the dicom informations: " << e.what() << endl; return; } // Iterate over all layers. For each a dcm file will be generated for (unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer) { vector segmentations; try { // Cast mitk layer image to itk ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); // BUG: It must be the layer image, but there are some errors with it (dcmqi: generate the dcmSeg "No frame data // available") --> input->GetLayerImage(layer) imageToItkFilter->SetInput(input); imageToItkFilter->Update(); // Cast from original itk type to dcmqi input itk image type typedef itk::CastImageFilter castItkImageFilterType; castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New(); castFilter->SetInput(imageToItkFilter->GetOutput()); castFilter->Update(); itkInternalImageType::Pointer itkLabelImage = castFilter->GetOutput(); itkLabelImage->DisconnectPipeline(); // Iterate over all labels. For each a segmentation image will be created const LabelSet *labelSet = input->GetLabelSet(layer); for (auto itLabel = labelSet->IteratorConstBegin(); itLabel != labelSet->IteratorConstEnd(); ++itLabel) { // Thresold over the image with the given label value itk::ThresholdImageFilter::Pointer thresholdFilter = itk::ThresholdImageFilter::New(); thresholdFilter->SetInput(itkLabelImage); thresholdFilter->ThresholdOutside(itLabel->first, itLabel->first); thresholdFilter->SetOutsideValue(0); thresholdFilter->Update(); itkInternalImageType::Pointer segmentImage = thresholdFilter->GetOutput(); segmentImage->DisconnectPipeline(); segmentations.push_back(segmentImage); } } catch (const itk::ExceptionObject &e) { MITK_ERROR << e.GetDescription() << endl; return; } // Create segmentation meta information const std::string &tmpMetaInfoFile = this->CreateMetaDataJsonFile(layer); MITK_INFO << "Writing image: " << path << std::endl; try { // Convert itk segmentation images to dicom image dcmqi::ImageSEGConverter *converter = new dcmqi::ImageSEGConverter(); DcmDataset *result = converter->itkimage2dcmSegmentation(dcmDatasets, segmentations, tmpMetaInfoFile); // Write dicom file DcmFileFormat dcmFileFormat(result); std::string filePath = path.substr(0, path.find_last_of(".")); // If there is more than one layer, we have to write more than 1 dicom file if (input->GetNumberOfLayers() != 1) filePath = filePath + std::to_string(layer) + ".dcm"; else filePath = filePath + ".dcm"; dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit); // Clean up if (converter != nullptr) delete converter; if (result != nullptr) delete result; } catch (const std::exception &e) { MITK_ERROR << "An error occurred during writing the DICOM Seg: " << e.what() << endl; return; } } // Write a dcm file for the next layer // End of image writing; clean up if (readFileFormat) delete readFileFormat; for (auto obj : dcmDatasets) delete obj; dcmDatasets.clear(); } IFileIO::ConfidenceLevel DICOMSegmentationIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; const std::string fileName = this->GetLocalFileName(); DcmFileFormat dcmFileFormat; OFCondition status = dcmFileFormat.loadFile(fileName.c_str()); if (status.bad()) return Unsupported; OFString modality; if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good()) { if (modality.compare("SEG") == 0) return Supported; else return Unsupported; } return Unsupported; } std::vector DICOMSegmentationIO::Read() { mitk::LocaleSwitch localeSwitch("C"); LabelSetImage::Pointer labelSetImage; std::vector result; const std::string path = this->GetLocalFileName(); MITK_INFO << "loading " << path << std::endl; if (path.empty()) mitkThrow() << "Empty filename in mitk::ItkImageIO "; try { // Get the dcm data set from file path DcmFileFormat dcmFileFormat; OFCondition status = dcmFileFormat.loadFile(path.c_str()); if (status.bad()) mitkThrow() << "Can't read the input file!"; DcmDataset *dataSet = dcmFileFormat.getDataset(); if (dataSet == nullptr) mitkThrow() << "Can't read data from input file!"; // Read the DICOM SEG images (segItkImages) and DICOM tags (metaInfo) dcmqi::ImageSEGConverter *converter = new dcmqi::ImageSEGConverter(); pair, string> dcmqiOutput = converter->dcmSegmentation2itkimage(dataSet); map segItkImages = dcmqiOutput.first; // For each itk image add a layer to the LabelSetImage output for (auto &element : segItkImages) { // Get the labeled image and cast it to mitkImage typedef itk::CastImageFilter castItkImageFilterType; castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New(); castFilter->SetInput(element.second); castFilter->Update(); Image::Pointer layerImage; CastToMitkImage(castFilter->GetOutput(), layerImage); // Get pixel value of the label itkInternalImageType::ValueType segValue = 1; typedef itk::ImageRegionIterator IteratorType; // Iterate over the image to find the pixel value of the label IteratorType iter(element.second, element.second->GetLargestPossibleRegion()); iter.GoToBegin(); while (!iter.IsAtEnd()) { itkInputImageType::PixelType value = iter.Get(); if (value != 0) { segValue = value; break; } ++iter; } dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str()); metaInfo.read(); MITK_INFO << "Input " << metaInfo.getJSONOutputAsString(); // TODO: Read all DICOM Tags // Get the label information from segment attributes vector>::const_iterator segmentIter = metaInfo.segmentsAttributesMappingList.begin(); map segmentMap = (*segmentIter); map::const_iterator segmentMapIter = (*segmentIter).begin(); dcmqi::SegmentAttributes *segmentAttr = (*segmentMapIter).second; OFString labelName; if (segmentAttr->getSegmentedPropertyTypeCodeSequence() != nullptr) segmentAttr->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName); else { labelName = std::to_string(segmentAttr->getLabelID()).c_str(); if (labelName.empty()) labelName = "Unnamed"; } float tmp[3] = {0.0, 0.0, 0.0}; if (segmentAttr->getRecommendedDisplayRGBValue() != nullptr) { tmp[0] = segmentAttr->getRecommendedDisplayRGBValue()[0] / 255.0; tmp[1] = segmentAttr->getRecommendedDisplayRGBValue()[1] / 255.0; tmp[2] = segmentAttr->getRecommendedDisplayRGBValue()[2] / 255.0; } // If labelSetImage do not exists (first image) if (labelSetImage.IsNull()) { // Initialize the labelSetImage with the read image labelSetImage = LabelSetImage::New(); labelSetImage->InitializeByLabeledImage(layerImage); // Already a label was generated, so set the information to this Label *activeLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer()); activeLabel->SetName(labelName.c_str()); activeLabel->SetColor(Color(tmp)); activeLabel->SetValue(segValue); } else { // Add a new layer to the labelSetImage. Background label is set automatically labelSetImage->AddLayer(layerImage); // Add new label Label *newLabel = new Label; newLabel->SetName(labelName.c_str()); newLabel->SetColor(Color(tmp)); newLabel->SetValue(segValue); labelSetImage->GetLabelSet(labelSetImage->GetActiveLayer())->AddLabel(newLabel); } ++segmentIter; } // Clean up if (converter != nullptr) delete converter; } catch (const std::exception &e) { MITK_ERROR << "An error occurred while reading the DICOM Seg file: " << e.what(); return result; } // Set active layer to th first layer of the labelset image if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0) labelSetImage->SetActiveLayer(0); result.push_back(labelSetImage.GetPointer()); return result; } const std::string mitk::DICOMSegmentationIO::CreateMetaDataJsonFile(int layer) { const mitk::LabelSetImage *image = dynamic_cast(this->GetInput()); const std::string output; dcmqi::JSONSegmentationMetaInformationHandler handler; // Default values handler.setContentCreatorName("MITK"); handler.setClinicalTrialSeriesID("Session 1"); handler.setClinicalTrialTimePointID("0"); + handler.setClinicalTrialCoordinatingCenterName("Unknown"); std::string seriesDescription = ""; image->GetPropertyList()->GetStringProperty("name", seriesDescription); if (seriesDescription.empty()) - seriesDescription = "Segmentation"; + seriesDescription = "MITK Segmentation"; handler.setSeriesDescription(seriesDescription); handler.setSeriesNumber("34" + std::to_string(layer)); // TODO:Create own series number handler.setInstanceNumber("1"); handler.setBodyPartExamined(""); const LabelSet *labelSet = image->GetLabelSet(layer); for (auto it = labelSet->IteratorConstBegin(); it != labelSet->IteratorConstEnd(); ++it) { const Label *label = it->second; if (label != nullptr) { mitk::DICOMTagPath segmentNumberPath; segmentNumberPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0004); StringProperty *segmentNumberProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentNumberPath).c_str())); mitk::DICOMTagPath segmentLabelPath; segmentLabelPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0005); StringProperty *segmentLabelProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentLabelPath).c_str())); mitk::DICOMTagPath segmentAlgorithmTypePath; segmentAlgorithmTypePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0008); StringProperty *algorithmTypeProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentAlgorithmTypePath).c_str())); mitk::DICOMTagPath segmentCategoryCodeValuePath; segmentCategoryCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0100); StringProperty *segmentCategoryCodeValueProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeValuePath).c_str())); mitk::DICOMTagPath segmentCategoryCodeSchemePath; segmentCategoryCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0102); StringProperty *segmentCategoryCodeSchemeProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeSchemePath).c_str())); mitk::DICOMTagPath segmentCategoryCodeMeaningPath; segmentCategoryCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x0003).AddElement(0x008, 0x0104); StringProperty *segmentCategoryCodeMeaningProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentCategoryCodeMeaningPath).c_str())); mitk::DICOMTagPath segmentTypeCodeValuePath; segmentTypeCodeValuePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0100); StringProperty *segmentTypeCodeValueProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeValuePath).c_str())); mitk::DICOMTagPath segmentTypeCodeSchemePath; segmentTypeCodeSchemePath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0102); StringProperty *segmentTypeCodeSchemeProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeSchemePath).c_str())); mitk::DICOMTagPath segmentTypeCodeMeaningPath; segmentTypeCodeMeaningPath.AddElement(0x0062, 0x0002).AddElement(0x0062, 0x000F).AddElement(0x008, 0x0104); StringProperty *segmentTypeCodeMeaningProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentTypeCodeMeaningPath).c_str())); mitk::DICOMTagPath segmentModifierCodeValuePath; segmentModifierCodeValuePath.AddElement(0x0062, 0x0002) .AddElement(0x0062, 0x000F) .AddElement(0x0062, 0x0011) .AddElement(0x008, 0x0100); StringProperty *segmentModifierCodeValueProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeValuePath).c_str())); mitk::DICOMTagPath segmentModifierCodeSchemePath; segmentModifierCodeSchemePath.AddElement(0x0062, 0x0002) .AddElement(0x0062, 0x000F) .AddElement(0x0062, 0x0011) .AddElement(0x008, 0x0102); StringProperty *segmentModifierCodeSchemeProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeSchemePath).c_str())); mitk::DICOMTagPath segmentModifierCodeMeaningPath; segmentModifierCodeMeaningPath.AddElement(0x0062, 0x0002) .AddElement(0x0062, 0x000F) .AddElement(0x0062, 0x0011) .AddElement(0x008, 0x0104); StringProperty *segmentModifierCodeMeaningProp = dynamic_cast( label->GetProperty(mitk::DICOMTagPathToPropertyName(segmentModifierCodeMeaningPath).c_str())); int labelId = std::stoi(segmentNumberProp->GetValue()); dcmqi::SegmentAttributes *segAttr = handler.createAndGetNewSegment(labelId); if (segAttr != nullptr) { segAttr->setSegmentDescription(segmentLabelProp->GetValueAsString()); segAttr->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString()); segAttr->setSegmentAlgorithmName("MITK Segmentation"); if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr && segmentCategoryCodeMeaningProp != nullptr) segAttr->setSegmentedPropertyCategoryCodeSequence(segmentCategoryCodeValueProp->GetValueAsString(), segmentCategoryCodeSchemeProp->GetValueAsString(), segmentCategoryCodeMeaningProp->GetValueAsString()); if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr && segmentTypeCodeMeaningProp != nullptr) { segAttr->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->GetValueAsString(), segmentTypeCodeSchemeProp->GetValueAsString(), segmentTypeCodeMeaningProp->GetValueAsString()); handler.setBodyPartExamined(segmentTypeCodeMeaningProp->GetValueAsString()); } if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr && segmentModifierCodeMeaningProp != nullptr) segAttr->setSegmentedPropertyTypeModifierCodeSequence(segmentModifierCodeValueProp->GetValueAsString(), segmentModifierCodeSchemeProp->GetValueAsString(), segmentModifierCodeMeaningProp->GetValueAsString()); Color color = label->GetColor(); segAttr->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255); } } } return handler.getJSONOutputAsString(); } DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); } } // namespace #endif //__mitkDICOMSegmentationIO__cpp diff --git a/Modules/Segmentation/Interactions/mitkTool.cpp b/Modules/Segmentation/Interactions/mitkTool.cpp index 6455cf4e1a..18e245fcf8 100644 --- a/Modules/Segmentation/Interactions/mitkTool.cpp +++ b/Modules/Segmentation/Interactions/mitkTool.cpp @@ -1,571 +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 "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")); + StringProperty::New("MITK 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/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp index 036858380d..7baa56ab7e 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/QmitkMultiLabelSegmentationView.cpp @@ -1,1281 +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 // mitk #include "mitkApplicationCursor.h" #include "mitkLabelSetImage.h" #include "mitkStatusBar.h" #include "mitkToolManagerProvider.h" //#include "mitkSegmentationObjectFactory.h" #include "mitkDICOMTag.h" #include "mitkDICOMTagPath.h" #include "mitkIDICOMTagsOfInterest.h" #include "mitkInteractionEventObserver.h" #include "mitkPlanePositionManager.h" #include "mitkPluginActivator.h" #include "mitkPropertyNameHelper.h" #include "mitkSegTool2D.h" // Qmitk #include "QmitkNewSegmentationDialog.h" #include "QmitkRenderWindow.h" #include "QmitkSegmentationOrganNamesHandling.cpp" // us #include #include #include #include #include // Qt #include #include #include #include #include "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) { m_SegmentationPredicate = mitk::NodePredicateAnd::New(); m_SegmentationPredicate->AddPredicate(mitk::TNodePredicateDataType::New()); m_SegmentationPredicate->AddPredicate(mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object"))); mitk::TNodePredicateDataType::Pointer isImage = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinary = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateAnd::Pointer isMask = mitk::NodePredicateAnd::New(isBinary, isImage); mitk::NodePredicateDataType::Pointer isDwi = mitk::NodePredicateDataType::New("DiffusionImage"); mitk::NodePredicateDataType::Pointer isDti = mitk::NodePredicateDataType::New("TensorImage"); mitk::NodePredicateDataType::Pointer 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); /* 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_ServiceRegistration.Unregister(); // Loose LabelSetConnections OnLooseLabelSetConnection(); } 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_cbWorkingNodeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode *)), this, SLOT(OnSegmentationSelectionChanged(const mitk::DataNode *))); // *------------------------ // * ToolManager // *------------------------ m_ToolManager = mitk::ToolManagerProvider::GetInstance()->GetToolManager(); assert(m_ToolManager); m_ToolManager->SetDataStorage(*(this->GetDataStorage())); m_ToolManager->InitializeTools(); // use the same ToolManager instance for our 3D Tools m_Controls.m_ManualToolSelectionBox3D->SetToolManager(*m_ToolManager); // *------------------------ // * LabelSetWidget // *------------------------ m_Controls.m_LabelSetWidget->SetDataStorage(this->GetDataStorage()); m_Controls.m_LabelSetWidget->SetOrganColors(mitk::OrganNamesHandling::GetDefaultOrganColorString()); m_Controls.m_LabelSetWidget->hide(); // *------------------------ // * Interpolation // *------------------------ m_Controls.m_SurfaceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); m_Controls.m_SliceBasedInterpolatorWidget->SetDataStorage(*(this->GetDataStorage())); connect(m_Controls.m_cbInterpolation, SIGNAL(activated(int)), this, SLOT(OnInterpolationSelectionChanged(int))); m_Controls.m_cbInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->hide(); // *------------------------ // * ToolSelection 2D // *------------------------ m_Controls.m_ManualToolSelectionBox2D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox2D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer2D); m_Controls.m_ManualToolSelectionBox2D->SetDisplayedToolGroups( "Add Subtract Fill Erase Paint Wipe 'Region Growing' FastMarching2D Correction 'Live Wire'"); // todo: "Correction // 'Live Wire'" m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); connect(m_Controls.m_ManualToolSelectionBox2D, SIGNAL(ToolSelected(int)), this, SLOT(OnManualTool2DSelected(int))); // *------------------------ // * ToolSelection 3D // *------------------------ m_Controls.m_ManualToolSelectionBox3D->SetGenerateAccelerators(true); m_Controls.m_ManualToolSelectionBox3D->SetToolGUIArea(m_Controls.m_ManualToolGUIContainer3D); m_Controls.m_ManualToolSelectionBox3D->SetDisplayedToolGroups( "Threshold 'Two Thresholds' 'Auto Threshold' 'Multiple Otsu'"); // todo add : FastMarching3D RegionGrowing Watershed m_Controls.m_ManualToolSelectionBox3D->SetLayoutColumns(2); m_Controls.m_ManualToolSelectionBox3D->SetEnabledMode( QmitkToolSelectionBox::EnabledWithReferenceAndWorkingDataVisible); // *------------------------* // * Connect PushButtons (pb) // *------------------------* connect(m_Controls.m_pbNewLabel, SIGNAL(clicked()), this, SLOT(OnNewLabel())); connect(m_Controls.m_pbNewSegmentationSession, SIGNAL(clicked()), this, SLOT(OnNewSegmentationSession())); connect(m_Controls.m_pbShowLabelTable, SIGNAL(toggled(bool)), this, SLOT(OnShowLabelTable(bool))); // *------------------------* // * Connect LabelSetWidget // *------------------------* connect(m_Controls.m_LabelSetWidget, SIGNAL(goToLabel(const mitk::Point3D &)), this, SLOT(OnGoToLabel(const mitk::Point3D &))); connect(m_Controls.m_LabelSetWidget, SIGNAL(resetView()), this, SLOT(OnResetView())); // *------------------------* // * DATA SLECTION WIDGET // *------------------------* m_IRenderWindowPart = this->GetRenderWindowPart(); if (m_IRenderWindowPart) { QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); // m_Controls.m_LabelSetWidget->SetRenderWindowPart(this->m_IRenderWindowPart); } // this->InitializeListeners(); connect(m_Controls.m_btAddLayer, SIGNAL(clicked()), this, SLOT(OnAddLayer())); connect(m_Controls.m_btDeleteLayer, SIGNAL(clicked()), this, SLOT(OnDeleteLayer())); connect(m_Controls.m_btPreviousLayer, SIGNAL(clicked()), this, SLOT(OnPreviousLayer())); connect(m_Controls.m_btNextLayer, SIGNAL(clicked()), this, SLOT(OnNextLayer())); connect(m_Controls.m_btLockExterior, SIGNAL(toggled(bool)), this, SLOT(OnLockExteriorToggled(bool))); connect(m_Controls.m_cbActiveLayer, SIGNAL(currentIndexChanged(int)), this, SLOT(OnChangeLayer(int))); m_Controls.m_btAddLayer->setEnabled(false); m_Controls.m_btDeleteLayer->setEnabled(false); m_Controls.m_btNextLayer->setEnabled(false); m_Controls.m_btPreviousLayer->setEnabled(false); m_Controls.m_cbActiveLayer->setEnabled(false); m_Controls.m_pbNewLabel->setEnabled(false); m_Controls.m_btLockExterior->setEnabled(false); m_Controls.m_pbShowLabelTable->setEnabled(false); // Make sure the GUI notices if appropriate data is already present on creation this->OnReferenceSelectionChanged(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); this->OnSegmentationSelectionChanged(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Activated() { m_ToolManager->SetReferenceData(m_Controls.m_cbReferenceNodeSelector->GetSelectedNode()); m_ToolManager->SetWorkingData(m_Controls.m_cbWorkingNodeSelector->GetSelectedNode()); } void QmitkMultiLabelSegmentationView::Deactivated() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Visible() { // Not yet implemented } void QmitkMultiLabelSegmentationView::Hidden() { // Not yet implemented } void QmitkMultiLabelSegmentationView::InitializeListeners() { if (m_Interactor.IsNull()) { us::Module *module = us::GetModuleContext()->GetModule(); std::vector resources = module->FindResources("/", "*", true); for (std::vector::iterator iter = resources.begin(); iter != resources.end(); ++iter) { MITK_INFO << iter->GetResourcePath(); } m_Interactor = mitk::SegmentationInteractor::New(); if (!m_Interactor->LoadStateMachine("SegmentationInteraction.xml", module)) { MITK_WARN << "Error loading state machine"; } if (!m_Interactor->SetEventConfig("ConfigSegmentation.xml", module)) { MITK_WARN << "Error loading state machine configuration"; } // Register as listener via micro services us::ServiceProperties props; props["name"] = std::string("SegmentationInteraction"); m_ServiceRegistration = us::GetModuleContext()->RegisterService(m_Interactor.GetPointer(), props); } } 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()); return isSameGeometry; } else { return false; } } void QmitkMultiLabelSegmentationView::RenderWindowPartActivated(mitk::IRenderWindowPart *renderWindowPart) { if (m_IRenderWindowPart != renderWindowPart) { m_IRenderWindowPart = renderWindowPart; m_Parent->setEnabled(true); QList controllers; controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("axial")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("sagittal")->GetSliceNavigationController()); controllers.push_back(m_IRenderWindowPart->GetQmitkRenderWindow("coronal")->GetSliceNavigationController()); m_Controls.m_SliceBasedInterpolatorWidget->SetSliceNavigationControllers(controllers); } } void QmitkMultiLabelSegmentationView::RenderWindowPartDeactivated(mitk::IRenderWindowPart * /*renderWindowPart*/) { m_ToolManager->ActivateTool(-1); m_IRenderWindowPart = 0; m_Parent->setEnabled(false); } int QmitkMultiLabelSegmentationView::GetSizeFlags(bool width) { if (!width) { return berry::Constants::MIN | berry::Constants::MAX | berry::Constants::FILL; } else { return 0; } } int QmitkMultiLabelSegmentationView::ComputePreferredSize(bool width, int /*availableParallel*/, int /*availablePerpendicular*/, int preferredResult) { if (width == false) { return 100; } else { return preferredResult; } } void QmitkMultiLabelSegmentationView::UpdateControls() { mitk::DataNode *referenceNode = m_ToolManager->GetReferenceData(0); bool hasReferenceNode = referenceNode != NULL; 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); if (hasValidWorkingNode) { // TODO adapt tool manager so that this check is done there, e.g. convenience function mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); hasValidWorkingNode = workingImage != nullptr; if (hasValidWorkingNode) { m_Controls.m_pbNewLabel->setEnabled(true); m_Controls.m_btLockExterior->setEnabled(true); m_Controls.m_pbShowLabelTable->setEnabled(true); m_Controls.m_gbInterpolation->setEnabled(true); m_Controls.m_SliceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_SurfaceBasedInterpolatorWidget->setEnabled(true); m_Controls.m_LabelSetWidget->setEnabled(true); m_Controls.m_btAddLayer->setEnabled(true); int activeLayer = workingImage->GetActiveLayer(); int numberOfLayers = workingImage->GetNumberOfLayers(); m_Controls.m_cbActiveLayer->blockSignals(true); m_Controls.m_cbActiveLayer->clear(); for (unsigned int lidx = 0; lidx < workingImage->GetNumberOfLayers(); ++lidx) m_Controls.m_cbActiveLayer->addItem(QString::number(lidx)); m_Controls.m_cbActiveLayer->setCurrentIndex(activeLayer); m_Controls.m_cbActiveLayer->blockSignals(false); m_Controls.m_cbActiveLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btDeleteLayer->setEnabled(numberOfLayers > 1); m_Controls.m_btPreviousLayer->setEnabled(activeLayer > 0); m_Controls.m_btNextLayer->setEnabled(activeLayer != numberOfLayers - 1); m_Controls.m_btLockExterior->setChecked(workingImage->GetLabel(0, activeLayer)->GetLocked()); m_Controls.m_pbShowLabelTable->setChecked(workingImage->GetNumberOfLabels() > 1 /*1st is exterior*/); // MLI TODO // m_Controls.m_ManualToolSelectionBox2D->SetEnabledMode(QmitkToolSelectionBox::EnabledWithWorkingDataVisible); } } if (hasValidWorkingNode && hasReferenceNode) { int layer = -1; referenceNode->GetIntProperty("layer", layer); workingNode->SetIntProperty("layer", layer + 1); } this->RequestRenderWindowUpdate(mitk::RenderingManager::REQUEST_UPDATE_ALL); } void QmitkMultiLabelSegmentationView::OnNewSegmentationSession() { mitk::DataNode *referenceNode = m_Controls.m_cbReferenceNodeSelector->GetSelectedNode(); if (!referenceNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } m_ToolManager->ActivateTool(-1); mitk::Image *referenceImage = dynamic_cast(referenceNode->GetData()); assert(referenceImage); QString newName = QString::fromStdString(referenceNode->GetName()); newName.append("-labels"); bool ok = false; newName = QInputDialog::getText(m_Parent, "New Segmentation Session", "New name:", QLineEdit::Normal, newName, &ok); if (!ok) return; this->WaitCursorOn(); mitk::LabelSetImage::Pointer workingImage = mitk::LabelSetImage::New(); try { workingImage->Initialize(referenceImage); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Parent, "New Segmentation Session", "Could not create a new segmentation session.\n"); return; } this->WaitCursorOff(); mitk::DataNode::Pointer workingNode = mitk::DataNode::New(); workingNode->SetData(workingImage); workingNode->SetName(newName.toStdString()); workingImage->GetExteriorLabel()->SetProperty("name.parent", mitk::StringProperty::New(referenceNode->GetName().c_str())); workingImage->GetExteriorLabel()->SetProperty("name.image", mitk::StringProperty::New(newName.toStdString().c_str())); 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); if (!workingNode) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); if (!workingImage) { QMessageBox::information( m_Parent, "New Segmentation Session", "Please load and select a patient image before starting some action."); return; } QmitkNewSegmentationDialog *dialog = new QmitkNewSegmentationDialog(m_Parent); dialog->SetSuggestionList(mitk::OrganNamesHandling::GetDefaultOrganColorString()); dialog->setWindowTitle("New Label"); int dialogReturnValue = dialog->exec(); if (dialogReturnValue == QDialog::Rejected) return; QString segName = dialog->GetSegmentationName(); if (segName.isEmpty()) segName = "Unnamed"; workingImage->GetActiveLabelSet()->AddLabel(segName.toStdString(), dialog->GetColor()); 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); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() + 1); } void QmitkMultiLabelSegmentationView::OnPreviousLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); OnChangeLayer(workingImage->GetActiveLayer() - 1); } void QmitkMultiLabelSegmentationView::OnChangeLayer(int layer) { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); this->WaitCursorOn(); workingImage->SetActiveLayer(layer); this->WaitCursorOff(); UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnDeleteLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); if (workingImage->GetNumberOfLayers() < 2) return; QString question = "Do you really want to delete the current layer?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Delete layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; try { this->WaitCursorOn(); workingImage->RemoveLayer(); this->WaitCursorOff(); } catch (mitk::Exception &e) { this->WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information(m_Controls.m_LabelSetWidget, "Delete Layer", "Could not delete the currently active layer. See error log for details.\n"); return; } UpdateControls(); m_Controls.m_LabelSetWidget->ResetAllTableWidgetItems(); } void QmitkMultiLabelSegmentationView::OnAddLayer() { m_ToolManager->ActivateTool(-1); mitk::DataNode *workingNode = m_ToolManager->GetWorkingData(0); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); QString question = "Do you really want to add a layer to the current segmentation session?"; QMessageBox::StandardButton answerButton = QMessageBox::question( m_Controls.m_LabelSetWidget, "Add layer", question, QMessageBox::Yes | QMessageBox::Cancel, QMessageBox::Yes); if (answerButton != QMessageBox::Yes) return; int newLabelSetId = -1; try { WaitCursorOn(); newLabelSetId = workingImage->AddLayer(); WaitCursorOff(); } catch (mitk::Exception &e) { WaitCursorOff(); MITK_ERROR << "Exception caught: " << e.GetDescription(); QMessageBox::information( m_Controls.m_LabelSetWidget, "Add Layer", "Could not add a new layer. See error log for details.\n"); return; } // 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); assert(workingNode); mitk::LabelSetImage *workingImage = dynamic_cast(workingNode->GetData()); assert(workingImage); workingImage->GetLabel(0)->SetLocked(checked); } void QmitkMultiLabelSegmentationView::NodeAdded(const mitk::DataNode *) { /* bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) return; if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { mitk::LabelSetImage* workingImage = dynamic_cast(node->GetData()); if (workingImage->GetNumberOfLabels() > 2) m_Controls.m_LabelSetWidget->show(); else m_Controls.m_LabelSetWidget->hide(); } */ } void QmitkMultiLabelSegmentationView::NodeRemoved(const mitk::DataNode *node) { bool isHelperObject(false); node->GetBoolProperty("helper object", isHelperObject); if (isHelperObject) return; if (m_ReferenceNode.IsNotNull() && dynamic_cast(node->GetData())) { // remove all possible contour markers of the segmentation mitk::DataStorage::SetOfObjects::ConstPointer allContourMarkers = this->GetDataStorage()->GetDerivations( node, mitk::NodePredicateProperty::New("isContourMarker", mitk::BoolProperty::New(true))); ctkPluginContext *context = mitk::PluginActivator::getContext(); ctkServiceReference ppmRef = context->getServiceReference(); mitk::PlanePositionManagerService *service = context->getService(ppmRef); for (mitk::DataStorage::SetOfObjects::ConstIterator it = allContourMarkers->Begin(); it != allContourMarkers->End(); ++it) { std::string nodeName = node->GetName(); unsigned int t = nodeName.find_last_of(" "); unsigned int id = atof(nodeName.substr(t + 1).c_str()) - 1; service->RemovePlanePosition(id); this->GetDataStorage()->Remove(it->Value()); } context->ungetService(ppmRef); service = NULL; } } void QmitkMultiLabelSegmentationView::OnInterpolationSelectionChanged(int index) { if (index == 1) { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked( false); // OnToggleWidgetActivation(false); m_Controls.m_swInterpolation->setCurrentIndex(0); m_Controls.m_swInterpolation->show(); } else if (index == 2) { m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(1); m_Controls.m_swInterpolation->show(); } else { m_Controls.m_SurfaceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_SliceBasedInterpolatorWidget->m_Controls.m_btStart->setChecked(false); m_Controls.m_swInterpolation->setCurrentIndex(2); m_Controls.m_swInterpolation->hide(); } } void QmitkMultiLabelSegmentationView::OnReferenceSelectionChanged(const mitk::DataNode *node) { m_ToolManager->ActivateTool(-1); m_ReferenceNode = const_cast(node); m_ToolManager->SetReferenceData(m_ReferenceNode); // check match of segmentation and reference image geometries if (node && m_WorkingNode.IsNotNull()) { mitk::Image *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); mitk::Image *refImage = dynamic_cast(node->GetData()); assert(refImage); if (!this->CheckForSameGeometry(refImage, workingImage)) return; } this->UpdateControls(); // 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()); assert(workingImage); workingImage->GetActiveLabelSet()->AddLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent += mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent += mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent += mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection() { MITK_INFO << "Connection Lost"; if (m_WorkingNode.IsNull()) { return; } mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Reset LabelSetWidget Events workingImage->GetActiveLabelSet()->AddLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->RemoveLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::ResetAllTableWidgetItems); workingImage->GetActiveLabelSet()->ModifyLabelEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->AllLabelsModifiedEvent -= mitk::MessageDelegate( m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::UpdateAllTableWidgetItems); workingImage->GetActiveLabelSet()->ActiveLabelEvent -= mitk::MessageDelegate1(m_Controls.m_LabelSetWidget, &QmitkLabelSetWidget::SelectLabelByPixelValue); workingImage->BeforeChangeLayerEvent -= mitk::MessageDelegate( this, &QmitkMultiLabelSegmentationView::OnLooseLabelSetConnection); } void QmitkMultiLabelSegmentationView::OnSegmentationSelectionChanged(const mitk::DataNode *node) { m_ToolManager->ActivateTool(-1); if (m_WorkingNode.IsNotNull()) { mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Loose LabelSetConnections OnLooseLabelSetConnection(); } m_WorkingNode = const_cast(node); if (m_WorkingNode.IsNotNull()) { mitk::LabelSetImage *workingImage = dynamic_cast(m_WorkingNode->GetData()); assert(workingImage); // Establish LabelSetConnection OnEstablishLabelSetConnection(); } m_ToolManager->SetWorkingData(m_WorkingNode); // check match of segmentation and reference image geometries if (node && m_ReferenceNode.IsNotNull()) { mitk::Image *refImage = dynamic_cast(m_ReferenceNode->GetData()); assert(refImage); 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) { 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) { 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; // iterate all segmentations (binary (single label) and LabelSetImages) mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateOr::Pointer allSegmentationsPredicate = mitk::NodePredicateOr::New(isBinaryPredicate, m_SegmentationPredicate); mitk::DataStorage::SetOfObjects::ConstPointer allSegmentations = GetDataStorage()->GetSubset(allSegmentationsPredicate); for (mitk::DataStorage::SetOfObjects::const_iterator it = allSegmentations->begin(); it != allSegmentations->end(); ++it) { segmentation = *it; labelSetImage = dynamic_cast(segmentation->GetData()); if (nullptr != labelSetImage) { // segmentation node is a multi label segmentation segmentation->SetProperty("labelset.contour.active", drawOutline); segmentation->SetProperty("opacity", mitk::FloatProperty::New(drawOutline->GetValue() ? 1.0f : 0.3f)); segmentation->SetProperty("volumerendering", volumeRendering); // force render window update to show outline segmentation->GetData()->Modified(); } else { // 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) { mitk::ApplicationCursor::GetInstance()->PopCursor(); m_MouseCursorSet = false; } } void QmitkMultiLabelSegmentationView::SetMouseCursor(const us::ModuleResource resource, int hotspotX, int hotspotY) { // Remove previously set mouse cursor if (m_MouseCursorSet) { mitk::ApplicationCursor::GetInstance()->PopCursor(); } us::ModuleResourceStream cursor(resource, std::ios::binary); mitk::ApplicationCursor::GetInstance()->PushCursor(cursor, hotspotX, hotspotY); m_MouseCursorSet = true; } void QmitkMultiLabelSegmentationView::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) { 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")); + mitk::StringProperty::New("MITK 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()); } }