diff --git a/Modules/DICOMReaderServices/CMakeLists.txt b/Modules/DICOMReaderServices/CMakeLists.txt index 2400f84511..ca742d6e75 100644 --- a/Modules/DICOMReaderServices/CMakeLists.txt +++ b/Modules/DICOMReaderServices/CMakeLists.txt @@ -1,6 +1,6 @@ MITK_CREATE_MODULE( DEPENDS MitkCore MitkDICOMReader PACKAGE_DEPENDS - PRIVATE ITK|ITKIOGDCM+ITKIOImageBase DCMQI DCMTK + PRIVATE ITK|ITKIOGDCM+ITKIOImageBase AUTOLOAD_WITH MitkCore ) diff --git a/Modules/DICOMReaderServices/files.cmake b/Modules/DICOMReaderServices/files.cmake index 070dd706c3..c8987299cc 100644 --- a/Modules/DICOMReaderServices/files.cmake +++ b/Modules/DICOMReaderServices/files.cmake @@ -1,12 +1,10 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkBaseDICOMReaderService.cpp mitkAutoSelectingDICOMReaderService.cpp mitkClassicDICOMSeriesReaderService.cpp mitkDICOMReaderServicesActivator.cpp mitkDICOMFilesHelper.cpp mitkDICOMTagsOfInterestService.cpp - mitkDICOMSegmentationWriterService.cpp - #mitkDICOMSegmentationReaderService.cpp ) diff --git a/Modules/DICOMReaderServices/include/mitkDICOMSegmentationReaderService.h b/Modules/DICOMReaderServices/include/mitkDICOMSegmentationReaderService.h deleted file mode 100644 index 4eccb60351..0000000000 --- a/Modules/DICOMReaderServices/include/mitkDICOMSegmentationReaderService.h +++ /dev/null @@ -1,52 +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 _MITK_DICOM_SEGMENTATION_READER_SERVICE__H_ -#define _MITK_DICOM_SEGMENTATION_READER_SERVICE__H_ - -// MITK -#include - -namespace mitk -{ -//TODO: Docu -/** - * @internal - * - * @brief - * - * @ingroup IO - */ -class DICOMSegmentationService: public AbstractFileReader -{ -public: - - DICOMSegmentationService(); - virtual ~DICOMSegmentationService(); - - using AbstractFileReader::Read; - virtual std::vector< itk::SmartPointer > Read() override; - -private: - - DICOMSegmentationService(const DICOMSegmentationService& other); - - virtual DICOMSegmentationService* Clone() const override; -}; - -} - -#endif diff --git a/Modules/DICOMReaderServices/include/mitkDICOMSegmentationWriterService.h b/Modules/DICOMReaderServices/include/mitkDICOMSegmentationWriterService.h deleted file mode 100644 index eaf38d5860..0000000000 --- a/Modules/DICOMReaderServices/include/mitkDICOMSegmentationWriterService.h +++ /dev/null @@ -1,55 +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 _MITK_DICOM_SEGMENTATION_WRITER_SERVICE__H_ -#define _MITK_DICOM_SEGMENTATION_WRITER_SERVICE__H_ - -#include - -namespace mitk -{ -//TODO: Docu -/** - * @internal - * - * @brief - * - * @ingroup IO - */ -class DICOMSegmentationWriterService : public AbstractFileWriter -{ -public: - - DICOMSegmentationWriterService(); - virtual ~DICOMSegmentationWriterService(); - - using AbstractFileWriter::Write; - virtual void Write() override; - - virtual ConfidenceLevel GetConfidenceLevel() const override; - -private: - - DICOMSegmentationWriterService(const DICOMSegmentationWriterService& other); - - virtual mitk::DICOMSegmentationWriterService* Clone() const override; - -}; - -} - -#endif diff --git a/Modules/DICOMReaderServices/src/mitkDICOMSegmentationReaderService.cpp b/Modules/DICOMReaderServices/src/mitkDICOMSegmentationReaderService.cpp deleted file mode 100644 index 495435b4b3..0000000000 --- a/Modules/DICOMReaderServices/src/mitkDICOMSegmentationReaderService.cpp +++ /dev/null @@ -1,118 +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. - -===================================================================*/ - -// MITK -#include "mitkDICOMSegmentationReaderService.h" -#include "mitkIOMimeTypes.h" - -// STL -#include -#include -#include - - -mitk::DICOMSegmentationReaderService::DICOMSegmentationReaderService() - : AbstractFileReader(CustomMimeType(IOMimeTypes::DICOM_MIMETYPE()), "DICOM Segmentation Reader") -{ - RegisterService(); -} - -mitk::DICOMSegmentationReaderService::~DICOMSegmentationReaderService() -{} - -std::vector< itk::SmartPointer > mitk::DICOMSegmentationReaderService::Read() -{ - //// Switch the current locale to "C" - //LocaleSwitch localeSwitch("C"); - - //std::vector< itk::SmartPointer > result; - - //InputStream stream(this); - - //TiXmlDocument doc; - //stream >> doc; - //if (!doc.Error()) - //{ - // TiXmlHandle docHandle( &doc ); - // //unsigned int pointSetCounter(0); - // for( TiXmlElement* currentPointSetElement = docHandle.FirstChildElement("point_set_file").FirstChildElement("point_set").ToElement(); - // currentPointSetElement != NULL; currentPointSetElement = currentPointSetElement->NextSiblingElement()) - // { - // mitk::PointSet::Pointer newPointSet = mitk::PointSet::New(); - - // // time geometry assembled for addition after all points - // // else the SetPoint method would already transform the points that we provide it - // mitk::ProportionalTimeGeometry::Pointer timeGeometry = mitk::ProportionalTimeGeometry::New(); - - // if(currentPointSetElement->FirstChildElement("time_series") != NULL) - // { - // for( TiXmlElement* currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); - // currentTimeSeries != NULL; currentTimeSeries = currentTimeSeries->NextSiblingElement()) - // { - // unsigned int currentTimeStep(0); - // TiXmlElement* currentTimeSeriesID = currentTimeSeries->FirstChildElement("time_series_id"); - - // currentTimeStep = atoi(currentTimeSeriesID->GetText()); - - // timeGeometry->Expand( currentTimeStep + 1 ); // expand (default to identity) in any case - // TiXmlElement* geometryElem = currentTimeSeries->FirstChildElement("Geometry3D"); - // if ( geometryElem ) - // { - // Geometry3D::Pointer geometry = Geometry3DToXML::FromXML(geometryElem); - // if (geometry.IsNotNull()) - // { - // timeGeometry->SetTimeStepGeometry(geometry,currentTimeStep); - // } - // else - // { - // MITK_ERROR << "Could not deserialize Geometry3D element."; - // } - // } - // else - // { - // MITK_WARN << "Fallback to legacy behavior: defining PointSet geometry as identity"; - // } - - // newPointSet = this->ReadPoints(newPointSet, currentTimeSeries, currentTimeStep); - // } - // } - // else - // { - // newPointSet = this->ReadPoints(newPointSet, currentPointSetElement, 0); - // } - - // newPointSet->SetTimeGeometry(timeGeometry); - - // result.push_back( newPointSet.GetPointer() ); - // } - //} - //else - //{ - // mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); - //} - - //return result; -} - -mitk::DICOMSegmentationReaderService::DICOMSegmentationReaderService(const mitk::DICOMSegmentationReaderService& other) - : mitk::AbstractFileReader(other) -{ -} - -mitk::DICOMSegmentationReaderService* mitk::DICOMSegmentationReaderService::Clone() const -{ - return new mitk::DICOMSegmentationReaderService(*this); -} diff --git a/Modules/DICOMReaderServices/src/mitkDICOMSegmentationWriterService.cpp b/Modules/DICOMReaderServices/src/mitkDICOMSegmentationWriterService.cpp deleted file mode 100644 index cad55d15ef..0000000000 --- a/Modules/DICOMReaderServices/src/mitkDICOMSegmentationWriterService.cpp +++ /dev/null @@ -1,122 +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 "mitkDICOMSegmentationWriterService.h" -#include "mitkIOMimeTypes.h" -#include "mitkLocaleSwitch.h" -#include "mitkImage.h" -#include "mitkImageToItk.h" -#include "ImageSEGConverter.h" - -#include - - -mitk::DICOMSegmentationWriterService::DICOMSegmentationWriterService() - : AbstractFileWriter(mitk::Image::GetStaticNameOfClass(), CustomMimeType(IOMimeTypes::DICOM_MIMETYPE()), "DICOM Segmentation Writer") -{ - RegisterService(); -} - -mitk::DICOMSegmentationWriterService::DICOMSegmentationWriterService(const mitk::DICOMSegmentationWriterService& other) - : AbstractFileWriter(other) -{ -} - -mitk::DICOMSegmentationWriterService::~DICOMSegmentationWriterService() -{ -} - -void mitk::DICOMSegmentationWriterService::Write() -{ - typedef itk::Image ImageType; - vector segmentations; - - // Switch the current locale to "C" - LocaleSwitch localeSwitch("C"); - - LocalFile localFile(this); - const std::string path = localFile.GetFileName(); - - //1. Handle segmentation as image - const mitk::Image* image = dynamic_cast(this->GetInput()); - - if (image == NULL) - { - mitkThrow() << "Cannot write non-image data"; - } - - - ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); - try - { - imageToItkFilter->SetInput(image); - } - catch (const itk::ExceptionObject &e) - { - // Most probably the input image type is wrong. Binary images are expected to be - // >unsigned< char images. - MITK_ERROR << e.GetDescription() << endl; - return; - } - - imageToItkFilter->Update(); - ImageType::Pointer itkImage = imageToItkFilter->GetOutput(); - - segmentations.push_back(itkImage); - - //TODO: 2. LabelSetImage - try - { - //TODO: Fill dcmDatasets with information - vector dcmDatasets; - //TODO: Fill meta data with information - const std::string &tmpMetaInfoFile = ""; - - MITK_INFO << "Writing image: " << path << std::endl; - - //Convert itk image to dicom image - dcmqi::ImageSEGConverter* converter = new dcmqi::ImageSEGConverter(); - DcmDataset* result = converter->itkimage2dcmSegmentation(dcmDatasets, segmentations, tmpMetaInfoFile); - - //write dicom file - DcmFileFormat dcmFileFormat(result); - //TODO: Check if path contains filename with ending .dcm - dcmFileFormat.saveFile(path.c_str(), EXS_LittleEndianExplicit); - } - catch (const std::exception& e) - { - mitkThrow() << e.what(); - } - -} - -mitk::DICOMSegmentationWriterService*mitk::DICOMSegmentationWriterService::Clone() const -{ - return new DICOMSegmentationWriterService(*this); -} - -mitk::IFileWriter::ConfidenceLevel mitk::DICOMSegmentationWriterService::GetConfidenceLevel() const -{//TODO check if segmentation with dicom infos - mitk::Image::ConstPointer input = dynamic_cast(this->GetInput()); - if (input.IsNull() /*|| !mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(input)*/) - { - return Unsupported; - } - else - { - return Supported; - } -} \ No newline at end of file diff --git a/Modules/Multilabel/autoload/IO/CMakeLists.txt b/Modules/Multilabel/autoload/IO/CMakeLists.txt index 8037339405..e441ab484e 100644 --- a/Modules/Multilabel/autoload/IO/CMakeLists.txt +++ b/Modules/Multilabel/autoload/IO/CMakeLists.txt @@ -1,9 +1,9 @@ MITK_CREATE_MODULE( MultilabelIO INCLUDE_DIRS PRIVATE src/IO - DEPENDS PUBLIC MitkMultilabel MitkSceneSerialization + DEPENDS PUBLIC MitkMultilabel MitkSceneSerialization MitkDICOMReader PACKAGE_DEPENDS - PRIVATE ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD + PRIVATE ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD+ITKImageProcessing DCMTK DCMQI AUTOLOAD_WITH MitkCore WARNINGS_AS_ERRORS ) \ No newline at end of file diff --git a/Modules/Multilabel/autoload/IO/files.cmake b/Modules/Multilabel/autoload/IO/files.cmake index a5079ce423..2040a89216 100644 --- a/Modules/Multilabel/autoload/IO/files.cmake +++ b/Modules/Multilabel/autoload/IO/files.cmake @@ -1,8 +1,10 @@ set(CPP_FILES + mitkDICOMSegmentationIO.cpp + mitkDICOMSegmentationIO.h mitkLabelSetImageIO.cpp mitkLabelSetImageIO.h mitkLabelSetImageSerializer.cpp mitkLabelSetImageSerializer.h mitkMultilabelActivator.cpp ) diff --git a/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp new file mode 100644 index 0000000000..c2ab097f84 --- /dev/null +++ b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp @@ -0,0 +1,461 @@ +/*=================================================================== + +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 __mitkDICOMSegmentationIOWriter__cpp +#define __mitkDICOMSegmentationIOWriter__cpp + +#include "mitkDICOMSegmentationIO.h" +#include "mitkBasePropertySerializer.h" +#include "mitkDICOMProperty.h" +#include "mitkIOMimeTypes.h" +#include "mitkImageAccessByItk.h" +#include "mitkImageCast.h" +#include "mitkLabelSetIOHelper.h" +#include "mitkLabelSetImageConverter.h" +#include "mitkProperties.h" +#include "mitkPropertyNameHelper.h" +#include "mitkStringProperty.h" +#include + +// itk +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkMetaDataDictionary.h" +#include "itkMetaDataObject.h" +#include "itkNrrdImageIO.h" +#include "itkThresholdImageFilter.h" + +// dcmqi +#include "ImageSEGConverter.h" +#include "JSONSegmentationMetaInformationHandler.h" + +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; + try + { + // TODO: Generate dcmdataset witk DICOM tags from property list + DcmFileFormat readFileFormat; + mitk::StringLookupTableProperty::Pointer files = + dynamic_cast(input->GetProperty("files").GetPointer()); + + if (files.IsNull()) + { + MITK_ERROR << "No property with dicom file path."; + return; + } + + for (int i = 0; i < (int)files->GetValue().GetLookupTable().size(); ++i) + { + const char *fileName = files->GetValue().GetTableValue(i).c_str(); + readFileFormat.loadFile(fileName); + DcmDataset *dataSet = readFileFormat.getDataset(); + if (dataSet != nullptr) + dcmDatasets.push_back(dataSet); + } + } + catch (const std::exception &e) + { + mitkThrow() << e.what(); + } + + // + vector segmentations; + for (unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer) + { + try + { + const LabelSet *labelSet = input->GetLabelSet(layer); + + for (int label = 1; label < input->GetNumberOfLabels(layer); ++label) + { + typedef itk::CastImageFilter castItkImageFilterType; + ImageToItk::Pointer imageToItkFilter = ImageToItk::New(); + + imageToItkFilter->SetInput(input); + imageToItkFilter->Update(); + + castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New(); + castFilter->SetInput(imageToItkFilter->GetOutput()); + castFilter->Update(); + itkInternalImageType::Pointer itkLabelImage = castFilter->GetOutput(); + + itk::ThresholdImageFilter::Pointer thresholdFilter = + itk::ThresholdImageFilter::New(); + + thresholdFilter->SetInput(itkLabelImage); + thresholdFilter->ThresholdOutside(label, label); + 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 image to dicom image + dcmqi::ImageSEGConverter *converter = new dcmqi::ImageSEGConverter(); + DcmDataset *result = converter->itkimage2dcmSegmentation(dcmDatasets, segmentations, tmpMetaInfoFile); + // Todo for each layer + // write dicom file + DcmFileFormat dcmFileFormat(result); + // TODO: Check if path contains filename with ending .dcm + dcmFileFormat.saveFile(path.c_str(), EXS_LittleEndianExplicit); + } + catch (const std::exception &e) + { + mitkThrow() << e.what(); + } + } + // end image write + } + + 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; + const std::string path = this->GetLocalFileName(); + + MITK_INFO << "loading " << path << std::endl; + + // Check to see if we can read the file given the name or prefix + if (path.empty()) + { + mitkThrow() << "Empty filename in mitk::ItkImageIO "; + } + + try + { + DcmFileFormat dcmFileFormat; + OFCondition status = dcmFileFormat.loadFile(path.c_str()); + if (status.bad()) + MITK_ERROR << "Can't read the input file!"; + + DcmDataset *dataSet = dcmFileFormat.getDataset(); + if (dataSet == nullptr) + MITK_ERROR << "Can't read data from input file!"; + + dcmqi::ImageSEGConverter *converter = new dcmqi::ImageSEGConverter(); + pair, string> dcmqiOutput = converter->dcmSegmentation2itkimage(dataSet); + + dcmqi::JSONSegmentationMetaInformationHandler metaInfo(dcmqiOutput.second.c_str()); + metaInfo.read(); + + map segItkImages = dcmqiOutput.first; + + vector>::const_iterator segmentIter = + metaInfo.segmentsAttributesMappingList.begin(); + 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; + + 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 the label information from segment attributes + map segmentMap = (*segmentIter); + map::const_iterator segmentMapIter = (*segmentIter).begin(); + dcmqi::SegmentAttributes *segmentAttr = (*segmentMapIter).second; + + OFString labelName; + + if (segmentAttr->getSegmentedPropertyType() != nullptr) + segmentAttr->getSegmentedPropertyType()->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 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; + } + } + catch (const std::exception &e) + { + mitkThrow() << e.what(); + } + + if (labelSetImage->GetNumberOfLayers() > 1 && labelSetImage->GetActiveLayer() != 0) + labelSetImage->SetActiveLayer(0); + + std::vector 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; + handler.setContentCreatorName("MITK"); + handler.setClinicalTrialSeriesID(""); + handler.setClinicalTrialTimePointID("1"); + + std::string seriesDescription = ""; + image->GetPropertyList()->GetStringProperty("name", seriesDescription); + if (seriesDescription.empty()) + seriesDescription = "Segmentation"; + handler.setSeriesDescription(seriesDescription); + handler.setSeriesNumber(""); + handler.setInstanceNumber("1"); + handler.setBodyPartExamined(""); + + + const LabelSet *labelSet = image->GetLabelSet(layer); + vector> segAttrMappingList = handler.segmentsAttributesMappingList; + map labelID2SegmentAttributes; + + for (int i = 1; i < image->GetNumberOfLabels(); ++i) + { + const Label *label = labelSet->GetLabel(i); + 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())); + + dcmqi::SegmentAttributes *segAttr = handler.createAndGetNewSegment((int) segmentNumberProp->GetValue()); + segAttr->setSegmentDescription(segmentLabelProp->GetValueAsString()); + segAttr->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString()); + segAttr->setSegmentAlgorithmName(""); + if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr && segmentCategoryCodeMeaningProp!= nullptr) + segAttr->setSegmentedPropertyCategoryCode(segmentCategoryCodeValueProp->GetValueAsString(), + segmentCategoryCodeSchemeProp->GetValueAsString(), + segmentCategoryCodeMeaningProp->GetValueAsString()); + if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr && segmentTypeCodeMeaningProp != nullptr) + segAttr->setSegmentedPropertyType(segmentTypeCodeValueProp->GetValueAsString(), + segmentTypeCodeSchemeProp->GetValueAsString(), + segmentTypeCodeMeaningProp->GetValueAsString()); + if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr && segmentModifierCodeMeaningProp != nullptr) + segAttr->setSegmentedPropertyTypeModifier(segmentModifierCodeValueProp->GetValueAsString(), + segmentModifierCodeSchemeProp->GetValueAsString(), + segmentModifierCodeMeaningProp->GetValueAsString()); + segAttr->setAnatomicRegion(CodeSequenceMacro()); + segAttr->setAnatomicRegionModifier(CodeSequenceMacro()); + Color color = label->GetColor(); + segAttr->setRecommendedDisplayRGBValue(color[0]*255, color[1]*255, color[2]*255); + labelID2SegmentAttributes[(int) segmentNumberProp->GetValue()] = segAttr; + segAttrMappingList.push_back(labelID2SegmentAttributes); + } + } + + handler.segmentsAttributesMappingList = segAttrMappingList; + + return handler.getJSONOutputAsString(); + } + + DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); } +} // namespace + +#endif //__mitkLabelSetImageWriter__cpp diff --git a/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h new file mode 100644 index 0000000000..9cc7fb6726 --- /dev/null +++ b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h @@ -0,0 +1,64 @@ +/*=================================================================== + +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_h +#define __mitkDICOMSegmentationIO_h + +#include +#include + +namespace mitk +{ + /** + * Writes a LabelSetImage to a dcm file + * @ingroup Process + */ + class DICOMSegmentationIO : public mitk::AbstractFileIO + { + public: + typedef mitk::LabelSetImage InputType; + typedef itk::Image itkInputImageType; + typedef itk::Image itkInternalImageType; + + DICOMSegmentationIO(); + + // -------------- AbstractFileReader ------------- + + using AbstractFileReader::Read; + /** + * @brief Reads a number of DICOM segmentation from the file system + * @return a vector of mitk::LabelSetImages + * @throws throws an mitk::Exception if an error ocurrs + */ + virtual std::vector Read() override; + virtual ConfidenceLevel GetReaderConfidenceLevel() const override; + + // -------------- AbstractFileWriter ------------- + + virtual void Write() override; + virtual ConfidenceLevel GetWriterConfidenceLevel() const override; + + // -------------- DICOMSegmentationIO specific functions ------------- + + const std::string CreateMetaDataJsonFile(int layer); + //const std::map GetImagesFromLayer(Image::Pointer layerImage); + + private: + DICOMSegmentationIO *IOClone() const override; + }; +} // end of namespace mitk + +#endif // __mitkDICOMSegmentationIO_h diff --git a/Modules/Multilabel/autoload/IO/mitkMultilabelActivator.cpp b/Modules/Multilabel/autoload/IO/mitkMultilabelActivator.cpp index 5aa50d7259..3f9491c746 100644 --- a/Modules/Multilabel/autoload/IO/mitkMultilabelActivator.cpp +++ b/Modules/Multilabel/autoload/IO/mitkMultilabelActivator.cpp @@ -1,45 +1,50 @@ /*=================================================================== 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 #include #include #include +#include "mitkDICOMSegmentationIO.h" #include "mitkLabelSetImageIO.h" namespace mitk { /** \brief Registers services for multilabel module. */ class MultilabelModuleActivator : public us::ModuleActivator { std::vector m_FileIOs; public: - void Load(us::ModuleContext * /*context*/) override { m_FileIOs.push_back(new LabelSetImageIO()); } + void Load(us::ModuleContext * /*context*/) override + { + m_FileIOs.push_back(new LabelSetImageIO()); + m_FileIOs.push_back(new DICOMSegmentationIO()); + } void Unload(us::ModuleContext *) override { for (auto &elem : m_FileIOs) { delete elem; } } }; } US_EXPORT_MODULE_ACTIVATOR(mitk::MultilabelModuleActivator)