diff --git a/CMake/FindDCMQI.cmake b/CMake/FindDCMQI.cmake index 809ffc01dd..1cc25ef6bb 100644 --- a/CMake/FindDCMQI.cmake +++ b/CMake/FindDCMQI.cmake @@ -1,48 +1,49 @@ set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}/src/DCMQI-build) find_path(DCMQI_INCLUDE_DIR NAMES DCMQI/DCMQI PATHS ${DCMQI_DIR}/../DCMQI ${MITK_EXTERNAL_PROJECT_PREFIX} ${CMAKE_PREFIX_PATH} PATH_SUFFIXES include include/dcmqi ) set(DCMQI_INCLUDE_DIR "${DCMQI_DIR}/include" "${MITK_EXTERNAL_PROJECT_PREFIX}/src/DCMQI/include" "${MITK_EXTERNAL_PROJECT_PREFIX}/src/DCMQI/jsoncpp" ${DCMQI_DIR}) -find_package_handle_standard_args(DCMQI - FOUND_VAR DCMQI_FOUND - REQUIRED_VARS DCMQI_INCLUDE_DIR -) # Find all libraries, store debug and release separately # Find Release libraries find_library(DCMQI_LIBRARY_RELEASE dcmqi PATHS ${DCMQI_DIR}/bin ${DCMQI_DIR}/bin/Release ${DCMQI_DIR}/bin/RelWithDebInfo NO_DEFAULT_PATH ) # Find Debug libraries find_library(DCMQI_LIBRARY_DEBUG dcmqi${DCMTK_CMAKE_DEBUG_POSTFIX} PATHS ${DCMQI_DIR}/bin ${DCMQI_DIR}/bin/Debug NO_DEFAULT_PATH ) mark_as_advanced(DCMQI_LIBRARY_RELEASE) mark_as_advanced(DCMQI_LIBRARY_DEBUG) # Add libraries to variable according to build type set(DCMQI_LIBRARIES) if(DCMQI_LIBRARY_RELEASE) list(APPEND DCMQI_LIBRARIES optimized ${DCMQI_LIBRARY_RELEASE}) endif() if(DCMQI_LIBRARY_DEBUG) list(APPEND DCMQI_LIBRARIES debug ${DCMQI_LIBRARY_DEBUG}) endif() + +find_package_handle_standard_args(DCMQI + FOUND_VAR DCMQI_FOUND + REQUIRED_VARS DCMQI_INCLUDE_DIR DCMQI_LIBRARIES +) diff --git a/CMakeExternals/DCMQI.cmake b/CMakeExternals/DCMQI.cmake index af564f9a98..e3ba3813bc 100644 --- a/CMakeExternals/DCMQI.cmake +++ b/CMakeExternals/DCMQI.cmake @@ -1,57 +1,59 @@ #----------------------------------------------------------------------------- # DCMQI #----------------------------------------------------------------------------- if(MITK_USE_DCMQI) # Sanity checks if(DEFINED DCMQI_DIR AND NOT EXISTS ${DCMQI_DIR}) message(FATAL_ERROR "DCMQI_DIR variable is defined but corresponds to non-existing directory") endif() set(proj DCMQI) set(proj_DEPENDENCIES DCMTK ITK) set(DCMQI_DEPENDS ${proj}) if(NOT DEFINED DCMQI_DIR) set(additional_cmake_args) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/dcmqi_3867f503.tar.gz URL_MD5 d535f2c74861a6fd96014c23b7fb6554 PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/DCMQI.patch UPDATE_COMMAND "" INSTALL_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} #-DCMAKE_INSTALL_PREFIX:PATH= - -DDCMQI_BUILD_APPS=OFF + -DBUILD_SHARED_LIBS:BOOL=ON + -DDCMQI_BUILD_APPS:BOOL=OFF -DDCMTK_DIR:PATH=${DCMTK_DIR} -DITK_DIR:PATH=${ITK_DIR} + -DITK_NO_IO_FACTORY_REGISTER_MANAGER:BOOL=ON -DDCMQI_SUPERBUILD:BOOL=OFF CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) ExternalProject_Get_Property(${proj} binary_dir) set(DCMQI_DIR ${binary_dir}) #set(${proj}_DIR ${ep_prefix}) #message(${proj}_DIR: ${${proj}_DIR}) #mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/Modules/DICOMReaderServices/CMakeLists.txt b/Modules/DICOMReaderServices/CMakeLists.txt index 218118c204..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 + PRIVATE ITK|ITKIOGDCM+ITKIOImageBase AUTOLOAD_WITH MitkCore ) diff --git a/Modules/Multilabel/autoload/IO/CMakeLists.txt b/Modules/Multilabel/autoload/IO/CMakeLists.txt index 8037339405..fdd65535f7 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 DCMQI DCMTK ITK|ITKQuadEdgeMesh+ITKAntiAlias+ITKIONRRD 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..d47d34865b --- /dev/null +++ b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.cpp @@ -0,0 +1,478 @@ +/*=================================================================== + +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 +#include + +namespace mitk +{ + DICOMSegmentationIO::DICOMSegmentationIO() + : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::DICOM_MIMETYPE(), "DICOM Segmentation") + { + AbstractFileWriter::SetRanking(10); + AbstractFileReader::SetRanking(10); + this->RegisterService(); + } + + IFileIO::ConfidenceLevel DICOMSegmentationIO::GetWriterConfidenceLevel() const + { + if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) + return Unsupported; + + const LabelSetImage *input = static_cast(this->GetInput()); + if (input) + return Supported; + else + return Unsupported; + } + + void DICOMSegmentationIO::Write() + { + ValidateOutputLocation(); + + mitk::LocaleSwitch localeSwitch("C"); + LocalFile localFile(this); + const std::string path = localFile.GetFileName(); + + auto input = dynamic_cast(this->GetInput()); + if (input == nullptr) + mitkThrow() << "Cannot write non-image data"; + + // Get DICOM information from referenced image + vector dcmDatasets; + DcmFileFormat *readFileFormat = new DcmFileFormat(); + try + { + // TODO: Generate dcmdataset witk DICOM tags from property list + mitk::StringLookupTableProperty::Pointer filesProp = + dynamic_cast(input->GetProperty("files").GetPointer()); + + if (filesProp.IsNull()) + { + MITK_ERROR << "No property with dicom file path."; + return; + } + + StringLookupTable filesLut = filesProp->GetValue(); + const StringLookupTable::LookupTableType &map = filesLut.GetLookupTable(); + + for (auto it = map.begin(); it != map.end(); ++it) + { + const char *fileName = (it->second).c_str(); + if (readFileFormat->loadFile(fileName, EXS_Unknown).good()) + dcmDatasets.push_back(readFileFormat->getAndRemoveDataset()); + } + } + catch (const std::exception &e) + { + mitkThrow() << e.what(); + } + + //Iterate over all layers. For each adcm file is generated + for (unsigned int layer = 0; layer < input->GetNumberOfLayers(); ++layer) + { + vector segmentations; + + 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(); + // BUG: It must be the layer image, but there are some errors with it (dcmqi: generate the dcmSeg "No frame data available") --> input->GetLayerImage(layer) + imageToItkFilter->SetInput(input); + imageToItkFilter->Update(); + + 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); + + 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); + } + catch (const std::exception &e) + { + mitkThrow() << e.what(); + } + } + + // end image write + if (readFileFormat) + delete readFileFormat; + for (int i = 0; i < dcmDatasets.size(); i++) + { + delete dcmDatasets[i]; + } + } + + 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(); + MITK_INFO << "Input " << metaInfo.getJSONOutputAsString(); + + 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->getSegmentedPropertyTypeCodeSequence() != nullptr) + segmentAttr->getSegmentedPropertyTypeCodeSequence()->getCodeMeaning(labelName); + else + { + labelName = std::to_string(segmentAttr->getLabelID()).c_str(); + if (labelName.empty()) + labelName = "Unnamed"; + } + + float tmp[3] = { 0.0, 0.0, 0.0 }; + if (segmentAttr->getRecommendedDisplayRGBValue() != nullptr) + { + tmp[0] = segmentAttr->getRecommendedDisplayRGBValue()[0] / 255.0; + tmp[1] = segmentAttr->getRecommendedDisplayRGBValue()[1] / 255.0; + tmp[2] = segmentAttr->getRecommendedDisplayRGBValue()[2] / 255.0; + } + + // if labelSetImage do not exists (first image) + if (labelSetImage.IsNull()) + { + // Initialize the labelSetImage with the read image + labelSetImage = LabelSetImage::New(); + labelSetImage->InitializeByLabeledImage(layerImage); + // Already a label 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("Session 1"); + handler.setClinicalTrialTimePointID("0"); + + std::string seriesDescription = ""; + image->GetPropertyList()->GetStringProperty("name", seriesDescription); + if (seriesDescription.empty()) + seriesDescription = "Segmentation"; + handler.setSeriesDescription(seriesDescription); + handler.setSeriesNumber("34" + std::to_string(layer)); // TODO:Create own series number + handler.setInstanceNumber("1"); + handler.setBodyPartExamined(""); + + const LabelSet *labelSet = image->GetLabelSet(layer); + + for (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())); + + int labelId = std::stoi(segmentNumberProp->GetValue()); + dcmqi::SegmentAttributes *segAttr = handler.createAndGetNewSegment(labelId); + if (segAttr != nullptr) + { + segAttr->setSegmentDescription(segmentLabelProp->GetValueAsString()); + segAttr->setSegmentAlgorithmType(algorithmTypeProp->GetValueAsString()); + segAttr->setSegmentAlgorithmName("MITK Segmentation"); + if (segmentCategoryCodeValueProp != nullptr && segmentCategoryCodeSchemeProp != nullptr && + segmentCategoryCodeMeaningProp != nullptr) + segAttr->setSegmentedPropertyCategoryCodeSequence(segmentCategoryCodeValueProp->GetValueAsString(), + segmentCategoryCodeSchemeProp->GetValueAsString(), + segmentCategoryCodeMeaningProp->GetValueAsString()); + if (segmentTypeCodeValueProp != nullptr && segmentTypeCodeSchemeProp != nullptr && + segmentTypeCodeMeaningProp != nullptr) + { + segAttr->setSegmentedPropertyTypeCodeSequence(segmentTypeCodeValueProp->GetValueAsString(), + segmentTypeCodeSchemeProp->GetValueAsString(), + segmentTypeCodeMeaningProp->GetValueAsString()); + handler.setBodyPartExamined(segmentTypeCodeMeaningProp->GetValueAsString()); + } + if (segmentModifierCodeValueProp != nullptr && segmentModifierCodeSchemeProp != nullptr && + segmentModifierCodeMeaningProp != nullptr) + segAttr->setSegmentedPropertyTypeModifierCodeSequence(segmentModifierCodeValueProp->GetValueAsString(), + segmentModifierCodeSchemeProp->GetValueAsString(), + segmentModifierCodeMeaningProp->GetValueAsString()); + + Color color = label->GetColor(); + segAttr->setRecommendedDisplayRGBValue(color[0] * 255, color[1] * 255, color[2] * 255); + } + } + } + return handler.getJSONOutputAsString(); + } + + DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); } +} // namespace + +#endif //__mitkLabelSetImageWriter__cpp diff --git a/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h new file mode 100644 index 0000000000..fc601957aa --- /dev/null +++ b/Modules/Multilabel/autoload/IO/mitkDICOMSegmentationIO.h @@ -0,0 +1,65 @@ +/*=================================================================== + +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 +#include "MitkMultilabelIOExports.h" + +namespace mitk +{ + /** + * Writes a LabelSetImage to a dcm file + * @ingroup Process + */ + class MITKMULTILABELIO_EXPORT 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)