diff --git a/Modules/DICOMQI/autoload/IO/CMakeLists.txt b/Modules/DICOMQI/autoload/IO/CMakeLists.txt index 4ea9d2932d..6e41cc8639 100644 --- a/Modules/DICOMQI/autoload/IO/CMakeLists.txt +++ b/Modules/DICOMQI/autoload/IO/CMakeLists.txt @@ -1,8 +1,8 @@ MITK_CREATE_MODULE( DICOMQIIO INCLUDE_DIRS PRIVATE src/IO - DEPENDS PUBLIC MitkMultilabel + DEPENDS PUBLIC MitkMultilabel MitkDICOMReader PACKAGE_DEPENDS PRIVATE DCMQI DCMTK AUTOLOAD_WITH MitkCore ) diff --git a/Modules/DICOMQI/autoload/IO/files.cmake b/Modules/DICOMQI/autoload/IO/files.cmake index 85559b779d..b6faaec765 100644 --- a/Modules/DICOMQI/autoload/IO/files.cmake +++ b/Modules/DICOMQI/autoload/IO/files.cmake @@ -1,6 +1,5 @@ set(CPP_FILES mitkDICOMSegmentationIO.cpp - mitkDICOMSegIOHelper.cpp mitkDICOMQIIOMimeTypes.cpp mitkDICOMQIActivator.cpp ) diff --git a/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.cpp b/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.cpp deleted file mode 100644 index 21fd5e3ebf..0000000000 --- a/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/*=================================================================== - -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 "mitkDICOMSegIOHelper.h" - -#include -#include -#include "mitkTemporoSpatialStringProperty.h" -#include "mitkImage.h" - -namespace mitk -{ - mitk::IDICOMTagsOfInterest* GetDicomTagsOfInterestService() - { - mitk::IDICOMTagsOfInterest* result = 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."; - } - result = us::GetModuleContext()->GetService(toiRegisters.front()); - } - - return result; - } - - FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList& pathsOfInterest, const DICOMDatasetAccessingImageFrameList& frames) - { - std::vector findings; - for (const auto& entry : pathsOfInterest) { - findings.push_back(frames.front()->GetTagValueAsString(entry)); - } - return findings; - } - - void SetProperties(BaseDataPointer image, const FindingsListVectorType& findings) - { - for (const auto& finding : findings) { - for (const auto& entry : finding) { - const std::string propertyName = mitk::DICOMTagPathToPropertyName(entry.path); - auto property = mitk::TemporoSpatialStringProperty::New(); - property->SetValue(entry.value); - image->SetProperty(propertyName.c_str(), property); - } - } - } - -} diff --git a/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.h b/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.h deleted file mode 100644 index e024a80ddd..0000000000 --- a/Modules/DICOMQI/autoload/IO/mitkDICOMSegIOHelper.h +++ /dev/null @@ -1,38 +0,0 @@ -/*=================================================================== - -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 MITKDICOMSegIOHelper_H -#define MITKDICOMSegIOHelper_H - -#include -#include - -#include "MitkDICOMQIIOExports.h" - -namespace mitk { - class BaseData; - - typedef std::vector FindingsListVectorType; - typedef BaseData* BaseDataPointer; - - mitk::IDICOMTagsOfInterest* GetDicomTagsOfInterestService(); - - FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList& pathsOfInterest, const DICOMDatasetAccessingImageFrameList& frames); - - void SetProperties(BaseDataPointer image, const FindingsListVectorType& findings); -} - -#endif diff --git a/Modules/DICOMQI/autoload/IO/mitkDICOMSegmentationIO.cpp b/Modules/DICOMQI/autoload/IO/mitkDICOMSegmentationIO.cpp index 2a073f6681..ef10baed96 100644 --- a/Modules/DICOMQI/autoload/IO/mitkDICOMSegmentationIO.cpp +++ b/Modules/DICOMQI/autoload/IO/mitkDICOMSegmentationIO.cpp @@ -1,700 +1,700 @@ /*=================================================================== 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 "mitkDICOMQIIOMimeTypes.h" -#include "mitkDICOMSegIOHelper.h" #include "mitkDICOMSegmentationConstants.h" #include +#include #include #include #include #include #include #include // itk #include // dcmqi #include // us #include #include namespace mitk { DICOMSegmentationIO::DICOMSegmentationIO() : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), mitk::MitkDICOMQIIOMimeTypes::DICOMQI_MIMETYPE_NAME(), "DICOM Segmentation") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); this->AddDICOMTagsToService(); } void DICOMSegmentationIO::AddDICOMTagsToService() { IDICOMTagsOfInterest *toiService = GetDicomTagsOfInterestService(); if (toiService != nullptr) { toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_SEQUENCE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_SEQUENCE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_CATEGORY_SEQUENCE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_TYPE_SEQUENCE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENTED_PROPERTY_MODIFIER_SEQUENCE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()); toiService->AddTagOfInterest(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()); } } 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("referenceFiles").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 { // Hack: Remove the const attribute to switch between the layer images. Normally you could get the different // layer images by input->GetLayerImage(layer) mitk::LabelSetImage *mitkLayerImage = const_cast(input); mitkLayerImage->SetActiveLayer(layer); // Cast mitk layer image to itk ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); imageToItkFilter->SetInput(mitkLayerImage); 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 label a segmentation image will be created const LabelSet *labelSet = input->GetLabelSet(layer); auto labelIter = labelSet->IteratorConstBegin(); // Ignore background label ++labelIter; for (; labelIter != labelSet->IteratorConstEnd(); ++labelIter) { // Thresold over the image with the given label value itk::ThresholdImageFilter::Pointer thresholdFilter = itk::ThresholdImageFilter::New(); thresholdFilter->SetInput(itkLabelImage); thresholdFilter->ThresholdOutside(labelIter->first, labelIter->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!"; //=============================== dcmqi part ==================================== // 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; dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str()); metaInfo.read(); MITK_INFO << "Input " << metaInfo.getJSONOutputAsString(); //=============================================================================== // Get the label information from segment attributes for each itk image vector>::const_iterator segmentIter = metaInfo.segmentsAttributesMappingList.begin(); // 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; } // Get Segment information map map segmentMap = (*segmentIter); map::const_iterator segmentMapIter = (*segmentIter).begin(); dcmqi::SegmentAttributes *segmentAttribute = (*segmentMapIter).second; OFString labelName; if (segmentAttribute->getSegmentedPropertyTypeCodeSequence() != nullptr) { segmentAttribute->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName); if (segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence() != nullptr) { OFString modifier; segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence()->getCodeMeaning(modifier); labelName.append(" (").append(modifier).append(")"); } } else { labelName = std::to_string(segmentAttribute->getLabelID()).c_str(); if (labelName.empty()) labelName = "Unnamed"; } float tmp[3] = {0.0, 0.0, 0.0}; if (segmentAttribute->getRecommendedDisplayRGBValue() != nullptr) { tmp[0] = segmentAttribute->getRecommendedDisplayRGBValue()[0] / 255.0; tmp[1] = segmentAttribute->getRecommendedDisplayRGBValue()[1] / 255.0; tmp[2] = segmentAttribute->getRecommendedDisplayRGBValue()[2] / 255.0; } Label *newLabel = nullptr; // 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 newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer()); newLabel->SetName(labelName.c_str()); newLabel->SetColor(Color(tmp)); newLabel->SetValue(segValue); } else { // Add a new layer to the labelSetImage. Background label is set automatically labelSetImage->AddLayer(layerImage); // Add new label newLabel = new Label; newLabel->SetName(labelName.c_str()); newLabel->SetColor(Color(tmp)); newLabel->SetValue(segValue); labelSetImage->GetLabelSet(labelSetImage->GetActiveLayer())->AddLabel(newLabel); } // Add some more label properties this->SetLabelProperties(newLabel, segmentAttribute); ++segmentIter; } // Add some general DICOM Segmentation properties mitk::IDICOMTagsOfInterest *toiSrv = GetDicomTagsOfInterestService(); auto tagsOfInterest = toiSrv->GetTagsOfInterest(); DICOMTagPathList tagsOfInterestList; for (const auto &tag : tagsOfInterest) { tagsOfInterestList.push_back(tag.first); } mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->SetInputFiles({GetInputLocation()}); scanner->AddTagPaths(tagsOfInterestList); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); if (frames.empty()) { MITK_ERROR << "Error reading the DICOM Seg file" << std::endl; return result; } auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames); SetProperties(labelSetImage, findings); // Set active layer to the first layer of the labelset image if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0) labelSetImage->SetActiveLayer(0); // 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; } 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; // 1. Metadata attributes that will be listed in the resulting DICOM SEG object std::string contentCreatorName; if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0070, 0x0084).c_str(), contentCreatorName)) contentCreatorName = "MITK"; handler.setContentCreatorName(contentCreatorName); std::string clinicalTrailSeriesId; if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0071).c_str(), clinicalTrailSeriesId)) clinicalTrailSeriesId = "Session 1"; handler.setClinicalTrialSeriesID(clinicalTrailSeriesId); std::string clinicalTrialTimePointID; if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0050).c_str(), clinicalTrialTimePointID)) clinicalTrialTimePointID = "0"; handler.setClinicalTrialTimePointID(clinicalTrialTimePointID); std::string clinicalTrialCoordinatingCenterName = ""; if (!image->GetPropertyList()->GetStringProperty(GeneratePropertyNameForDICOMTag(0x0012, 0x0060).c_str(), clinicalTrialCoordinatingCenterName)) clinicalTrialCoordinatingCenterName = "Unknown"; handler.setClinicalTrialCoordinatingCenterName(clinicalTrialCoordinatingCenterName); std::string seriesDescription; if (!image->GetPropertyList()->GetStringProperty("name", seriesDescription)) seriesDescription = "MITK Segmentation"; handler.setSeriesDescription(seriesDescription); handler.setSeriesNumber("0" + std::to_string(layer)); handler.setInstanceNumber("1"); handler.setBodyPartExamined(""); const LabelSet *labelSet = image->GetLabelSet(layer); auto labelIter = labelSet->IteratorConstBegin(); // Ignore background label ++labelIter; for (; labelIter != labelSet->IteratorConstEnd(); ++labelIter) { const Label *label = labelIter->second; if (label != nullptr) { StringProperty *segmentNumberProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str())); StringProperty *segmentLabelProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str())); StringProperty *algorithmTypeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str())); StringProperty *segmentCategoryCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str())); StringProperty *segmentCategoryCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str())); StringProperty *segmentCategoryCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str())); StringProperty *segmentTypeCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str())); StringProperty *segmentTypeCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str())); StringProperty *segmentTypeCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str())); StringProperty *segmentModifierCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str())); StringProperty *segmentModifierCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str())); StringProperty *segmentModifierCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str())); dcmqi::SegmentAttributes *segmentAttribute = nullptr; if (segmentNumberProp->GetValue() == nullptr) { MITK_ERROR << "Something went wrong with the label ID."; } else { int labelId = std::stoi(segmentNumberProp->GetValue()); segmentAttribute = handler.createAndGetNewSegment(labelId); } if (segmentAttribute != nullptr) { segmentAttribute->setSegmentDescription(segmentLabelProp->GetValueAsString()); segmentAttribute->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString()); segmentAttribute->setSegmentAlgorithmName("MITK Segmentation"); if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr && segmentCategoryCodeMeaningProp != nullptr) segmentAttribute->setSegmentedPropertyCategoryCodeSequence( segmentCategoryCodeValueProp->GetValueAsString(), segmentCategoryCodeSchemeProp->GetValueAsString(), segmentCategoryCodeMeaningProp->GetValueAsString()); else // some default values segmentAttribute->setSegmentedPropertyCategoryCodeSequence( "M-01000", "SRT", "Morphologically Altered Structure"); if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr && segmentTypeCodeMeaningProp != nullptr) { segmentAttribute->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->GetValueAsString(), segmentTypeCodeSchemeProp->GetValueAsString(), segmentTypeCodeMeaningProp->GetValueAsString()); handler.setBodyPartExamined(segmentTypeCodeMeaningProp->GetValueAsString()); } else { // some default values segmentAttribute->setSegmentedPropertyTypeCodeSequence("M-03000", "SRT", "Mass"); handler.setBodyPartExamined("Mass"); } if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr && segmentModifierCodeMeaningProp != nullptr) segmentAttribute->setSegmentedPropertyTypeModifierCodeSequence( segmentModifierCodeValueProp->GetValueAsString(), segmentModifierCodeSchemeProp->GetValueAsString(), segmentModifierCodeMeaningProp->GetValueAsString()); Color color = label->GetColor(); segmentAttribute->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255); } } } return handler.getJSONOutputAsString(); } void mitk::DICOMSegmentationIO::SetLabelProperties(mitk::Label *label, dcmqi::SegmentAttributes *segmentAttribute) { // 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 label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str(), StringProperty::New(std::to_string(label->GetValue()))); // Segment Label: User-defined label identifying this segment. label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str(), StringProperty::New(label->GetName())); // Segment Algorithm Type: Type of algorithm used to generate the segment. if (!segmentAttribute->getSegmentAlgorithmType().empty()) label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str(), StringProperty::New(segmentAttribute->getSegmentAlgorithmType())); // Add Segmented Property Category Code Sequence tags auto categoryCodeSequence = segmentAttribute->getSegmentedPropertyCategoryCodeSequence(); if (categoryCodeSequence != nullptr) { OFString codeValue; // (0008,0100) Code Value categoryCodeSequence->getCodeValue(codeValue); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str(), StringProperty::New(codeValue.c_str())); OFString codeScheme; // (0008,0102) Coding Scheme Designator categoryCodeSequence->getCodingSchemeDesignator(codeScheme); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str(), StringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning categoryCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str(), StringProperty::New(codeMeaning.c_str())); } // Add Segmented Property Type Code Sequence tags auto typeCodeSequence = segmentAttribute->getSegmentedPropertyTypeCodeSequence(); if (typeCodeSequence != nullptr) { OFString codeValue; // (0008,0100) Code Value typeCodeSequence->getCodeValue(codeValue); label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str(), StringProperty::New(codeValue.c_str())); OFString codeScheme; // (0008,0102) Coding Scheme Designator typeCodeSequence->getCodingSchemeDesignator(codeScheme); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str(), StringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning typeCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str(), StringProperty::New(codeMeaning.c_str())); } // Add Segmented Property Type Modifier Code Sequence tags auto modifierCodeSequence = segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence(); if (modifierCodeSequence != nullptr) { OFString codeValue; // (0008,0100) Code Value modifierCodeSequence->getCodeValue(codeValue); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str(), StringProperty::New(codeValue.c_str())); OFString codeScheme; // (0008,0102) Coding Scheme Designator modifierCodeSequence->getCodingSchemeDesignator(codeScheme); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str(), StringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning modifierCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str(), StringProperty::New(codeMeaning.c_str())); } // Add Atomic RegionSequence tags auto atomicRegionSequence = segmentAttribute->getAnatomicRegionSequence(); if (atomicRegionSequence != nullptr) { OFString codeValue; // (0008,0100) Code Value atomicRegionSequence->getCodeValue(codeValue); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_VALUE_PATH()).c_str(), StringProperty::New(codeValue.c_str())); OFString codeScheme; // (0008,0102) Coding Scheme Designator atomicRegionSequence->getCodingSchemeDesignator(codeScheme); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_SCHEME_PATH()).c_str(), StringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning atomicRegionSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH()).c_str(), StringProperty::New(codeMeaning.c_str())); } } DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); } } // namespace #endif //__mitkDICOMSegmentationIO__cpp diff --git a/Modules/DICOMReader/files.cmake b/Modules/DICOMReader/files.cmake index bcfb0850c7..07c291c856 100644 --- a/Modules/DICOMReader/files.cmake +++ b/Modules/DICOMReader/files.cmake @@ -1,51 +1,52 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkBaseDICOMReaderService.cpp mitkDICOMFileReader.cpp mitkDICOMTagScanner.cpp mitkDICOMGDCMTagScanner.cpp mitkDICOMDCMTKTagScanner.cpp mitkDICOMImageBlockDescriptor.cpp mitkDICOMITKSeriesGDCMReader.cpp mitkDICOMDatasetSorter.cpp mitkDICOMTagBasedSorter.cpp mitkDICOMGDCMImageFrameInfo.cpp mitkDICOMImageFrameInfo.cpp + mitkDICOMIOHelper.cpp mitkDICOMGenericImageFrameInfo.cpp mitkDICOMDatasetAccessingImageFrameInfo.cpp mitkDICOMSortCriterion.cpp mitkDICOMSortByTag.cpp mitkITKDICOMSeriesReaderHelper.cpp mitkEquiDistantBlocksSorter.cpp mitkNormalDirectionConsistencySorter.cpp mitkSortByImagePositionPatient.cpp mitkGantryTiltInformation.cpp mitkClassicDICOMSeriesReader.cpp mitkThreeDnTDICOMSeriesReader.cpp mitkDICOMTag.cpp mitkDICOMTagsOfInterestHelper.cpp mitkDICOMTagCache.cpp mitkDICOMGDCMTagCache.cpp mitkDICOMGenericTagCache.cpp mitkDICOMEnums.cpp mitkDICOMReaderConfigurator.cpp mitkDICOMFileReaderSelector.cpp mitkIDICOMTagsOfInterest.cpp mitkDICOMTagPath.cpp mitkDICOMProperty.cpp mitkDICOMFilesHelper.cpp ) set(RESOURCE_FILES configurations/3D/classicreader.xml configurations/3D/imageposition.xml configurations/3D/imageposition_byacquisition.xml configurations/3D/instancenumber.xml configurations/3D/instancenumber_soft.xml configurations/3D/slicelocation.xml configurations/3DnT/classicreader.xml configurations/3DnT/imageposition_byacquisition.xml configurations/3DnT/imageposition_bytriggertime.xml ) diff --git a/Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.h b/Modules/DICOMReader/include/mitkDICOMIOHelper.h similarity index 53% rename from Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.h rename to Modules/DICOMReader/include/mitkDICOMIOHelper.h index aa07d095cb..48b0b7bfb1 100644 --- a/Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.h +++ b/Modules/DICOMReader/include/mitkDICOMIOHelper.h @@ -1,38 +1,40 @@ /*=================================================================== 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 MITKDicomRTIOHelper_H -#define MITKDicomRTIOHelper_H +#ifndef MITKDICOMIOHelper_H +#define MITKDICOMIOHelper_H -#include #include "mitkDICOMDatasetAccessingImageFrameInfo.h" +#include "mitkIDICOMTagsOfInterest.h" -#include +#include -namespace mitk { +namespace mitk +{ class BaseData; typedef std::vector FindingsListVectorType; - typedef BaseData* BaseDataPointer; + typedef BaseData *BaseDataPointer; - mitk::IDICOMTagsOfInterest* GetDicomTagsOfInterestService(); + MITKDICOMREADER_EXPORT mitk::IDICOMTagsOfInterest *GetDicomTagsOfInterestService(); - FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList& pathsOfInterest, const DICOMDatasetAccessingImageFrameList& frames); + MITKDICOMREADER_EXPORT FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList &pathsOfInterest, + const DICOMDatasetAccessingImageFrameList &frames); - void SetProperties(BaseDataPointer image, const FindingsListVectorType& findings); + MITKDICOMREADER_EXPORT void SetProperties(BaseDataPointer image, const FindingsListVectorType &findings); } #endif diff --git a/Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.cpp b/Modules/DICOMReader/src/mitkDICOMIOHelper.cpp similarity index 68% rename from Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.cpp rename to Modules/DICOMReader/src/mitkDICOMIOHelper.cpp index 7a93419db9..59f29af021 100644 --- a/Modules/DicomRT/autoload/IO/mitkDicomRTIOHelper.cpp +++ b/Modules/DICOMReader/src/mitkDICOMIOHelper.cpp @@ -1,64 +1,69 @@ /*=================================================================== 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 "mitkDicomRTIOHelper.h" +#include "mitkDICOMIOHelper.h" + +#include +#include -#include #include -#include "mitkTemporoSpatialStringProperty.h" -#include "mitkImage.h" +#include namespace mitk { - mitk::IDICOMTagsOfInterest* GetDicomTagsOfInterestService() + mitk::IDICOMTagsOfInterest *GetDicomTagsOfInterestService() { - mitk::IDICOMTagsOfInterest* result = nullptr; + mitk::IDICOMTagsOfInterest *result = nullptr; - std::vector > toiRegisters = us::GetModuleContext()->GetServiceReferences(); + 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."; } result = us::GetModuleContext()->GetService(toiRegisters.front()); } return result; } - FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList& pathsOfInterest, const DICOMDatasetAccessingImageFrameList& frames) + FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList &pathsOfInterest, + const DICOMDatasetAccessingImageFrameList &frames) { - std::vector findings; - for (const auto& entry : pathsOfInterest) { + std::vector findings; + for (const auto &entry : pathsOfInterest) + { findings.push_back(frames.front()->GetTagValueAsString(entry)); } return findings; } - void SetProperties(BaseDataPointer image, const FindingsListVectorType& findings) + void SetProperties(BaseDataPointer image, const FindingsListVectorType &findings) { - for (const auto& finding : findings) { - for (const auto& entry : finding) { + for (const auto &finding : findings) + { + for (const auto &entry : finding) + { const std::string propertyName = mitk::DICOMTagPathToPropertyName(entry.path); auto property = mitk::TemporoSpatialStringProperty::New(); property->SetValue(entry.value); image->SetProperty(propertyName.c_str(), property); } } } - } diff --git a/Modules/DicomRT/autoload/IO/files.cmake b/Modules/DicomRT/autoload/IO/files.cmake index 5bcdb2f9d9..f3970e6991 100644 --- a/Modules/DicomRT/autoload/IO/files.cmake +++ b/Modules/DicomRT/autoload/IO/files.cmake @@ -1,8 +1,7 @@ set(CPP_FILES mitkDicomRTIOActivator.cpp mitkDicomRTIOMimeTypes.cpp mitkRTDoseReaderService.cpp mitkRTPlanReaderService.cpp mitkRTStructureSetReaderService.cpp - mitkDicomRTIOHelper.cpp ) diff --git a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp index 08ba6abb55..74b935d036 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp @@ -1,172 +1,172 @@ /*=================================================================== 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 "mitkRTDoseReaderService.h" #include #include #include #include #include #include #include #include #include "mitkDICOMDCMTKTagScanner.h" #include "mitkDicomRTIOMimeTypes.h" -#include "mitkDicomRTIOHelper.h" +#include #include "dcmtk/dcmrt/drtdose.h" #include #include namespace mitk { RTDoseReaderService::RTDoseReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTIOMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()), mitk::DicomRTIOMimeTypes::DICOMRT_DOSE_MIMETYPE_DESCRIPTION()) { m_FileReaderServiceReg = RegisterService(); } RTDoseReaderService::RTDoseReaderService(const RTDoseReaderService& other) : mitk::AbstractFileReader(other) { } RTDoseReaderService::~RTDoseReaderService() {} template void RTDoseReaderService::MultiplyGridScaling(itk::Image* image, float gridscale) { typedef itk::Image OutputImageType; typedef itk::Image InputImageType; typedef itk::CastImageFilter CastFilterType; typedef itk::ShiftScaleImageFilter ScaleFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); typename ScaleFilterType::Pointer scaleFilter = ScaleFilterType::New(); castFilter->SetInput(image); scaleFilter->SetInput(castFilter->GetOutput()); scaleFilter->SetScale(gridscale); scaleFilter->Update(); typename OutputImageType::Pointer scaledOutput = scaleFilter->GetOutput(); this->scaledDoseImage = mitk::Image::New(); mitk::CastToMitkImage(scaledOutput, this->scaledDoseImage); } std::vector > RTDoseReaderService::Read() { std::vector > result; mitk::IDICOMTagsOfInterest* toiSrv = GetDicomTagsOfInterestService(); auto tagsOfInterest = toiSrv->GetTagsOfInterest(); DICOMTagPathList tagsOfInterestList; for (const auto& tag : tagsOfInterest) { tagsOfInterestList.push_back(tag.first); } std::string location = GetInputLocation(); mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New(); selector->LoadBuiltIn3DConfigs(); selector->SetInputFiles({ location }); mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages(); reader->SetAdditionalTagsOfInterest(toiSrv->GetTagsOfInterest()); reader->SetInputFiles({ location }); reader->AnalyzeInputFiles(); reader->LoadImages(); if (reader->GetNumberOfOutputs() == 0) { MITK_ERROR << "Could not determine a DICOM reader for this file" << std::endl; return result; } mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->SetInputFiles({ location }); scanner->AddTagPaths(tagsOfInterestList); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); if (frames.empty()) { MITK_ERROR << "Error reading the RTDOSE file" << std::endl; return result; } const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(0); mitk::Image::Pointer originalImage = desc.GetMitkImage(); if (originalImage.IsNull()) { MITK_ERROR << "Error reading the RTDOSE file in mitk::DicomFileReader" << std::endl; return result; } DcmFileFormat fileformat; OFCondition outp = fileformat.loadFile(location.c_str(), EXS_Unknown); if (outp.bad()) { MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl; return result; } DcmDataset *dataset = fileformat.getDataset(); DRTDoseIOD doseObject; OFCondition DCMTKresult = doseObject.read(*dataset); if (DCMTKresult.bad()) { MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl; return result; } auto findingsGridScaling = frames.front()->GetTagValueAsString(DICOMTagPath(0x3004, 0x000e)); //(0x3004, 0x000e) is grid scaling double gridScaling; if (findingsGridScaling.empty()) { MITK_ERROR << "Could not find DoseGridScaling tag" << std::endl; return result; } else { gridScaling = boost::lexical_cast(findingsGridScaling.front().value); } AccessByItk_1(originalImage, MultiplyGridScaling, gridScaling); auto statistics = this->scaledDoseImage->GetStatistics(); double maxDose = statistics->GetScalarValueMax(); this->scaledDoseImage->SetPropertyList(originalImage->GetPropertyList()); this->scaledDoseImage->SetProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(), mitk::GenericProperty::New(0.8*maxDose)); auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames); SetProperties(this->scaledDoseImage, findings); result.push_back(this->scaledDoseImage.GetPointer()); return result; } RTDoseReaderService* RTDoseReaderService::Clone() const { return new RTDoseReaderService(*this); } } diff --git a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp index b59594787d..7d5e9c301f 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp @@ -1,86 +1,86 @@ /*=================================================================== 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 "mitkRTPlanReaderService.h" #include "mitkImage.h" #include "mitkDICOMDCMTKTagScanner.h" #include "mitkIOMimeTypes.h" -#include "mitkDicomRTIOHelper.h" +#include #include "mitkDICOMTagPath.h" #include "mitkDICOMTagsOfInterestService.h" #include "mitkDICOMDatasetAccessingImageFrameInfo.h" #include "mitkDicomRTIOMimeTypes.h" namespace mitk { RTPlanReaderService::RTPlanReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTIOMimeTypes::DICOMRT_PLAN_MIMETYPE_NAME()), mitk::DicomRTIOMimeTypes::DICOMRT_PLAN_MIMETYPE_DESCRIPTION()) { m_FileReaderServiceReg = RegisterService(); } RTPlanReaderService::RTPlanReaderService(const RTPlanReaderService& other) : mitk::AbstractFileReader(other) { } RTPlanReaderService::~RTPlanReaderService() {} std::vector > RTPlanReaderService::Read() { std::vector > result; auto DICOMTagsOfInterestService = GetDicomTagsOfInterestService(); auto tagsOfInterest = DICOMTagsOfInterestService->GetTagsOfInterest(); DICOMTagPathList tagsOfInterestList; for (const auto& tag : tagsOfInterest) { tagsOfInterestList.push_back(tag.first); } std::string location = GetInputLocation(); mitk::StringList files = { location }; mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->SetInputFiles(files); scanner->AddTagPaths(tagsOfInterestList); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); if (frames.empty()) { MITK_ERROR << "Error reading the RTPLAN file" << std::endl; return result; } auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames); //just create empty image. No image information available in RTPLAN. But properties will be attached. Image::Pointer dummyImage = Image::New(); mitk::PixelType pt = mitk::MakeScalarPixelType(); unsigned int dim[] = { 1,1}; dummyImage->Initialize(pt, 2, dim); SetProperties(dummyImage, findings); result.push_back(dummyImage.GetPointer()); return result; } RTPlanReaderService* RTPlanReaderService::Clone() const { return new RTPlanReaderService(*this); } } diff --git a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp index 85b895af2d..47fbcd6d5c 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp @@ -1,292 +1,292 @@ /*=================================================================== 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 "mitkRTStructureSetReaderService.h" #include "mitkDicomRTIOMimeTypes.h" -#include "mitkDicomRTIOHelper.h" +#include #include #include #include "dcmtk/dcmrt/drtstrct.h" namespace mitk { RTStructureSetReaderService::RTStructureSetReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTIOMimeTypes::DICOMRT_STRUCT_MIMETYPE_NAME()), mitk::DicomRTIOMimeTypes::DICOMRT_STRUCT_MIMETYPE_DESCRIPTION()) { m_FileReaderServiceReg = RegisterService(); } RTStructureSetReaderService::RTStructureSetReaderService(const RTStructureSetReaderService& other) : mitk::AbstractFileReader(other) { } RTStructureSetReaderService::~RTStructureSetReaderService() {} RTStructureSetReaderService::RoiEntry::RoiEntry() { Number = 0; DisplayColor[0] = 1.0; DisplayColor[1] = 0.0; DisplayColor[2] = 0.0; ContourModelSet = mitk::ContourModelSet::New(); } RTStructureSetReaderService::RoiEntry::RoiEntry(const RoiEntry& src) { Number = src.Number; Name = src.Name; Description = src.Description; DisplayColor[0] = src.DisplayColor[0]; DisplayColor[1] = src.DisplayColor[1]; DisplayColor[2] = src.DisplayColor[2]; ContourModelSet = mitk::ContourModelSet::New(); SetPolyData(src.ContourModelSet); } RTStructureSetReaderService::RoiEntry::~RoiEntry() {} RTStructureSetReaderService::RoiEntry& RTStructureSetReaderService:: RoiEntry::operator =(const RoiEntry& src) { Number = src.Number; Name = src.Name; Description = src.Description; DisplayColor[0] = src.DisplayColor[0]; DisplayColor[1] = src.DisplayColor[1]; DisplayColor[2] = src.DisplayColor[2]; SetPolyData(src.ContourModelSet); return (*this); } void RTStructureSetReaderService::RoiEntry:: SetPolyData(mitk::ContourModelSet::Pointer roiPolyData) { if (roiPolyData == this->ContourModelSet) { return; } this->ContourModelSet = roiPolyData; } size_t RTStructureSetReaderService::GetNumberOfROIs() const { return this->ROISequenceVector.size(); } RTStructureSetReaderService::RoiEntry* RTStructureSetReaderService:: FindRoiByNumber(unsigned int roiNum) { for (unsigned int i = 0; i < this->ROISequenceVector.size(); ++i) { if (this->ROISequenceVector[i].Number == roiNum) { return &this->ROISequenceVector[i]; } } return nullptr; } std::vector > RTStructureSetReaderService::Read() { std::vector > result; std::string location = GetInputLocation(); auto DICOMTagsOfInterestService = GetDicomTagsOfInterestService(); auto tagsOfInterest = DICOMTagsOfInterestService->GetTagsOfInterest(); DICOMTagPathList tagsOfInterestList; for (const auto& tag : tagsOfInterest) { tagsOfInterestList.push_back(tag.first); } mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->SetInputFiles({ location }); scanner->AddTagPaths(tagsOfInterestList); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); if (frames.empty()) { MITK_ERROR << "Error reading the RTSTRUCT file" << std::endl; return result; } auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames); DcmFileFormat file; OFCondition output = file.loadFile(location.c_str(), EXS_Unknown); if (output.bad()) { MITK_ERROR << "Can't read the file" << std::endl; return result; } DcmDataset* dataset = file.getDataset(); DRTStructureSetIOD structureSetObject; OFCondition outp = structureSetObject.read(*dataset); if (!outp.good()) { MITK_ERROR << "Error reading the file" << std::endl; return result; } DRTStructureSetROISequence& roiSequence = structureSetObject.getStructureSetROISequence(); if (!roiSequence.gotoFirstItem().good()) { MITK_ERROR << "Error reading the structure sequence" << std::endl; return result; } do { DRTStructureSetROISequence::Item& currentSequence = roiSequence.getCurrentItem(); if (!currentSequence.isValid()) { continue; } OFString roiName; OFString roiDescription; Sint32 roiNumber; RoiEntry roi; currentSequence.getROIName(roiName); currentSequence.getROIDescription(roiDescription); currentSequence.getROINumber(roiNumber); roi.Name = roiName.c_str(); roi.Description = roiDescription.c_str(); roi.Number = roiNumber; this->ROISequenceVector.push_back(roi); } while (roiSequence.gotoNextItem().good()); Sint32 refRoiNumber; DRTROIContourSequence& roiContourSeqObject = structureSetObject.getROIContourSequence(); if (!roiContourSeqObject.gotoFirstItem().good()) { MITK_ERROR << "Error reading the contour sequence" << std::endl; return result; } do { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); DRTROIContourSequence::Item& currentRoiObject = roiContourSeqObject.getCurrentItem(); if (!currentRoiObject.isValid()) { continue; } currentRoiObject.getReferencedROINumber(refRoiNumber); DRTContourSequence& contourSeqObject = currentRoiObject.getContourSequence(); if (contourSeqObject.getNumberOfItems() > 0 && contourSeqObject.gotoFirstItem().good()) { do { DRTContourSequence::Item& contourItem = contourSeqObject.getCurrentItem(); if (!contourItem.isValid()) { continue; } OFString contourNumber; OFString numberOfPoints; OFVector contourData_LPS; mitk::ContourModel::Pointer contourSequence = mitk::ContourModel::New(); contourItem.getContourNumber(contourNumber); contourItem.getNumberOfContourPoints(numberOfPoints); contourItem.getContourData(contourData_LPS); for (unsigned int i = 0; i < contourData_LPS.size() / 3; i++) { mitk::Point3D point; point[0] = contourData_LPS.at(3 * i); point[1] = contourData_LPS.at(3 * i + 1); point[2] = contourData_LPS.at(3 * i + 2); contourSequence->AddVertex(point); } contourSequence->Close(); contourSet->AddContourModel(contourSequence); } while (contourSeqObject.gotoNextItem().good()); } else { MITK_WARN << "contourSeqObject has no items in sequence. Object is neglected and not read. Struct name: " << this->FindRoiByNumber(refRoiNumber)->Name << std::endl; } RoiEntry* refROI = this->FindRoiByNumber(refRoiNumber); if (refROI == NULL) { MITK_ERROR << "Can not find references ROI" << std::endl; continue; } Sint32 roiColor; for (unsigned int j = 0; j < 3; j++) { currentRoiObject.getROIDisplayColor(roiColor, j); refROI->DisplayColor[j] = roiColor / 255.0; } refROI->ContourModelSet = contourSet; contourSet->SetProperty("name", mitk::StringProperty::New(refROI->Name)); contourSet->SetProperty("contour.color", mitk::ColorProperty::New( refROI->DisplayColor[0], refROI->DisplayColor[1], refROI->DisplayColor[2])); } while (roiContourSeqObject.gotoNextItem().good()); for (auto const& aROI : ROISequenceVector) { result.push_back(aROI.ContourModelSet.GetPointer()); result.at(result.size() - 1)->SetProperty("name", aROI.ContourModelSet->GetProperty("name")); result.at(result.size() - 1)->SetProperty("color", aROI.ContourModelSet->GetProperty("contour.color")); result.at(result.size() - 1)->SetProperty("contour.color", aROI.ContourModelSet->GetProperty("contour.color")); SetProperties(result.at(result.size() - 1).GetPointer(), findings); } return result; } RTStructureSetReaderService* RTStructureSetReaderService::Clone() const { return new RTStructureSetReaderService(*this); } }