13 #ifndef __mitkDICOMSegmentationIO__cpp 14 #define __mitkDICOMSegmentationIO__cpp 31 #include <itkThresholdImageFilter.h> 34 #include <dcmqi/ImageSEGConverter.h> 51 this->AddDICOMTagsToService();
54 void DICOMSegmentationIO::AddDICOMTagsToService()
57 if (toiService !=
nullptr)
99 MITK_INFO <<
"DICOM segmentation writer is tested only with 3D images, sorry.";
107 if (dicomFilesProp.IsNotNull())
123 if (input ==
nullptr)
124 mitkThrow() <<
"Cannot write non-image data";
127 vector<std::unique_ptr<DcmDataset>> dcmDatasetsSourceImage;
128 std::unique_ptr<DcmFileFormat> readFileFormat(
new DcmFileFormat());
136 if (filesProp.IsNull())
138 mitkThrow() <<
"No property with dicom file path.";
145 for (
auto it : lookUpTableMap)
147 const char *fileName = (it.second).c_str();
148 if (readFileFormat->loadFile(fileName, EXS_Unknown).good())
150 std::unique_ptr<DcmDataset> readDCMDataset(readFileFormat->getAndRemoveDataset());
151 dcmDatasetsSourceImage.push_back(std::move(readDCMDataset));
155 catch (
const std::exception &e)
157 MITK_ERROR <<
"An error occurred while getting the dicom informations: " << e.what() << endl;
162 for (
unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer)
164 vector<itkInternalImageType::Pointer> segmentations;
175 imageToItkFilter->SetInput(mitkLayerImage);
177 typedef itk::CastImageFilter<itkInputImageType, itkInternalImageType> castItkImageFilterType;
178 castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
179 castFilter->SetInput(imageToItkFilter->GetOutput());
180 castFilter->Update();
182 itkInternalImageType::Pointer itkLabelImage = castFilter->GetOutput();
183 itkLabelImage->DisconnectPipeline();
186 const LabelSet *labelSet = input->GetLabelSet(layer);
194 itk::ThresholdImageFilter<itkInternalImageType>::Pointer thresholdFilter =
195 itk::ThresholdImageFilter<itkInternalImageType>::New();
196 thresholdFilter->SetInput(itkLabelImage);
197 thresholdFilter->ThresholdOutside(labelIter->first, labelIter->first);
198 thresholdFilter->SetOutsideValue(0);
199 thresholdFilter->Update();
200 itkInternalImageType::Pointer segmentImage = thresholdFilter->GetOutput();
201 segmentImage->DisconnectPipeline();
203 segmentations.push_back(segmentImage);
206 catch (
const itk::ExceptionObject &e)
213 const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFile(layer);
215 MITK_INFO <<
"Writing image: " << path << std::endl;
219 vector<DcmDataset*> rawVecDataset;
220 for (
const auto& dcmDataSet : dcmDatasetsSourceImage)
221 rawVecDataset.push_back(dcmDataSet.get());
224 std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
225 std::unique_ptr<DcmDataset> result(converter->itkimage2dcmSegmentation(rawVecDataset, segmentations, tmpMetaInfoFile));
228 DcmFileFormat dcmFileFormat(result.get());
230 std::string filePath = path.substr(0, path.find_last_of(
"."));
232 if (input->GetNumberOfLayers() != 1)
233 filePath = filePath + std::to_string(layer) +
".dcm";
235 filePath = filePath +
".dcm";
237 dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit);
239 catch (
const std::exception &e)
241 MITK_ERROR <<
"An error occurred during writing the DICOM Seg: " << e.what() << endl;
254 DcmFileFormat dcmFileFormat;
255 OFCondition status = dcmFileFormat.loadFile(fileName.c_str());
261 if (dcmFileFormat.getDataset()->findAndGetOFString(DCM_Modality, modality).good())
263 if (modality.compare(
"SEG") == 0)
276 std::vector<BaseData::Pointer> result;
280 MITK_INFO <<
"loading " << path << std::endl;
283 mitkThrow() <<
"Empty filename in mitk::ItkImageIO ";
288 DcmFileFormat dcmFileFormat;
289 OFCondition status = dcmFileFormat.loadFile(path.c_str());
291 mitkThrow() <<
"Can't read the input file!";
293 DcmDataset *dataSet = dcmFileFormat.getDataset();
294 if (dataSet ==
nullptr)
295 mitkThrow() <<
"Can't read data from input file!";
299 std::unique_ptr<dcmqi::ImageSEGConverter> converter = std::make_unique<dcmqi::ImageSEGConverter>();
300 pair<map<unsigned, itkInternalImageType::Pointer>,
string> dcmqiOutput =
301 converter->dcmSegmentation2itkimage(dataSet);
303 map<unsigned, itkInternalImageType::Pointer> segItkImages = dcmqiOutput.first;
305 dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str());
308 MITK_INFO <<
"Input " << metaInfo.getJSONOutputAsString();
312 vector<map<unsigned, dcmqi::SegmentAttributes *>>::const_iterator segmentIter =
313 metaInfo.segmentsAttributesMappingList.begin();
316 for (
auto &element : segItkImages)
319 typedef itk::CastImageFilter<itkInternalImageType, itkInputImageType> castItkImageFilterType;
320 castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New();
321 castFilter->SetInput(element.second);
322 castFilter->Update();
329 typedef itk::ImageRegionIterator<const itkInternalImageType> IteratorType;
331 IteratorType iter(element.second, element.second->GetLargestPossibleRegion());
333 while (!iter.IsAtEnd())
335 itkInputImageType::PixelType value = iter.Get();
344 map<unsigned, dcmqi::SegmentAttributes *> segmentMap = (*segmentIter);
345 map<unsigned, dcmqi::SegmentAttributes *>::const_iterator segmentMapIter = (*segmentIter).begin();
346 dcmqi::SegmentAttributes *segmentAttribute = (*segmentMapIter).second;
350 if (segmentAttribute->getSegmentedPropertyTypeCodeSequence() !=
nullptr)
352 segmentAttribute->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName);
353 if (segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence() !=
nullptr)
356 segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence()->getCodeMeaning(modifier);
357 labelName.append(
" (").append(modifier).append(
")");
362 labelName = std::to_string(segmentAttribute->getLabelID()).c_str();
363 if (labelName.empty())
364 labelName =
"Unnamed";
367 float tmp[3] = { 0.0, 0.0, 0.0 };
368 if (segmentAttribute->getRecommendedDisplayRGBValue() !=
nullptr)
370 tmp[0] = segmentAttribute->getRecommendedDisplayRGBValue()[0] / 255.0;
371 tmp[1] = segmentAttribute->getRecommendedDisplayRGBValue()[1] / 255.0;
372 tmp[2] = segmentAttribute->getRecommendedDisplayRGBValue()[2] / 255.0;
375 Label *newLabel =
nullptr;
377 if (labelSetImage.IsNull())
381 labelSetImage->InitializeByLabeledImage(layerImage);
383 newLabel = labelSetImage->GetActiveLabel(labelSetImage->GetActiveLayer());
384 newLabel->
SetName(labelName.c_str());
391 labelSetImage->AddLayer(layerImage);
394 newLabel =
new Label;
395 newLabel->
SetName(labelName.c_str());
398 labelSetImage->GetLabelSet(labelSetImage->GetActiveLayer())->AddLabel(newLabel);
402 this->SetLabelProperties(newLabel, segmentAttribute);
406 labelSetImage->GetLabelSet()->SetAllLabelsVisible(
true);
412 for (
const auto &tag : tagsOfInterest)
414 tagsOfInterestList.push_back(tag.first);
419 scanner->AddTagPaths(tagsOfInterestList);
425 MITK_ERROR <<
"Error reading the DICOM Seg file" << std::endl;
433 if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0)
434 labelSetImage->SetActiveLayer(0);
436 catch (
const std::exception &e)
438 MITK_ERROR <<
"An error occurred while reading the DICOM Seg file: " << e.what();
443 MITK_ERROR <<
"An error occurred in dcmqi while reading the DICOM Seg file";
447 result.push_back(labelSetImage.GetPointer());
451 const std::string mitk::DICOMSegmentationIO::CreateMetaDataJsonFile(
int layer)
455 const std::string output;
456 dcmqi::JSONSegmentationMetaInformationHandler
handler;
460 std::string contentCreatorName;
463 contentCreatorName =
"MITK";
464 handler.setContentCreatorName(contentCreatorName);
466 std::string clinicalTrailSeriesId;
468 clinicalTrailSeriesId))
469 clinicalTrailSeriesId =
"Session 1";
470 handler.setClinicalTrialSeriesID(clinicalTrailSeriesId);
472 std::string clinicalTrialTimePointID;
474 clinicalTrialTimePointID))
475 clinicalTrialTimePointID =
"0";
476 handler.setClinicalTrialTimePointID(clinicalTrialTimePointID);
478 std::string clinicalTrialCoordinatingCenterName =
"";
480 clinicalTrialCoordinatingCenterName))
481 clinicalTrialCoordinatingCenterName =
"Unknown";
482 handler.setClinicalTrialCoordinatingCenterName(clinicalTrialCoordinatingCenterName);
484 std::string seriesDescription;
485 if (!image->
GetPropertyList()->GetStringProperty(
"name", seriesDescription))
486 seriesDescription =
"MITK Segmentation";
487 handler.setSeriesDescription(seriesDescription);
489 handler.setSeriesNumber(
"0" + std::to_string(layer));
490 handler.setInstanceNumber(
"1");
491 handler.setBodyPartExamined(
"");
500 const Label *label = labelIter->second;
502 if (label !=
nullptr)
540 dcmqi::SegmentAttributes *segmentAttribute =
nullptr;
542 if (segmentNumberProp->
GetValue() ==
"")
544 MITK_ERROR <<
"Something went wrong with the label ID.";
548 int labelId = std::stoi(segmentNumberProp->
GetValue());
549 segmentAttribute = handler.createAndGetNewSegment(labelId);
551 if (segmentAttribute !=
nullptr)
553 segmentAttribute->setSegmentDescription(segmentLabelProp->
GetValueAsString());
554 segmentAttribute->setSegmentAlgorithmType(algorithmTypeProp->
GetValueAsString());
555 segmentAttribute->setSegmentAlgorithmName(
"MITK Segmentation");
556 if (segmentCategoryCodeValueProp !=
nullptr && segmentCategoryCodeSchemeProp !=
nullptr &&
557 segmentCategoryCodeMeaningProp !=
nullptr)
558 segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
564 segmentAttribute->setSegmentedPropertyCategoryCodeSequence(
565 "M-01000",
"SRT",
"Morphologically Altered Structure");
567 if (segmentTypeCodeValueProp !=
nullptr && segmentTypeCodeSchemeProp !=
nullptr &&
568 segmentTypeCodeMeaningProp !=
nullptr)
570 segmentAttribute->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->
GetValueAsString(),
573 handler.setBodyPartExamined(segmentTypeCodeMeaningProp->
GetValueAsString());
578 segmentAttribute->setSegmentedPropertyTypeCodeSequence(
"M-03000",
"SRT",
"Mass");
579 handler.setBodyPartExamined(
"Mass");
581 if (segmentModifierCodeValueProp !=
nullptr && segmentModifierCodeSchemeProp !=
nullptr &&
582 segmentModifierCodeMeaningProp !=
nullptr)
583 segmentAttribute->setSegmentedPropertyTypeModifierCodeSequence(
589 segmentAttribute->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255);
593 return handler.getJSONOutputAsString();
596 void mitk::DICOMSegmentationIO::SetLabelProperties(
mitk::Label *label, dcmqi::SegmentAttributes *segmentAttribute)
608 if (!segmentAttribute->getSegmentAlgorithmType().empty())
613 auto categoryCodeSequence = segmentAttribute->getSegmentedPropertyCategoryCodeSequence();
614 if (categoryCodeSequence !=
nullptr)
617 categoryCodeSequence->getCodeValue(codeValue);
623 categoryCodeSequence->getCodingSchemeDesignator(codeScheme);
628 OFString codeMeaning;
629 categoryCodeSequence->getCodeMeaning(codeMeaning);
636 auto typeCodeSequence = segmentAttribute->getSegmentedPropertyTypeCodeSequence();
637 if (typeCodeSequence !=
nullptr)
640 typeCodeSequence->getCodeValue(codeValue);
645 typeCodeSequence->getCodingSchemeDesignator(codeScheme);
650 OFString codeMeaning;
651 typeCodeSequence->getCodeMeaning(codeMeaning);
658 auto modifierCodeSequence = segmentAttribute->getSegmentedPropertyTypeModifierCodeSequence();
659 if (modifierCodeSequence !=
nullptr)
662 modifierCodeSequence->getCodeValue(codeValue);
668 modifierCodeSequence->getCodingSchemeDesignator(codeScheme);
673 OFString codeMeaning;
674 modifierCodeSequence->getCodeMeaning(codeMeaning);
681 auto atomicRegionSequence = segmentAttribute->getAnatomicRegionSequence();
682 if (atomicRegionSequence !=
nullptr)
685 atomicRegionSequence->getCodeValue(codeValue);
691 atomicRegionSequence->getCodingSchemeDesignator(codeScheme);
696 OFString codeMeaning;
697 atomicRegionSequence->getCodeMeaning(codeMeaning);
707 #endif //__mitkDICOMSegmentationIO__cpp MITKDICOMREADER_EXPORT FindingsListVectorType ExtractPathsOfInterest(const DICOMTagPathList &pathsOfInterest, const DICOMDatasetAccessingImageFrameList &frames)
LabelContainerConstIteratorType IteratorConstBegin() const
Returns a const iterator poiting to the begining of the container.
static MsgHandler handler
std::map< IdentifierType, ValueType > LookupTableType
Provides the custom mime types for dicom qi objects loaded with DCMQI.
void SetProperty(const std::string &propertyKey, BaseProperty *property, const std::string &contextName="", bool fallBackOnDefaultContext=false) override
Add new or change existent property.
LabelContainerConstIteratorType IteratorConstEnd() const
Returns a const iterator pointing to the end of the container.
static DICOMTagPath ANATOMIC_REGION_CODE_VALUE_PATH()
ConfidenceLevel GetReaderConfidenceLevel() const override
std::string GetFileName()
std::string MITKCORE_EXPORT GeneratePropertyNameForDICOMTag(unsigned int group, unsigned int element)
static DICOMTagPath SEGMENTED_PROPERTY_MODIFIER_SEQUENCE_PATH()
DataCollection - Class to facilitate loading/accessing structured data.
void SetValue(PixelType pixelValue)
A data structure describing a label.
static DICOMTagPath SEGMENT_LABEL_PATH()
static DICOMTagPath SEGMENT_MODIFIER_CODE_VALUE_PATH()
ConfidenceLevel GetWriterConfidenceLevel() const override
ConfidenceLevel GetReaderConfidenceLevel() const override
static DICOMTagPath SEGMENT_CATEGORY_CODE_SCHEME_PATH()
MITKDICOMREADER_EXPORT std::string DICOMTagPathToPropertyName(const DICOMTagPath &tagPath)
void SetRanking(int ranking)
Set the service ranking for this file writer.
std::string GetLocalFileName() const
Get a local file name for reading.
static DICOMTagPath SEGMENT_ALGORITHM_TYPE_PATH()
const LookupTableType & GetLookupTable() const
void SetColor(const mitk::Color &)
static DICOMTagPath ANATOMIC_REGION_SEQUENCE_PATH()
unsigned int GetDimension() const
Get dimension of the image.
ConfidenceLevel
A confidence level describing the confidence of the reader or writer in handling the given data...
Convenience class to temporarily change the current locale.
std::pair< us::ServiceRegistration< IFileReader >, us::ServiceRegistration< IFileWriter > > RegisterService(us::ModuleContext *context=us::GetModuleContext())
static DICOMTagPath SEGMENT_MODIFIER_CODE_MEANING_PATH()
static DICOMTagPath SEGMENT_CATEGORY_CODE_MEANING_PATH()
ValueType
Type of the value held by a Value object.
const BaseData * GetInput() const override
Get the input data set via SetInput().
static DICOMTagPath SEGMENTED_PROPERTY_TYPE_SEQUENCE_PATH()
const mitk::Color & GetColor() const
A local file representation for streams.
void ValidateOutputLocation() const
std::string GetValueAsString() const override
mitk::Image::Pointer image
static DICOMTagPath ANATOMIC_REGION_CODE_SCHEME_PATH()
static DICOMTagPath SEGMENT_SEQUENCE_PATH()
PixelType GetValue() const
itk::RGBPixel< float > Color
Color Standard RGB color typedef (float)
ValueType GetValue() const
std::vector< DICOMTagPath > DICOMTagPathList
static DICOMTagPath SEGMENT_CATEGORY_CODE_VALUE_PATH()
void SetActiveLayer(unsigned int layer)
MITKDICOMREADER_EXPORT void SetProperties(BaseDataPointer image, const FindingsListVectorType &findings)
void SetRanking(int ranking)
Set the service ranking for this file reader.
mitk::PropertyList::Pointer GetPropertyList() const
Get the data's property list.
mitk::BaseProperty::Pointer GetProperty(const char *propertyKey) const
Get the property (instance of BaseProperty) with key propertyKey from the PropertyList, and set it to this, respectively;.
void Write() override
Write the base data to the specified location or output stream.
std::vector< DICOMDatasetAccessingImageFrameInfo::Pointer > DICOMDatasetAccessingImageFrameList
void CastToMitkImage(const itk::SmartPointer< ItkOutputImageType > &itkimage, itk::SmartPointer< mitk::Image > &mitkoutputimage)
Cast an itk::Image (with a specific type) to an mitk::Image.
static DICOMTagPath SEGMENT_TYPE_CODE_VALUE_PATH()
LabelSetImage class for handling labels and layers in a segmentation session.
MITKDICOMREADER_EXPORT mitk::IDICOMTagsOfInterest * GetDicomTagsOfInterestService()
mitk::BaseProperty * GetProperty(const std::string &propertyKey) const
Get a property by its name.
static DICOMTagPath SEGMENT_NUMBER_PATH()
static DICOMTagPath SEGMENT_MODIFIER_CODE_SCHEME_PATH()
ConfidenceLevel GetWriterConfidenceLevel() const override
static DICOMTagPath SEGMENTED_PROPERTY_CATEGORY_SEQUENCE_PATH()
std::string GetInputLocation() const override
Get the current input location.
static DICOMTagPath ANATOMIC_REGION_CODE_MEANING_PATH()
Abstract class for implementing a reader and writer.
static DICOMTagPath SEGMENT_TYPE_CODE_SCHEME_PATH()
mitk::LabelSet * GetLabelSet(unsigned int layer=0)
Gets the mitk::LabelSet for the given layer.
std::vector< BaseData::Pointer > Read() override
Reads a number of DICOM segmentation from the file system.
void SetName(const std::string &name)
Property for time and space resolved string values.
std::string GetName() const
static DICOMTagPath SEGMENT_TYPE_CODE_MEANING_PATH()