diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp index 0fd2a438da..1bfdb684f6 100644 --- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.cpp @@ -1,91 +1,91 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkExampleDataStructureReaderService.h" // mitk includes #include "mitkExampleIOMimeTypes.h" #include "mitkGeometry3D.h" #include // itk includes #include "itksys/SystemTools.hxx" namespace mitk { ExampleDataStructureReaderService::ExampleDataStructureReaderService(const ExampleDataStructureReaderService &other) : mitk::AbstractFileReader(other) { } ExampleDataStructureReaderService::ExampleDataStructureReaderService() : mitk::AbstractFileReader(CustomMimeType(mitk::ExampleIOMimeTypes::EXAMPLE_MIMETYPE()), "Default reader for the example data structure") { m_ServiceReg = this->RegisterService(); } ExampleDataStructureReaderService::~ExampleDataStructureReaderService() {} - std::vector> ExampleDataStructureReaderService::Read() + std::vector> ExampleDataStructureReaderService::DoRead() { std::vector> result; std::string location = GetInputLocation(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(location); ext = itksys::SystemTools::LowerCase(ext); if (location == "") { MITK_ERROR << "No file name specified."; } try { std::ifstream file(location); std::string content(""); std::string line(""); if (file.is_open()) { while (getline(file, line)) { content += line; content += "\n"; } } else { mitkThrow() << "Could not open file " << this->GetInputLocation() << " for reading."; } mitk::ExampleDataStructure::Pointer outputData = mitk::ExampleDataStructure::New(); outputData->SetData(content); result.push_back(outputData.GetPointer()); MITK_INFO << "Example file read"; } catch (const mitk::Exception& e) { MITK_ERROR << e.GetDescription(); } catch (...) { MITK_ERROR << "Unknown error occurred while trying to read file."; } return result; } } // namespace MITK mitk::ExampleDataStructureReaderService *mitk::ExampleDataStructureReaderService::Clone() const { return new ExampleDataStructureReaderService(*this); } diff --git a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h index 4f1384ed8e..bdc2ab20e8 100644 --- a/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h +++ b/Examples/FirstSteps/NewModule/autoload/IO/mitkExampleDataStructureReaderService.h @@ -1,47 +1,49 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkExampleDataStructureReaderService_h #define __mitkExampleDataStructureReaderService_h #include "mitkCommon.h" #include "mitkExampleDataStructure.h" #include #include #include namespace mitk { /** \brief The reader service for the MITK example data type */ class ExampleDataStructureReaderService : public mitk::AbstractFileReader { public: typedef mitk::ExampleDataStructure OutputType; ExampleDataStructureReaderService(const ExampleDataStructureReaderService &other); ExampleDataStructureReaderService(); ~ExampleDataStructureReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; + + protected: + std::vector> DoRead() override; private: ExampleDataStructureReaderService *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } // namespace MITK #endif // __mitkExampleDataStructureReaderService_h diff --git a/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h b/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h index b840cf141d..f118964448 100644 --- a/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h +++ b/Modules/Classification/CLVigraRandomForest/include/mitkDummyLsetReader.h @@ -1,45 +1,48 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_DummyLsetFileReader__H_ #define _MITK_DummyLsetFileReader__H_ #include namespace mitk { /** * Read deprecated *.lset format (Multilabel Image format 2014) * @ingroup Process */ class DummyLsetFileReader : public mitk::AbstractFileReader { public: DummyLsetFileReader(); DummyLsetFileReader(const mitk::DummyLsetFileReader& other); ~DummyLsetFileReader() override; using AbstractFileReader::Read; - std::vector > Read() override; + +protected: + std::vector> DoRead() override; + private: DummyLsetFileReader * Clone() const override; }; } // end of namespace mitk #endif diff --git a/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h b/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h index 1bcb652b7f..456837251c 100644 --- a/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h +++ b/Modules/Classification/CLVigraRandomForest/include/mitkRandomForestIO.h @@ -1,61 +1,62 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_DecisionForestFileIO__H_ #define _MITK_DecisionForestFileIO__H_ #include #include "vigra/random_forest.hxx" namespace mitk { /** * Writes vigra based mitk::DecisionForest * @ingroup Process */ class RandomForestFileIO : public mitk::AbstractFileIO { public: RandomForestFileIO(); RandomForestFileIO(const mitk::RandomForestFileIO& other); ~RandomForestFileIO() override; using AbstractFileIO::Write; void Write() override; using AbstractFileIO::Read; - std::vector > Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; ConfidenceLevel GetWriterConfidenceLevel() const override; - protected: +protected: + std::vector> DoRead() override; + mutable vigra::RandomForest m_rf; // DecisionForestFileIO(const DecisionForestFileIO& other); // virtual mitk::DecisionForestFileIO* Clone() const; private: AbstractFileIO* IOClone() const override; }; } // end of namespace mitk #endif diff --git a/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp b/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp index a4e6256ba0..a1ae48a41a 100644 --- a/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp +++ b/Modules/Classification/CLVigraRandomForest/src/IO/mitkDummyLsetReader.cpp @@ -1,66 +1,66 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include typedef itk::Image ImageType; -std::vector > mitk::DummyLsetFileReader::Read() +std::vector > mitk::DummyLsetFileReader::DoRead() { std::vector > result; typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetFileName(this->GetInputLocation()); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); reader->SetImageIO(io); reader->Update(); mitk::Image::Pointer img; mitk::CastToMitkImage(reader->GetOutput(),img); result.push_back(img.GetPointer()); return result; } mitk::DummyLsetFileReader::DummyLsetFileReader(const DummyLsetFileReader & other) : AbstractFileReader(other) { } mitk::DummyLsetFileReader* mitk::DummyLsetFileReader::Clone() const { return new DummyLsetFileReader(*this); } mitk::DummyLsetFileReader::~DummyLsetFileReader() {} mitk::DummyLsetFileReader::DummyLsetFileReader() { CustomMimeType mimeType(this->GetMimeTypePrefix() + "lset"); mimeType.AddExtension("lset"); mimeType.SetCategory("Images"); mimeType.SetComment("Experimental MBI LabelSetImage"); this->SetMimeType(mimeType); this->SetDescription("MBI LabelSetImage"); this->RegisterService(); } diff --git a/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp b/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp index 4dedf92d42..79a0e270fb 100644 --- a/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp +++ b/Modules/Classification/CLVigraRandomForest/src/IO/mitkRandomForestIO.cpp @@ -1,218 +1,218 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkDecisionForestIO__cpp #define __mitkDecisionForestIO__cpp #include "mitkRandomForestIO.h" #include "itksys/SystemTools.hxx" //#include "mitkHDF5IOMimeTypes.h" #include "vigra/random_forest_hdf5_impex.hxx" #include #include #include "mitkVigraRandomForestClassifier.h" #include "mitkIOMimeTypes.h" #define GetAttribute(name,type)\ type name;\ hdf5_file.readAttribute(".",name,name); mitk::RandomForestFileIO::ConfidenceLevel mitk::RandomForestFileIO::GetReaderConfidenceLevel() const { std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetLocalFileName().c_str()); bool is_loaded = vigra::rf_import_HDF5(m_rf, this->GetInputLocation()); return ext == ".forest" && is_loaded == true? IFileReader::Supported : IFileReader::Unsupported; } mitk::RandomForestFileIO::ConfidenceLevel mitk::RandomForestFileIO::GetWriterConfidenceLevel() const { mitk::VigraRandomForestClassifier::ConstPointer input = dynamic_cast(this->GetInput()); if (input.IsNull()) { return IFileWriter::Unsupported; }else{ return IFileWriter::Supported; } } mitk::RandomForestFileIO::RandomForestFileIO() : AbstractFileIO(mitk::VigraRandomForestClassifier::GetStaticNameOfClass()) { CustomMimeType customReaderMimeType(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest"); std::string category = "Vigra Random Forest File"; customReaderMimeType.SetComment("Vigra Random Forest"); customReaderMimeType.SetCategory(category); customReaderMimeType.AddExtension("forest"); // this->AbstractFileIOWriter::SetRanking(100); this->AbstractFileWriter::SetMimeTypePrefix(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest"); this->AbstractFileWriter::SetMimeType(customReaderMimeType); this->SetWriterDescription("Vigra Random Forest"); this->AbstractFileReader::SetMimeTypePrefix(mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".forest"); this->AbstractFileReader::SetMimeType(customReaderMimeType); this->SetReaderDescription("Vigra Random Forest"); // this->SetReaderDescription(mitk::DecisionForestIOMimeTypes::DECISIONFOREST_MIMETYPE_DESCRIPTION()); // this->SetWriterDescription(mitk::DecisionForestIOMimeTypes::DECISIONFOREST_MIMETYPE_DESCRIPTION()); this->RegisterService(); } mitk::RandomForestFileIO::RandomForestFileIO(const mitk::RandomForestFileIO& other) : AbstractFileIO(other) { } mitk::RandomForestFileIO::~RandomForestFileIO() {} std::vector > mitk::RandomForestFileIO:: -Read() +DoRead() { mitk::VigraRandomForestClassifier::Pointer output = mitk::VigraRandomForestClassifier::New(); std::vector > result; if ( this->GetInputLocation().empty()) { MITK_ERROR << "Sorry, filename has not been set!"; return result; } else { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } output->SetRandomForest(m_rf); result.push_back(output.GetPointer()); vigra::HDF5File hdf5_file(this->GetInputLocation() , vigra::HDF5File::Open); hdf5_file.cd_mk("/_mitkOptions"); // --------------------------------------------------------- // Read tree weights if(hdf5_file.existsDataset("treeWeights")) { auto treeWeight = output->GetTreeWeights(); treeWeight.resize(m_rf.tree_count(),1); vigra::MultiArrayView<2, double> W(vigra::Shape2(treeWeight.rows(),treeWeight.cols()),treeWeight.data()); hdf5_file.read("treeWeights",W); output->SetTreeWeights(treeWeight); } // --------------------------------------------------------- // --------------------------------------------------------- // Read itemList if(hdf5_file.existsDataset("itemList")){ std::string items_string; hdf5_file.read("itemList",items_string); auto itemlist = output->GetItemList(); std::string current_item = ""; for(auto character : items_string) { if(character == ';'){ // skip seperator and push back item itemlist.push_back(current_item); current_item.clear(); }else{ current_item = current_item + character; } } output->SetItemList(itemlist); } // --------------------------------------------------------- hdf5_file.close(); return result; } } void mitk::RandomForestFileIO::Write() { mitk::BaseData::ConstPointer input = this->GetInput(); if (input.IsNull()) { MITK_ERROR <<"Sorry, input to NrrdDiffusionImageWriter is nullptr!"; return; } if ( this->GetOutputLocation().empty() ) { MITK_ERROR << "Sorry, filename has not been set!"; return ; }else{ const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } mitk::VigraRandomForestClassifier::ConstPointer mitkDC = dynamic_cast(input.GetPointer()); //mitkDC->GetRandomForest() vigra::rf_export_HDF5(mitkDC->GetRandomForest(), this->GetOutputLocation()); vigra::HDF5File hdf5_file(this->GetOutputLocation() , vigra::HDF5File::Open); hdf5_file.cd_mk("/_mitkOptions"); // Write tree weights // --------------------------------------------------------- auto treeWeight = mitkDC->GetTreeWeights(); vigra::MultiArrayView<2, double> W(vigra::Shape2(treeWeight.rows(),treeWeight.cols()),treeWeight.data()); hdf5_file.write("treeWeights",W); // --------------------------------------------------------- // Write itemList // --------------------------------------------------------- auto items = mitkDC->GetItemList(); std::string item_stringlist; for(auto entry : items) item_stringlist = item_stringlist + entry + ";"; hdf5_file.write("itemList",item_stringlist); // --------------------------------------------------------- hdf5_file.close(); } } mitk::AbstractFileIO* mitk::RandomForestFileIO::IOClone() const { return new RandomForestFileIO(*this); } #endif diff --git a/Modules/ContourModel/IO/mitkContourModelReader.cpp b/Modules/ContourModel/IO/mitkContourModelReader.cpp index a7864602f2..fa0ead2c5f 100644 --- a/Modules/ContourModel/IO/mitkContourModelReader.cpp +++ b/Modules/ContourModel/IO/mitkContourModelReader.cpp @@ -1,157 +1,157 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelReader.h" #include #include #include #include mitk::ContourModelReader::ContourModelReader(const mitk::ContourModelReader &other) : mitk::AbstractFileReader(other) { } mitk::ContourModelReader::ContourModelReader() : AbstractFileReader() { std::string category = "Contour File"; mitk::CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("cnt"); this->SetDescription(category); this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::ContourModelReader::~ContourModelReader() { } -std::vector> mitk::ContourModelReader::Read() +std::vector> mitk::ContourModelReader::DoRead() { std::vector> result; std::string location = GetInputLocation(); // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); try { TiXmlDocument doc(location.c_str()); bool loadOkay = doc.LoadFile(); if (loadOkay) { TiXmlHandle docHandle(&doc); /*++++ handle n contourModels within data tags ++++*/ for (TiXmlElement *currentContourElement = docHandle.FirstChildElement("contourModel").ToElement(); currentContourElement != nullptr; currentContourElement = currentContourElement->NextSiblingElement()) { mitk::ContourModel::Pointer newContourModel = mitk::ContourModel::New(); if (currentContourElement->FirstChildElement("data")->FirstChildElement("timestep") != nullptr) { // handle geometry information // TiXmlElement* currentGeometryInfo = // currentContourElement->FirstChildElement("head")->FirstChildElement("geometryInformation")->ToElement(); ///////////// NOT SUPPORTED YET //////////////// /*++++ handle n timesteps within timestep tags ++++*/ for (TiXmlElement *currentTimeSeries = currentContourElement->FirstChildElement("data")->FirstChildElement("timestep")->ToElement(); currentTimeSeries != nullptr; currentTimeSeries = currentTimeSeries->NextSiblingElement()) { unsigned int currentTimeStep(0); currentTimeStep = atoi(currentTimeSeries->Attribute("n")); this->ReadPoints(newContourModel, currentTimeSeries, currentTimeStep); int isClosed; currentTimeSeries->QueryIntAttribute("isClosed", &isClosed); if (isClosed) { newContourModel->Close(currentTimeStep); } } /*++++ END handle n timesteps within timestep tags ++++*/ } else { // this should not happen MITK_WARN << "wrong file format!"; // newContourModel = this->ReadPoint(newContourModel, currentContourElement, 0); } newContourModel->UpdateOutputInformation(); result.push_back(dynamic_cast(newContourModel.GetPointer())); } /*++++ END handle n contourModels within data tags ++++*/ } else { MITK_WARN << "XML parser error!"; } } catch (...) { MITK_ERROR << "Cannot read contourModel."; } return result; } mitk::ContourModelReader *mitk::ContourModelReader::Clone() const { return new ContourModelReader(*this); } void mitk::ContourModelReader::ReadPoints(mitk::ContourModel::Pointer newContourModel, TiXmlElement *currentTimeSeries, unsigned int currentTimeStep) { // check if the timesteps in contourModel have to be expanded if (currentTimeStep != newContourModel->GetTimeSteps()) { newContourModel->Expand(currentTimeStep + 1); } // read all points within controlPoints tag if (currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point") != nullptr) { for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("controlPoints")->FirstChildElement("point")->ToElement(); currentPoint != nullptr; currentPoint = currentPoint->NextSiblingElement()) { double x(0.0); double y(0.0); double z(0.0); x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); int isActivePoint; currentPoint->QueryIntAttribute("isActive", &isActivePoint); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newContourModel->AddVertex(point, isActivePoint, currentTimeStep); } } else { // nothing to read } } diff --git a/Modules/ContourModel/IO/mitkContourModelReader.h b/Modules/ContourModel/IO/mitkContourModelReader.h index d84bfdc3aa..bbeae0a7ec 100644 --- a/Modules/ContourModel/IO/mitkContourModelReader.h +++ b/Modules/ContourModel/IO/mitkContourModelReader.h @@ -1,56 +1,56 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_CONTOURMODEL_READER__H_ #define _MITK_CONTOURMODEL_READER__H_ // MITK #include #include #include #include #include #include #include #include namespace mitk { /** * @brief * @ingroup MitkContourModelModule */ class ContourModelReader : public mitk::AbstractFileReader { public: ContourModelReader(const ContourModelReader &other); ContourModelReader(); ~ContourModelReader() override; using AbstractFileReader::Read; - std::vector> Read() override; protected: virtual void ReadPoints(mitk::ContourModel::Pointer newContourModel, TiXmlElement *currentTimeSeries, unsigned int currentTimeStep); + std::vector> DoRead() override; private: ContourModelReader *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } #endif diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp index 615a802fc1..9af5f8f49b 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetReader.cpp +++ b/Modules/ContourModel/IO/mitkContourModelSetReader.cpp @@ -1,77 +1,77 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkContourModelSetReader.h" #include "mitkContourModelReader.h" #include #include #include #include mitk::ContourModelSetReader::ContourModelSetReader(const mitk::ContourModelSetReader &other) : mitk::AbstractFileReader(other) { } mitk::ContourModelSetReader::ContourModelSetReader() : AbstractFileReader() { std::string category = "ContourModelSet File"; CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("cnt_set"); this->SetDescription(category); this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::ContourModelSetReader::~ContourModelSetReader() { } -std::vector> mitk::ContourModelSetReader::Read() +std::vector> mitk::ContourModelSetReader::DoRead() { std::vector> result; std::vector> internalResult; std::string location = GetInputLocation(); // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); try { mitk::ContourModelSet::Pointer contourSet = mitk::ContourModelSet::New(); mitk::ContourModelReader reader; reader.SetInput(location); internalResult = reader.Read(); for (unsigned int i = 0; i < internalResult.size(); ++i) { contourSet->AddContourModel(dynamic_cast(internalResult.at(i).GetPointer())); } result.push_back(dynamic_cast(contourSet.GetPointer())); } catch (...) { MITK_ERROR << "Cannot read contourModel."; } return result; } mitk::ContourModelSetReader *mitk::ContourModelSetReader::Clone() const { return new ContourModelSetReader(*this); } diff --git a/Modules/ContourModel/IO/mitkContourModelSetReader.h b/Modules/ContourModel/IO/mitkContourModelSetReader.h index 1434ab76ea..91e24180a1 100644 --- a/Modules/ContourModel/IO/mitkContourModelSetReader.h +++ b/Modules/ContourModel/IO/mitkContourModelSetReader.h @@ -1,53 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_ContourModelSetReader__H_ #define _MITK_ContourModelSetReader__H_ // MITK #include #include #include #include #include #include #include #include #include namespace mitk { /** * @brief * @ingroup MitkContourModelModule */ class ContourModelSetReader : public mitk::AbstractFileReader { public: ContourModelSetReader(const ContourModelSetReader &other); ContourModelSetReader(); ~ContourModelSetReader() override; using AbstractFileReader::Read; - std::vector> Read() override; protected: + std::vector> DoRead() override; + private: ContourModelSetReader *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } #endif diff --git a/Modules/Core/files.cmake b/Modules/Core/files.cmake index 78ae1b7ad2..75407c5ac8 100644 --- a/Modules/Core/files.cmake +++ b/Modules/Core/files.cmake @@ -1,324 +1,325 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCoreActivator.cpp mitkCoreObjectFactoryBase.cpp mitkCoreObjectFactory.cpp mitkCoreServices.cpp mitkException.cpp Algorithms/mitkBaseDataSource.cpp Algorithms/mitkClippedSurfaceBoundsCalculator.cpp Algorithms/mitkCompareImageDataFilter.cpp Algorithms/mitkCompositePixelValueToString.cpp Algorithms/mitkConvert2Dto3DImageFilter.cpp Algorithms/mitkDataNodeSource.cpp Algorithms/mitkExtractSliceFilter.cpp Algorithms/mitkExtractSliceFilter2.cpp Algorithms/mitkHistogramGenerator.cpp Algorithms/mitkImageChannelSelector.cpp Algorithms/mitkImageSliceSelector.cpp Algorithms/mitkImageSource.cpp Algorithms/mitkImageTimeSelector.cpp Algorithms/mitkImageToImageFilter.cpp Algorithms/mitkImageToSurfaceFilter.cpp Algorithms/mitkMultiComponentImageDataComparisonFilter.cpp Algorithms/mitkPlaneGeometryDataToSurfaceFilter.cpp Algorithms/mitkPointSetSource.cpp Algorithms/mitkPointSetToPointSetFilter.cpp Algorithms/mitkRGBToRGBACastImageFilter.cpp Algorithms/mitkSubImageSelector.cpp Algorithms/mitkSurfaceSource.cpp Algorithms/mitkSurfaceToImageFilter.cpp Algorithms/mitkSurfaceToSurfaceFilter.cpp Algorithms/mitkUIDGenerator.cpp Algorithms/mitkVolumeCalculator.cpp Algorithms/mitkTemporalJoinImagesFilter.cpp Controllers/mitkBaseController.cpp Controllers/mitkCallbackFromGUIThread.cpp Controllers/mitkCameraController.cpp Controllers/mitkCameraRotationController.cpp Controllers/mitkLimitedLinearUndo.cpp Controllers/mitkOperationEvent.cpp Controllers/mitkPlanePositionManager.cpp Controllers/mitkProgressBar.cpp Controllers/mitkRenderingManager.cpp Controllers/mitkSliceNavigationController.cpp Controllers/mitkSlicesCoordinator.cpp Controllers/mitkStatusBar.cpp Controllers/mitkStepper.cpp Controllers/mitkTestManager.cpp Controllers/mitkUndoController.cpp Controllers/mitkVerboseLimitedLinearUndo.cpp Controllers/mitkVtkLayerController.cpp DataManagement/mitkAnatomicalStructureColorPresets.cpp DataManagement/mitkArbitraryTimeGeometry.cpp DataManagement/mitkAbstractTransformGeometry.cpp DataManagement/mitkAnnotationProperty.cpp DataManagement/mitkApplicationCursor.cpp DataManagement/mitkApplyTransformMatrixOperation.cpp DataManagement/mitkBaseData.cpp DataManagement/mitkBaseGeometry.cpp DataManagement/mitkBaseProperty.cpp DataManagement/mitkChannelDescriptor.cpp DataManagement/mitkClippingProperty.cpp DataManagement/mitkColorProperty.cpp DataManagement/mitkDataNode.cpp DataManagement/mitkDataStorage.cpp DataManagement/mitkEnumerationProperty.cpp DataManagement/mitkFloatPropertyExtension.cpp DataManagement/mitkGeometry3D.cpp DataManagement/mitkGeometryData.cpp DataManagement/mitkGeometryTransformHolder.cpp DataManagement/mitkGroupTagProperty.cpp DataManagement/mitkGenericIDRelationRule.cpp DataManagement/mitkIdentifiable.cpp DataManagement/mitkImageAccessorBase.cpp DataManagement/mitkImageCaster.cpp DataManagement/mitkImageCastPart1.cpp DataManagement/mitkImageCastPart2.cpp DataManagement/mitkImageCastPart3.cpp DataManagement/mitkImageCastPart4.cpp DataManagement/mitkImage.cpp DataManagement/mitkImageDataItem.cpp DataManagement/mitkImageDescriptor.cpp DataManagement/mitkImageReadAccessor.cpp DataManagement/mitkImageStatisticsHolder.cpp DataManagement/mitkImageVtkAccessor.cpp DataManagement/mitkImageVtkReadAccessor.cpp DataManagement/mitkImageVtkWriteAccessor.cpp DataManagement/mitkImageWriteAccessor.cpp DataManagement/mitkIntPropertyExtension.cpp DataManagement/mitkIPersistenceService.cpp DataManagement/mitkIPropertyAliases.cpp DataManagement/mitkIPropertyDescriptions.cpp DataManagement/mitkIPropertyExtensions.cpp DataManagement/mitkIPropertyFilters.cpp DataManagement/mitkIPropertyOwner.cpp DataManagement/mitkIPropertyPersistence.cpp DataManagement/mitkIPropertyProvider.cpp DataManagement/mitkLandmarkProjectorBasedCurvedGeometry.cpp DataManagement/mitkLandmarkProjector.cpp DataManagement/mitkLevelWindow.cpp DataManagement/mitkLevelWindowManager.cpp DataManagement/mitkLevelWindowPreset.cpp DataManagement/mitkLevelWindowProperty.cpp DataManagement/mitkLine.cpp DataManagement/mitkLookupTable.cpp DataManagement/mitkLookupTableProperty.cpp DataManagement/mitkLookupTables.cpp # specializations of GenericLookupTable DataManagement/mitkMaterial.cpp DataManagement/mitkMemoryUtilities.cpp DataManagement/mitkModalityProperty.cpp DataManagement/mitkModifiedLock.cpp DataManagement/mitkNodePredicateAnd.cpp DataManagement/mitkNodePredicateBase.cpp DataManagement/mitkNodePredicateCompositeBase.cpp DataManagement/mitkNodePredicateData.cpp DataManagement/mitkNodePredicateDataType.cpp DataManagement/mitkNodePredicateDataUID.cpp DataManagement/mitkNodePredicateDimension.cpp DataManagement/mitkNodePredicateFirstLevel.cpp DataManagement/mitkNodePredicateFunction.cpp DataManagement/mitkNodePredicateGeometry.cpp DataManagement/mitkNodePredicateNot.cpp DataManagement/mitkNodePredicateOr.cpp DataManagement/mitkNodePredicateProperty.cpp DataManagement/mitkNodePredicateDataProperty.cpp DataManagement/mitkNodePredicateSource.cpp DataManagement/mitkNumericConstants.cpp DataManagement/mitkPlaneGeometry.cpp DataManagement/mitkPlaneGeometryData.cpp DataManagement/mitkPlaneOperation.cpp DataManagement/mitkPlaneOrientationProperty.cpp DataManagement/mitkPointOperation.cpp DataManagement/mitkPointSet.cpp DataManagement/mitkPointSetShapeProperty.cpp DataManagement/mitkProperties.cpp DataManagement/mitkPropertyAliases.cpp DataManagement/mitkPropertyDescriptions.cpp DataManagement/mitkPropertyExtension.cpp DataManagement/mitkPropertyExtensions.cpp DataManagement/mitkPropertyFilter.cpp DataManagement/mitkPropertyFilters.cpp DataManagement/mitkPropertyKeyPath.cpp DataManagement/mitkPropertyList.cpp DataManagement/mitkPropertyListReplacedObserver.cpp DataManagement/mitkPropertyNameHelper.cpp DataManagement/mitkPropertyObserver.cpp DataManagement/mitkPropertyPersistence.cpp DataManagement/mitkPropertyPersistenceInfo.cpp DataManagement/mitkPropertyRelationRuleBase.cpp DataManagement/mitkProportionalTimeGeometry.cpp DataManagement/mitkRenderingModeProperty.cpp DataManagement/mitkResliceMethodProperty.cpp DataManagement/mitkRestorePlanePositionOperation.cpp DataManagement/mitkRotationOperation.cpp DataManagement/mitkScaleOperation.cpp DataManagement/mitkSlicedData.cpp DataManagement/mitkSlicedGeometry3D.cpp DataManagement/mitkSmartPointerProperty.cpp DataManagement/mitkStandaloneDataStorage.cpp DataManagement/mitkStringProperty.cpp DataManagement/mitkSurface.cpp DataManagement/mitkSurfaceOperation.cpp DataManagement/mitkSourceImageRelationRule.cpp DataManagement/mitkThinPlateSplineCurvedGeometry.cpp DataManagement/mitkTimeGeometry.cpp DataManagement/mitkTransferFunction.cpp DataManagement/mitkTransferFunctionInitializer.cpp DataManagement/mitkTransferFunctionProperty.cpp DataManagement/mitkTemporoSpatialStringProperty.cpp DataManagement/mitkUIDManipulator.cpp DataManagement/mitkVector.cpp DataManagement/mitkVectorProperty.cpp DataManagement/mitkVtkInterpolationProperty.cpp DataManagement/mitkVtkRepresentationProperty.cpp DataManagement/mitkVtkResliceInterpolationProperty.cpp DataManagement/mitkVtkScalarModeProperty.cpp DataManagement/mitkVtkVolumeRenderingProperty.cpp DataManagement/mitkWeakPointerProperty.cpp DataManagement/mitkIPropertyRelations.cpp DataManagement/mitkPropertyRelations.cpp Interactions/mitkAction.cpp Interactions/mitkBindDispatcherInteractor.cpp Interactions/mitkCrosshairPositionEvent.cpp Interactions/mitkDataInteractor.cpp Interactions/mitkDispatcher.cpp Interactions/mitkDisplayActionEventBroadcast.cpp Interactions/mitkDisplayActionEventFunctions.cpp Interactions/mitkDisplayActionEventHandler.cpp Interactions/mitkDisplayActionEventHandlerDesynchronized.cpp Interactions/mitkDisplayActionEventHandlerStd.cpp Interactions/mitkDisplayActionEventHandlerSynchronized.cpp Interactions/mitkDisplayCoordinateOperation.cpp Interactions/mitkDisplayInteractor.cpp Interactions/mitkEventConfig.cpp Interactions/mitkEventFactory.cpp Interactions/mitkEventRecorder.cpp Interactions/mitkEventStateMachine.cpp Interactions/mitkInteractionEventConst.cpp Interactions/mitkInteractionEvent.cpp Interactions/mitkInteractionEventHandler.cpp Interactions/mitkInteractionEventObserver.cpp Interactions/mitkInteractionKeyEvent.cpp Interactions/mitkInteractionPositionEvent.cpp Interactions/mitkInteractionSchemeSwitcher.cpp Interactions/mitkInternalEvent.cpp Interactions/mitkMouseDoubleClickEvent.cpp Interactions/mitkMouseModeSwitcher.cpp Interactions/mitkMouseMoveEvent.cpp Interactions/mitkMousePressEvent.cpp Interactions/mitkMouseReleaseEvent.cpp Interactions/mitkMouseWheelEvent.cpp Interactions/mitkPointSetDataInteractor.cpp Interactions/mitkSinglePointDataInteractor.cpp Interactions/mitkStateMachineAction.cpp Interactions/mitkStateMachineCondition.cpp Interactions/mitkStateMachineContainer.cpp Interactions/mitkStateMachineState.cpp Interactions/mitkStateMachineTransition.cpp Interactions/mitkVtkEventAdapter.cpp Interactions/mitkVtkInteractorStyle.cxx Interactions/mitkXML2EventParser.cpp IO/mitkAbstractFileIO.cpp IO/mitkAbstractFileReader.cpp IO/mitkAbstractFileWriter.cpp IO/mitkCustomMimeType.cpp IO/mitkFileReader.cpp IO/mitkFileReaderRegistry.cpp IO/mitkFileReaderSelector.cpp IO/mitkFileReaderWriterBase.cpp IO/mitkFileWriter.cpp IO/mitkFileWriterRegistry.cpp IO/mitkFileWriterSelector.cpp IO/mitkGeometry3DToXML.cpp IO/mitkIFileIO.cpp IO/mitkIFileReader.cpp IO/mitkIFileWriter.cpp IO/mitkGeometryDataReaderService.cpp IO/mitkGeometryDataWriterService.cpp IO/mitkImageGenerator.cpp IO/mitkImageVtkLegacyIO.cpp IO/mitkImageVtkXmlIO.cpp IO/mitkIMimeTypeProvider.cpp IO/mitkIOConstants.cpp IO/mitkIOMimeTypes.cpp IO/mitkIOUtil.cpp IO/mitkItkImageIO.cpp IO/mitkItkLoggingAdapter.cpp IO/mitkLegacyFileReaderService.cpp IO/mitkLegacyFileWriterService.cpp IO/mitkLocaleSwitch.cpp IO/mitkLog.cpp IO/mitkMimeType.cpp IO/mitkMimeTypeProvider.cpp IO/mitkOperation.cpp IO/mitkPixelType.cpp IO/mitkPointSetReaderService.cpp IO/mitkPointSetWriterService.cpp IO/mitkProportionalTimeGeometryToXML.cpp IO/mitkRawImageFileReader.cpp IO/mitkStandardFileLocations.cpp IO/mitkSurfaceStlIO.cpp IO/mitkSurfaceVtkIO.cpp IO/mitkSurfaceVtkLegacyIO.cpp IO/mitkSurfaceVtkXmlIO.cpp IO/mitkVtkLoggingAdapter.cpp IO/mitkPreferenceListReaderOptionsFunctor.cpp + IO/mitkIOMetaInformationPropertyConstants.cpp Rendering/mitkAbstractAnnotationRenderer.cpp Rendering/mitkAnnotationUtils.cpp Rendering/mitkBaseRenderer.cpp #Rendering/mitkGLMapper.cpp Moved to deprecated LegacyGL Module Rendering/mitkGradientBackground.cpp Rendering/mitkImageVtkMapper2D.cpp Rendering/mitkMapper.cpp Rendering/mitkAnnotation.cpp Rendering/mitkPlaneGeometryDataMapper2D.cpp Rendering/mitkPlaneGeometryDataVtkMapper3D.cpp Rendering/mitkPointSetVtkMapper2D.cpp Rendering/mitkPointSetVtkMapper3D.cpp Rendering/mitkRenderWindowBase.cpp Rendering/mitkRenderWindow.cpp Rendering/mitkRenderWindowFrame.cpp #Rendering/mitkSurfaceGLMapper2D.cpp Moved to deprecated LegacyGL Module Rendering/mitkSurfaceVtkMapper2D.cpp Rendering/mitkSurfaceVtkMapper3D.cpp Rendering/mitkVtkEventProvider.cpp Rendering/mitkVtkMapper.cpp Rendering/mitkVtkPropRenderer.cpp Rendering/mitkVtkWidgetRendering.cpp Rendering/vtkMitkLevelWindowFilter.cpp Rendering/vtkMitkRectangleProp.cpp Rendering/vtkMitkRenderProp.cpp Rendering/vtkMitkThickSlicesFilter.cpp Rendering/vtkNeverTranslucentTexture.cpp ) set(RESOURCE_FILES Interactions/globalConfig.xml Interactions/DisplayInteraction.xml Interactions/DisplayConfig.xml Interactions/DisplayConfigPACS.xml Interactions/DisplayConfigPACSPan.xml Interactions/DisplayConfigPACSScroll.xml Interactions/DisplayConfigPACSZoom.xml Interactions/DisplayConfigPACSLevelWindow.xml Interactions/DisplayConfigMITK.xml Interactions/DisplayConfigMITKNoCrosshair.xml Interactions/DisplayConfigMITKRotation.xml Interactions/DisplayConfigMITKRotationUnCoupled.xml Interactions/DisplayConfigMITKSwivel.xml Interactions/DisplayConfigMITKLimited.xml Interactions/PointSet.xml Interactions/Legacy/StateMachine.xml Interactions/Legacy/DisplayConfigMITKTools.xml Interactions/PointSetConfig.xml mitkLevelWindowPresets.xml mitkAnatomicalStructureColorPresets.xml ) diff --git a/Modules/Core/include/mitkAbstractFileReader.h b/Modules/Core/include/mitkAbstractFileReader.h index 8b21bbde6b..83ab25d7f3 100644 --- a/Modules/Core/include/mitkAbstractFileReader.h +++ b/Modules/Core/include/mitkAbstractFileReader.h @@ -1,232 +1,241 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 #define AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 // Macro #include // MITK #include #include #include // Microservices #include #include #include namespace us { struct PrototypeServiceFactory; } namespace mitk { class CustomMimeType; /** * @brief Base class for creating mitk::BaseData objects from files or streams. * @ingroup IO */ class MITKCORE_EXPORT AbstractFileReader : public mitk::IFileReader { public: void SetInput(const std::string &location) override; void SetInput(const std::string &location, std::istream *is) override; std::string GetInputLocation() const override; std::istream *GetInputStream() const override; MimeType GetRegisteredMimeType() const; /** * @brief Reads a path or stream and creates a list of BaseData objects. * - * This method must be implemented for each specific reader. Call - * GetInputStream() first and check for a non-null stream to read from. - * If the input stream is \c nullptr, use GetInputLocation() to read from a local - * file-system path. - * - * If the reader cannot use streams directly, use GetLocalFileName() instead. - * - * @return The created BaseData objects. - * @throws mitk::Exception - * - * @see GetLocalFileName() - * @see IFileReader::Read() + * The default implementation of this method (1) calls DoRead() + * (Implement the specific reader operation there) and (2) it addes general + * meta information about the loading process. */ - std::vector> Read() override = 0; + std::vector> Read() override; DataStorage::SetOfObjects::Pointer Read(mitk::DataStorage &ds) override; ConfidenceLevel GetConfidenceLevel() const override; Options GetOptions() const override; us::Any GetOption(const std::string &name) const override; void SetOptions(const Options &options) override; void SetOption(const std::string &name, const us::Any &value) override; void AddProgressCallback(const ProgressCallback &callback) override; void RemoveProgressCallback(const ProgressCallback &callback) override; /** * Associate this reader with the MIME type returned by the current IMimeTypeProvider * service for the provided extension if the MIME type exists, otherwise registers * a new MIME type when RegisterService() is called. * * If no MIME type for \c extension is already registered, a call to RegisterService() * will register a new MIME type and associate this reader instance with it. The MIME * type id can be set via SetMimeType() or it will be auto-generated using \c extension, * having the form "application/vnd.mitk.". * * @param extension The file extension (without a leading period) for which a registered * mime-type object is looked up and associated with this reader instance. * @param description A human readable description of this reader. */ us::ServiceRegistration RegisterService(us::ModuleContext *context = us::GetModuleContext()); void UnregisterService(); /** * @return A list of files that were loaded during the last call of Read. Has to be filled by the actual reader class. */ std::vector< std::string > GetReadFiles() override; protected: /** * @brief An input stream wrapper. * * If a reader can only work with input streams, use an instance * of this class to either wrap the specified input stream or * create a new input stream based on the input location in the * file system. */ class MITKCORE_EXPORT InputStream : public std::istream { public: InputStream(IFileReader *writer, std::ios_base::openmode mode = std::ios_base::in); ~InputStream() override; private: std::istream *m_Stream; }; AbstractFileReader(); ~AbstractFileReader() override; AbstractFileReader(const AbstractFileReader &other); /** * Associate this reader instance with the given MIME type. * * If \c mimeType does not provide an extension list, an already * registered mime-type object is used. Otherwise, the first entry in * the extensions list is used to construct a mime-type name and * register it as a new CustomMimeType service object in the default * implementation of RegisterMimeType(). * * @param mimeType The mime type this reader can read. * @param description A human readable description of this reader. * * @throws std::invalid_argument if \c mimeType is empty. * * @see RegisterService */ explicit AbstractFileReader(const CustomMimeType &mimeType, const std::string &description); + /** Method that should be implemented by derived classes and does the real loading. + * This method is called by Read(). + * This method must be implemented for each specific reader. Call + * GetInputStream() first and check for a non-null stream to read from. + * If the input stream is \c nullptr, use GetInputLocation() to read from a local + * file-system path. + * + * If the reader cannot use streams directly, use GetLocalFileName() instead. + * + * @return The created BaseData objects. + * @throws mitk::Exception + * + * @see GetLocalFileName() + * @see IFileReader::Read() + */ + virtual std::vector> DoRead() = 0; + + virtual us::ServiceProperties GetServiceProperties() const; /** * Registers a new CustomMimeType service object. * * This method is called from RegisterService and the default implementation * registers a new mime-type service object if all of the following conditions * are true: * * - TODO * * @param context * @return * @throws std::invalid_argument if \c context is nullptr. */ virtual us::ServiceRegistration RegisterMimeType(us::ModuleContext *context); void SetMimeType(const CustomMimeType &mimeType); /** * @return The mime-type this reader can handle. */ const CustomMimeType *GetMimeType() const; void SetMimeTypePrefix(const std::string &prefix); std::string GetMimeTypePrefix() const; void SetDescription(const std::string &description); std::string GetDescription() const; void SetDefaultOptions(const Options &defaultOptions); Options GetDefaultOptions() const; /** * \brief Set the service ranking for this file reader. * * Default is zero and should only be chosen differently for a reason. * The ranking is used to determine which reader to use if several * equivalent readers have been found. * It may be used to replace a default reader from MITK in your own project. * E.g. if you want to use your own reader for nrrd files instead of the default, * implement it and give it a higher ranking than zero. */ void SetRanking(int ranking); int GetRanking() const; /** * @brief Get a local file name for reading. * * This is a convenience method for readers which cannot work natively * with input streams. If no input stream has been been set, * this method just returns the result of GetLocation(). However, if * SetLocation(std::string, std::istream*) has been called with a non-null * input stream, this method writes the contents of the stream to a temporary * file and returns the name of the temporary file. * * The temporary file is deleted when either SetLocation(std::string, std::istream*) * is called again with a different input stream or the destructor of this * class is called. * * This method does not validate file names set via SetInput(std::string). * * @return A file path in the local file-system for reading. */ std::string GetLocalFileName() const; virtual void SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath); std::vector< std::string > m_ReadFiles; private: AbstractFileReader &operator=(const AbstractFileReader &other); virtual mitk::IFileReader *Clone() const = 0; class Impl; std::unique_ptr d; }; } // namespace mitk #endif /* AbstractFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Modules/Core/include/mitkGeometryDataReaderService.h b/Modules/Core/include/mitkGeometryDataReaderService.h index 6bdb38da25..1c7f8e23cb 100644 --- a/Modules/Core/include/mitkGeometryDataReaderService.h +++ b/Modules/Core/include/mitkGeometryDataReaderService.h @@ -1,60 +1,61 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkGeometryDataReaderService_h #define mitkGeometryDataReaderService_h // MITK #include #include class TiXmlElement; namespace mitk { /** * @internal * * @brief reads XML representations of mitk::GeometryData from a file/stream. * * To be used via IOUtil. * * Reader for XML files containing one or multiple XML represenations of * mitk::GeometryData. If multiple mitk::GeometryData objects are stored in one file, * these are assigned to multiple BaseData objects. * * @sa Geometry3DToXML * * @ingroup IO */ class GeometryDataReaderService : public AbstractFileReader { public: GeometryDataReaderService(); ~GeometryDataReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; /** * @brief Provides the MIME type for reader and writer. */ static CustomMimeType GEOMETRY_DATA_MIMETYPE(); + protected: + std::vector> DoRead() override; private: GeometryDataReaderService(const GeometryDataReaderService &other); GeometryDataReaderService *Clone() const override; }; } #endif diff --git a/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h b/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h new file mode 100644 index 0000000000..166bd66d3e --- /dev/null +++ b/Modules/Core/include/mitkIOMetaInformationPropertyConstants.h @@ -0,0 +1,44 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef MITKIOMETAINFORMATIONCONSTANTS_H_ +#define MITKIOMETAINFORMATIONCONSTANTS_H_ + +#include + +#include "mitkPropertyKeyPath.h" + +namespace mitk +{ + /** + * @ingroup IO + * @brief The IOMetaInformationPropertyConstants struct + */ + struct MITKCORE_EXPORT IOMetaInformationPropertyConstants + { + //Path to the property containing the name of the reader used + static PropertyKeyPath READER_DESCRIPTION(); + //Path to the property containing the version of mitk used to read the data + static PropertyKeyPath READER_VERSION(); + //Path to the property containing the mine name detected used to read the data + static PropertyKeyPath READER_MIME_NAME(); + //Path to the property containing the mime category detected to read the data + static PropertyKeyPath READER_MIME_CATEGORY(); + //Path to the property containing the input location if loaded by file used to read the data + static PropertyKeyPath READER_INPUTLOCATION(); + //Path to the properties containing the reader optins used to read the data + static PropertyKeyPath READER_OPTION_ROOT(); + static PropertyKeyPath READER_OPTIONS_ANY(); + }; +} + +#endif // MITKIOCONSTANTS_H_ diff --git a/Modules/Core/include/mitkItkImageIO.h b/Modules/Core/include/mitkItkImageIO.h index a1c488f9fb..cefc222130 100644 --- a/Modules/Core/include/mitkItkImageIO.h +++ b/Modules/Core/include/mitkItkImageIO.h @@ -1,77 +1,79 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKITKFILEIO_H #define MITKITKFILEIO_H #include "mitkAbstractFileIO.h" #include namespace mitk { /** * This class wraps ITK image IO objects as mitk::IFileReader and * mitk::IFileWriter objects. * * Instantiating this class with a given itk::ImageIOBase instance * will register corresponding MITK reader/writer services for that * ITK ImageIO object. */ class MITKCORE_EXPORT ItkImageIO : public AbstractFileIO { public: ItkImageIO(itk::ImageIOBase::Pointer imageIO); ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector> Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; protected: virtual std::vector FixUpImageIOExtensions(const std::string &imageIOName); virtual void FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType); // Fills the m_DefaultMetaDataKeys vector with default values virtual void InitializeDefaultMetaDataKeys(); + // -------------- AbstractFileReader ------------- + std::vector> DoRead() override; + private: ItkImageIO(const ItkImageIO &other); ItkImageIO *IOClone() const override; itk::ImageIOBase::Pointer m_ImageIO; std::vector m_DefaultMetaDataKeys; }; /**Helper function that converts the content of a meta data into a time point vector. * If MetaData is not valid or cannot be converted an empty vector is returned.*/ MITKCORE_EXPORT std::vector ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data); /**Helper function that converts the time points of a passed time geometry to a time point list and stores it in a itk::MetaDataObject. Use ConvertMetaDataObjectToTimePointList() to convert it back to a time point list.*/ MITKCORE_EXPORT itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry); } // namespace mitk #endif /* MITKITKFILEIO_H */ diff --git a/Modules/Core/include/mitkPropertyKeyPath.h b/Modules/Core/include/mitkPropertyKeyPath.h index 525503f634..134bb8e9ff 100644 --- a/Modules/Core/include/mitkPropertyKeyPath.h +++ b/Modules/Core/include/mitkPropertyKeyPath.h @@ -1,214 +1,216 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkPropertyKeyPath_h #define mitkPropertyKeyPath_h #include #include #include #include namespace mitk { /** @brief Class that can be used to specify nested or wild carded property keys. E.g. * for the use in context of the property persistence service or the property relation service.\n * Following assumptions are made /preconditions are defined: * - A property key is partitioned by "." into nodes (c.f. visualization of property keys in the PropertyView). * - A node can either be an element or a selection. * - An element has a name (alphanumric, - and space; "A-Za-z0-9- ") or is wildcarded ("*") * - A selection is either an index (e.g. "[1]") or a wildcard ("[*]"). * * Selections are used to indicate that the preceding element has multiple occurences and which occurence is meant. * Example property keys would be: * - prop : A simple property key * - prop.subprop1 : A property key consting of two nodes * - prop.* : Any property key that starts with a node "prop" * - prop.sub.[2] : A property key that starts with a node "prop" and a has a second node that is selection and has * the index 2. * - prop.sub.[*] : Any property key that starts with a node "prop" and a has a second node that is selection (with * any index). * * To build a path one may use the Add* method to build up the PropertyKeyPath element by element.\n * "first.*.third.[3]" would be equivalent to * propKeyPath.AddElement("first"); * propKeyPath.AddAnyElement(); * propKeyPath.AddSelection("third",3);\n * or the inline version * propKeyPath.AddElement("first").AddAnyElement().AddSelection("third",3); */ class MITKCORE_EXPORT PropertyKeyPath final { public: using ItemSelectionIndex = std::size_t; using ElementNameType = std::string; struct MITKCORE_EXPORT NodeInfo { enum class NodeType { Invalid = 0, //*< Node does not exist or is invalid. Element, //*< Selects an specific element given the node name. ElementSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]"). AnySelection, //*< Selects all items of a specific element ("[*]"). AnyElement //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily. }; NodeType type; ElementNameType name; ItemSelectionIndex selection; NodeInfo(); NodeInfo(const ElementNameType &name, NodeType type = NodeType::Element, ItemSelectionIndex index = 0); bool Matches(const NodeInfo &right) const; bool operator==(const NodeInfo &right) const; }; using NodeInfoVectorType = std::vector; using PathIndexType = NodeInfoVectorType::size_type; /** Returns if the PropertyKeyPath is empty.*/ bool IsEmpty() const; /** Returns if the path is explicit (has no wildcards).*/ bool IsExplicit() const; /** Returns if the path has any nodes with item selection wild cards ([*]).*/ bool HasItemSelectionWildcardsOnly() const; /** Number of path nodes the PropertyKeyPath contains.*/ PathIndexType GetSize() const; /** Adds a new node to the end of the path. \param [in] newNode Reference to the node that should be added. \return Returns the index of the newly added node.*/ PathIndexType AddNode(const NodeInfo &newNode); /** Function returns the node info of a path node specified by the index * within the PropertyKeyPath. * \pre Passed index must not be out of bounds. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be * thrown.*/ const NodeInfo &GetNode(const PathIndexType &index) const; /** Function returns the node info of a path node specified by the index * within the PropertyKeyPath. * \pre Passed index must not be out of bounds. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be * thrown.*/ NodeInfo &GetNode(const PathIndexType &index); /** Function returns the node info of the first path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo &GetFirstNode(); /** Function returns the node info of the first path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo &GetFirstNode() const; /** Function returns the node info of the last path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo &GetLastNode(); /** Function returns the node info of the last path node within the PropertyKeyPath. * \pre PropertyKeyPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo &GetLastNode() const; const NodeInfoVectorType &GetNodes() const; /**Compares two PropertyKeyPaths for real equality. So it is a string comparison of their string conversion.*/ bool operator==(const PropertyKeyPath &path) const; /**Operation equals like comparing the ToStr() results with operator <.*/ bool operator<(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator <=.*/ bool operator<=(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator >=.*/ bool operator>=(const PropertyKeyPath &right) const; /**Operation equals like comparing the ToStr() results with operator >.*/ bool operator>(const PropertyKeyPath &right) const; /**Checks if two PropertyKeyPaths specify the same node. Hence all wildcards will be processed.\n * E.G.: "item1.child1.grandChild2" == "item1.*.grandChild2" is true. * \remark If you want to check if two paths are "truly" equal and not only equal in terms of * pointing to the same node, use the member function operator ==().*/ bool Equals(const PropertyKeyPath &path) const; PropertyKeyPath &operator=(const PropertyKeyPath &path); /** Appends an "any element" to the path instance.*/ PropertyKeyPath &AddAnyElement(); /** Appends an element with the passed name to the path instance.*/ PropertyKeyPath &AddElement(const ElementNameType &name); /** Appends an element with the passed name and any selection to the path instance.*/ PropertyKeyPath &AddAnySelection(const ElementNameType &name); /** Appends an element with the passed name and selection index to the path instance.*/ PropertyKeyPath &AddSelection(const ElementNameType &name, ItemSelectionIndex index); PropertyKeyPath(); PropertyKeyPath(const PropertyKeyPath &path); + /** overload constructor that supports simple key pathes consisting only of elements.*/ + PropertyKeyPath(const std::initializer_list< ElementNameType >& list); ~PropertyKeyPath(); void Reset(); protected: NodeInfoVectorType m_NodeInfos; static bool PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right); }; class MITKCORE_EXPORT InvalidPathNodeException : public mitk::Exception { public: mitkExceptionClassMacro(InvalidPathNodeException, mitk::Exception); }; MITKCORE_EXPORT std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &path); /**Helper function that converts a path PropertyKeyPath into a regex string that can be used to search for property keys (using std::regex) that are matched by the PropertyKeyPath. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex string that can be used to search for property persistence keys (using std::regex) that are matched by the PropertyKeyPath. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex that can be used as key template in a PropertyPersistanceInfo. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath); /**Helper function that converts a path PropertyKeyPath into a regex that can be used as name template in a PropertyPersistanceInfo. This function is used in context of the property persistence service.*/ MITKCORE_EXPORT std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath); /** Converts the passed property name into a tag path. If the property name cannot be converted into a valid path, the returned path is empty.*/ MITKCORE_EXPORT PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName); /** returns the correct property name for a given PropertyKeyPath instance. */ MITKCORE_EXPORT std::string PropertyKeyPathToPropertyName(const PropertyKeyPath &tagPath); } // namespace mitk #endif diff --git a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp index 83a2993207..27fa3f08a1 100644 --- a/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp +++ b/Modules/Core/src/DataManagement/mitkPropertyKeyPath.cpp @@ -1,596 +1,605 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include namespace mitk { PropertyKeyPath::NodeInfo::NodeInfo() : type(NodeType::Invalid), selection(0){}; PropertyKeyPath::NodeInfo::NodeInfo(const ElementNameType &name, NodeType type, ItemSelectionIndex index) : type(type), name(name), selection(index){}; bool PropertyKeyPath::NodeInfo::operator==(const NodeInfo &right) const { if (this->name != right.name) return false; if (this->type != right.type) return false; if (this->selection != right.selection) return false; return true; }; bool PropertyKeyPath::NodeInfo::Matches(const NodeInfo &right) const { if (type == NodeType::Invalid || right.type == NodeType::Invalid) { return false; } else if (type == NodeType::AnyElement || right.type == NodeType::AnyElement) { return true; } else if (name == right.name) { if (type == NodeType::Element && right.type == NodeType::Element) { return true; } else if (selection == right.selection || type == NodeType::AnySelection || right.type == NodeType::AnySelection) { return true; } } return false; }; bool PropertyKeyPath::IsEmpty() const { return m_NodeInfos.empty(); }; bool PropertyKeyPath::IsExplicit() const { for (const auto &pos : m_NodeInfos) { if ((pos.type == NodeInfo::NodeType::AnySelection) || (pos.type == NodeInfo::NodeType::AnyElement)) { return false; } } return true; }; bool PropertyKeyPath::HasItemSelectionWildcardsOnly() const { bool result = false; for (const auto &pos : m_NodeInfos) { if (pos.type == NodeInfo::NodeType::AnyElement) { return false; } result = result || pos.type == NodeInfo::NodeType::AnySelection; } return result; }; PropertyKeyPath::PathIndexType PropertyKeyPath::GetSize() const { return m_NodeInfos.size(); } PropertyKeyPath::PathIndexType PropertyKeyPath::AddNode(const NodeInfo &newNode) { m_NodeInfos.push_back(newNode); return m_NodeInfos.size() - 1; }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) const { if (index >= GetSize()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index << "; Path: " << PropertyKeyPathToPropertyName(*this); } return m_NodeInfos[index]; }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetNode(const PathIndexType &index) { if (index >= this->GetSize()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return info of path node. Node index is out of bounds. Index: " << index << "; Path: " << PropertyKeyPathToPropertyName(*this); } return m_NodeInfos[index]; }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() const { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; } return this->GetNode(0); }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetFirstNode() { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return first path node. Path is empty."; } return this->GetNode(0); }; const PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() const { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; } return this->GetNode(GetSize() - 1); }; PropertyKeyPath::NodeInfo &PropertyKeyPath::GetLastNode() { if (m_NodeInfos.empty()) { mitkThrowException(InvalidPathNodeException) << "Error. Cannot return last path node. Path is empty."; } return this->GetNode(GetSize() - 1); }; const PropertyKeyPath::NodeInfoVectorType &PropertyKeyPath::GetNodes() const { return m_NodeInfos; }; bool PropertyKeyPath::operator==(const PropertyKeyPath &path) const { return m_NodeInfos == path.m_NodeInfos; }; bool PropertyKeyPath::operator<(const PropertyKeyPath &right) const { auto rightIter = right.m_NodeInfos.cbegin(); const auto rightEnd = right.m_NodeInfos.cend(); for (const auto &leftPos : m_NodeInfos) { if (rightIter == rightEnd) { return false; } if (leftPos.name < rightIter->name) { return true; } if (rightIter->name < leftPos.name) { return false; } if (leftPos.type < rightIter->type) { return true; } if (rightIter->type < leftPos.type) { return false; } if (leftPos.selection < rightIter->selection) { return true; } if (rightIter->selection < leftPos.selection) { return false; } ++rightIter; } return rightIter != rightEnd; } bool PropertyKeyPath::operator>(const PropertyKeyPath &right) const { auto rightIter = right.m_NodeInfos.cbegin(); const auto rightEnd = right.m_NodeInfos.cend(); for (const auto &leftPos : m_NodeInfos) { if (rightIter == rightEnd) return false; if (leftPos.name > rightIter->name) return true; if (rightIter->name > leftPos.name) return false; if (leftPos.type > rightIter->type) return true; if (rightIter->type > leftPos.type) return false; if (leftPos.selection > rightIter->selection) return true; if (rightIter->selection > leftPos.selection) return false; ++rightIter; } return rightIter != rightEnd; } bool PropertyKeyPath::operator>=(const PropertyKeyPath &right) const { return !(*this < right); } bool PropertyKeyPath::operator<=(const PropertyKeyPath &right) const { return !(*this > right); } bool PropertyKeyPath::Equals(const PropertyKeyPath &path) const { return PropertyKeyPathsMatch(*this, path); }; PropertyKeyPath &PropertyKeyPath::operator=(const PropertyKeyPath &path) { if (this != &path) { m_NodeInfos = path.m_NodeInfos; } return *this; }; PropertyKeyPath &PropertyKeyPath::AddAnyElement() { m_NodeInfos.emplace_back("", NodeInfo::NodeType::AnyElement); return *this; }; PropertyKeyPath &PropertyKeyPath::AddElement(const ElementNameType &name) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::Element); return *this; }; PropertyKeyPath &PropertyKeyPath::AddAnySelection(const ElementNameType &name) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::AnySelection); return *this; }; PropertyKeyPath &PropertyKeyPath::AddSelection(const ElementNameType &name, ItemSelectionIndex index) { m_NodeInfos.emplace_back(name, NodeInfo::NodeType::ElementSelection, index); return *this; }; PropertyKeyPath::PropertyKeyPath() { this->Reset(); }; PropertyKeyPath::PropertyKeyPath(const PropertyKeyPath &path) { *this = path; }; + PropertyKeyPath::PropertyKeyPath(const std::initializer_list< ElementNameType >& list) + { + this->Reset(); + for (const auto& name : list) + { + this->AddElement(name); + } + } + PropertyKeyPath::~PropertyKeyPath(){}; void PropertyKeyPath::Reset() { m_NodeInfos.clear(); }; bool PropertyKeyPath::PropertyKeyPathsMatch(const PropertyKeyPath &left, const PropertyKeyPath &right) { auto leftPos = left.GetNodes().cbegin(); auto rightPos = right.GetNodes().cbegin(); auto leftEnd = left.GetNodes().cend(); auto rightEnd = right.GetNodes().cend(); while (leftPos != leftEnd && rightPos != rightEnd) { if (!leftPos->Matches(*rightPos)) { break; } ++leftPos; ++rightPos; } if (leftPos == leftEnd && rightPos == rightEnd) { return true; } else { return false; } }; std::ostream &operator<<(std::ostream &os, const PropertyKeyPath &value) { os << PropertyKeyPathToPropertyName(value); return os; }; std::string PropertyKeyPathToPropertyRegEx(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "\\."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "([a-zA-Z0-9- ]+)"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "\\.\\[" << node.selection << "\\]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "\\.\\[(\\d*)\\]"; } } else { nameStream << "INVALIDNODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceKeyRegEx(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "_"; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "([a-zA-Z0-9- ]+)"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "_\\[" << node.selection << "\\]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "_\\[(\\d*)\\]"; } } else { nameStream << "INVALIDNODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceKeyTemplate(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; int captureGroup = 1; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "_"; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "$" << captureGroup++; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << "_[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << "_[$" << captureGroup++ << "]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; std::string PropertyKeyPathToPersistenceNameTemplate(const PropertyKeyPath &tagPath) { std::ostringstream nameStream; int captureGroup = 1; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "$" << captureGroup++; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << ".[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << ".[$" << captureGroup++ << "]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; PropertyKeyPath PropertyNameToPropertyKeyPath(const std::string &propertyName) { PropertyKeyPath result; std::regex reg_element("([a-zA-Z0-9- ]+)"); std::regex reg_anySelection("\\[\\*\\]"); std::regex reg_Selection("\\[(\\d+)\\]"); std::istringstream f(propertyName); std::string subStr; PropertyKeyPath::ElementNameType name = ""; while (getline(f, subStr, '.')) { if (subStr == "*") { if (!name.empty()) { result.AddElement(name); name.clear(); } result.AddAnyElement(); } else { std::smatch sm; if (std::regex_match(subStr, sm, reg_anySelection)) { if (!name.empty()) { result.AddAnySelection(name); name.clear(); } else { // invalid path return PropertyKeyPath(); } } else if (std::regex_match(subStr, sm, reg_Selection)) { if (!name.empty()) { result.AddSelection(name, std::stoi(sm[1])); name.clear(); } else { // invalid path return PropertyKeyPath(); } } else if (std::regex_match(subStr, sm, reg_element)) { if (!name.empty()) { // store the last element and start the next result.AddElement(name); } name = sm[1]; } else { return PropertyKeyPath(); } } } if (!name.empty()) { // add last element result.AddElement(name); } return result; }; std::string PropertyKeyPathToPropertyName(const mitk::PropertyKeyPath &tagPath) { std::ostringstream nameStream; PropertyKeyPath::PathIndexType i = 0; for (const auto &node : tagPath.GetNodes()) { if (i) { nameStream << "."; } ++i; if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnyElement) { nameStream << "*"; } else if (node.type != PropertyKeyPath::NodeInfo::NodeType::Invalid) { nameStream << node.name; if (node.type == PropertyKeyPath::NodeInfo::NodeType::ElementSelection) { nameStream << ".[" << node.selection << "]"; } else if (node.type == PropertyKeyPath::NodeInfo::NodeType::AnySelection) { nameStream << ".[*]"; } } else { nameStream << "INVALID_NODE"; } } return nameStream.str(); }; } // namespace mitk diff --git a/Modules/Core/src/IO/mitkAbstractFileReader.cpp b/Modules/Core/src/IO/mitkAbstractFileReader.cpp index 05d7b1b837..af38ca14ad 100644 --- a/Modules/Core/src/IO/mitkAbstractFileReader.cpp +++ b/Modules/Core/src/IO/mitkAbstractFileReader.cpp @@ -1,320 +1,332 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include -#include #include +#include +#include #include #include #include #include #include namespace mitk { AbstractFileReader::InputStream::InputStream(IFileReader *reader, std::ios_base::openmode mode) : std::istream(nullptr), m_Stream(nullptr) { std::istream *stream = reader->GetInputStream(); if (stream) { this->init(stream->rdbuf()); } else { m_Stream = new std::ifstream(reader->GetInputLocation().c_str(), mode); this->init(m_Stream->rdbuf()); } } AbstractFileReader::InputStream::~InputStream() { delete m_Stream; } class AbstractFileReader::Impl : public FileReaderWriterBase { public: Impl() : FileReaderWriterBase(), m_Stream(nullptr), m_PrototypeFactory(nullptr) {} Impl(const Impl &other) : FileReaderWriterBase(other), m_Stream(nullptr), m_PrototypeFactory(nullptr) {} std::string m_Location; std::string m_TmpFile; std::istream *m_Stream; us::PrototypeServiceFactory *m_PrototypeFactory; us::ServiceRegistration m_Reg; }; AbstractFileReader::AbstractFileReader() : d(new Impl) {} AbstractFileReader::~AbstractFileReader() { UnregisterService(); delete d->m_PrototypeFactory; if (!d->m_TmpFile.empty()) { std::remove(d->m_TmpFile.c_str()); } } AbstractFileReader::AbstractFileReader(const AbstractFileReader &other) : IFileReader(), d(new Impl(*other.d.get())) { } AbstractFileReader::AbstractFileReader(const CustomMimeType &mimeType, const std::string &description) : d(new Impl) { d->SetMimeType(mimeType); d->SetDescription(description); } ////////////////////// Reading ///////////////////////// std::vector AbstractFileReader::Read() { - std::vector result; - - DataStorage::Pointer ds = StandaloneDataStorage::New().GetPointer(); - this->Read(*ds); - DataStorage::SetOfObjects::ConstPointer dataNodes = ds->GetAll(); - for (DataStorage::SetOfObjects::ConstIterator iter = dataNodes->Begin(), iterEnd = dataNodes->End(); - iter != iterEnd; - ++iter) + std::vector result = this->DoRead(); + + const auto options = this->GetOptions(); + + for (auto& data : result) { - result.push_back(iter.Value()->GetData()); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_DESCRIPTION()), StringProperty::New(d->GetDescription())); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_VERSION()), StringProperty::New(MITK_VERSION_STRING)); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_MIME_NAME()), StringProperty::New(d->GetMimeType()->GetName())); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()), StringProperty::New(d->GetMimeType()->GetCategory())); + if (this->GetInputStream() == nullptr) + { + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConstants::READER_INPUTLOCATION()), StringProperty::New(this->GetInputLocation())); + } + + for (const auto& option : options) + { + auto optionpath = IOMetaInformationPropertyConstants::READER_OPTION_ROOT().AddElement(option.first); + data->SetProperty(PropertyKeyPathToPropertyName(optionpath), StringProperty::New(option.second.ToString())); + } } + return result; } DataStorage::SetOfObjects::Pointer AbstractFileReader::Read(DataStorage &ds) { DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); std::vector data = this->Read(); for (auto iter = data.begin(); iter != data.end(); ++iter) { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(*iter); this->SetDefaultDataNodeProperties(node, this->GetInputLocation()); ds.Add(node); result->InsertElement(result->Size(), node); } return result; } IFileReader::ConfidenceLevel AbstractFileReader::GetConfidenceLevel() const { if (d->m_Stream) { if (*d->m_Stream) return Supported; } else { if (itksys::SystemTools::FileExists(this->GetInputLocation().c_str(), true)) { return Supported; } } return Unsupported; } //////////// µS Registration & Properties ////////////// us::ServiceRegistration AbstractFileReader::RegisterService(us::ModuleContext *context) { if (d->m_PrototypeFactory) return us::ServiceRegistration(); if (context == nullptr) { context = us::GetModuleContext(); } d->RegisterMimeType(context); if (this->GetMimeType()->GetName().empty()) { MITK_WARN << "Not registering reader due to empty MIME type."; return us::ServiceRegistration(); } struct PrototypeFactory : public us::PrototypeServiceFactory { AbstractFileReader *const m_Prototype; PrototypeFactory(AbstractFileReader *prototype) : m_Prototype(prototype) {} us::InterfaceMap GetService(us::Module * /*module*/, const us::ServiceRegistrationBase & /*registration*/) override { return us::MakeInterfaceMap(m_Prototype->Clone()); } void UngetService(us::Module * /*module*/, const us::ServiceRegistrationBase & /*registration*/, const us::InterfaceMap &service) override { delete us::ExtractInterface(service); } }; d->m_PrototypeFactory = new PrototypeFactory(this); us::ServiceProperties props = this->GetServiceProperties(); d->m_Reg = context->RegisterService(d->m_PrototypeFactory, props); return d->m_Reg; } void AbstractFileReader::UnregisterService() { try { d->m_Reg.Unregister(); } catch (const std::exception &) { } } us::ServiceProperties AbstractFileReader::GetServiceProperties() const { us::ServiceProperties result; result[IFileReader::PROP_DESCRIPTION()] = this->GetDescription(); result[IFileReader::PROP_MIMETYPE()] = this->GetMimeType()->GetName(); result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); return result; } us::ServiceRegistration AbstractFileReader::RegisterMimeType(us::ModuleContext *context) { return d->RegisterMimeType(context); } std::vector< std::string > AbstractFileReader::GetReadFiles(){ return m_ReadFiles; } void AbstractFileReader::SetMimeType(const CustomMimeType &mimeType) { d->SetMimeType(mimeType); } void AbstractFileReader::SetDescription(const std::string &description) { d->SetDescription(description); } void AbstractFileReader::SetRanking(int ranking) { d->SetRanking(ranking); } int AbstractFileReader::GetRanking() const { return d->GetRanking(); } std::string AbstractFileReader::GetLocalFileName() const { std::string localFileName; if (d->m_Stream) { if (d->m_TmpFile.empty()) { // write the stream contents to temporary file std::string ext = itksys::SystemTools::GetFilenameExtension(this->GetInputLocation()); std::ofstream tmpStream; localFileName = mitk::IOUtil::CreateTemporaryFile( tmpStream, std::ios_base::out | std::ios_base::trunc | std::ios_base::binary, "XXXXXX" + ext); tmpStream << d->m_Stream->rdbuf(); d->m_TmpFile = localFileName; } else { localFileName = d->m_TmpFile; } } else { localFileName = d->m_Location; } return localFileName; } //////////////////////// Options /////////////////////// void AbstractFileReader::SetDefaultOptions(const IFileReader::Options &defaultOptions) { d->SetDefaultOptions(defaultOptions); } IFileReader::Options AbstractFileReader::GetDefaultOptions() const { return d->GetDefaultOptions(); } void AbstractFileReader::SetInput(const std::string &location) { d->m_Location = location; d->m_Stream = nullptr; } void AbstractFileReader::SetInput(const std::string &location, std::istream *is) { if (d->m_Stream != is && !d->m_TmpFile.empty()) { std::remove(d->m_TmpFile.c_str()); d->m_TmpFile.clear(); } d->m_Location = location; d->m_Stream = is; } std::string AbstractFileReader::GetInputLocation() const { return d->m_Location; } std::istream *AbstractFileReader::GetInputStream() const { return d->m_Stream; } MimeType AbstractFileReader::GetRegisteredMimeType() const { return d->GetRegisteredMimeType(); } IFileReader::Options AbstractFileReader::GetOptions() const { return d->GetOptions(); } us::Any AbstractFileReader::GetOption(const std::string &name) const { return d->GetOption(name); } void AbstractFileReader::SetOptions(const Options &options) { d->SetOptions(options); } void AbstractFileReader::SetOption(const std::string &name, const us::Any &value) { d->SetOption(name, value); } ////////////////// MISC ////////////////// void AbstractFileReader::AddProgressCallback(const ProgressCallback &callback) { d->AddProgressCallback(callback); } void AbstractFileReader::RemoveProgressCallback(const ProgressCallback &callback) { d->RemoveProgressCallback(callback); } ////////////////// µS related Getters ////////////////// const CustomMimeType *AbstractFileReader::GetMimeType() const { return d->GetMimeType(); } void AbstractFileReader::SetMimeTypePrefix(const std::string &prefix) { d->SetMimeTypePrefix(prefix); } std::string AbstractFileReader::GetMimeTypePrefix() const { return d->GetMimeTypePrefix(); } std::string AbstractFileReader::GetDescription() const { return d->GetDescription(); } void AbstractFileReader::SetDefaultDataNodeProperties(DataNode *node, const std::string &filePath) { // path if (!filePath.empty()) { mitk::StringProperty::Pointer pathProp = mitk::StringProperty::New(itksys::SystemTools::GetFilenamePath(filePath)); node->SetProperty(StringProperty::PATH, pathProp); } // name already defined? mitk::StringProperty::Pointer nameProp = dynamic_cast(node->GetProperty("name")); if (nameProp.IsNull() || nameProp->GetValue() == DataNode::NO_NAME_VALUE()) { // name already defined in BaseData mitk::StringProperty::Pointer baseDataNameProp = dynamic_cast(node->GetData()->GetProperty("name").GetPointer()); if (baseDataNameProp.IsNull() || baseDataNameProp->GetValue() == DataNode::NO_NAME_VALUE()) { // name neither defined in node, nor in BaseData -> name = filebasename; nameProp = mitk::StringProperty::New(this->GetRegisteredMimeType().GetFilenameWithoutExtension(filePath)); node->SetProperty("name", nameProp); } else { // name defined in BaseData! nameProp = mitk::StringProperty::New(baseDataNameProp->GetValue()); node->SetProperty("name", nameProp); } } // visibility if (!node->GetProperty("visible")) { node->SetVisibility(true); } } } diff --git a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp index c95ed5eac5..0b13ffe89c 100644 --- a/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp +++ b/Modules/Core/src/IO/mitkGeometryDataReaderService.cpp @@ -1,112 +1,112 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkGeometryDataReaderService.h" #include "mitkGeometry3DToXML.h" #include "mitkIOMimeTypes.h" #include "mitkProportionalTimeGeometryToXML.h" // STL #include #include mitk::GeometryDataReaderService::GeometryDataReaderService() : AbstractFileReader(IOMimeTypes::GEOMETRY_DATA_MIMETYPE(), "MITK Geometry Data Reader") { RegisterService(); } mitk::GeometryDataReaderService::~GeometryDataReaderService() { } -std::vector> mitk::GeometryDataReaderService::Read() +std::vector> mitk::GeometryDataReaderService::DoRead() { // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); std::vector> result; InputStream stream(this); TiXmlDocument doc; stream >> doc; if (!doc.Error()) { TiXmlHandle docHandle(&doc); for (TiXmlElement *geomDataElement = docHandle.FirstChildElement("GeometryData").ToElement(); geomDataElement != nullptr; geomDataElement = geomDataElement->NextSiblingElement()) { for (TiXmlElement *currentElement = geomDataElement->FirstChildElement(); currentElement != nullptr; currentElement = currentElement->NextSiblingElement()) { // different geometries could have been serialized from a GeometryData // object: std::string tagName = currentElement->Value(); if (tagName == "Geometry3D") { Geometry3D::Pointer restoredGeometry = Geometry3DToXML::FromXML(currentElement); if (restoredGeometry.IsNotNull()) { GeometryData::Pointer newGeometryData = GeometryData::New(); newGeometryData->SetGeometry(restoredGeometry); result.push_back(newGeometryData.GetPointer()); } else { MITK_ERROR << "Invalid tag encountered. Skipping."; } } else if (tagName == "ProportionalTimeGeometry") { ProportionalTimeGeometry::Pointer restoredTimeGeometry = ProportionalTimeGeometryToXML::FromXML(currentElement); if (restoredTimeGeometry.IsNotNull()) { GeometryData::Pointer newGeometryData = GeometryData::New(); newGeometryData->SetTimeGeometry(restoredTimeGeometry); result.push_back(newGeometryData.GetPointer()); } else { MITK_ERROR << "Invalid tag encountered. Skipping."; } } } // for child of } // for } else { mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); } if (result.empty()) { mitkThrow() << "Did not read a single GeometryData object from input."; } return result; } mitk::GeometryDataReaderService::GeometryDataReaderService(const mitk::GeometryDataReaderService &other) : mitk::AbstractFileReader(other) { } mitk::GeometryDataReaderService *mitk::GeometryDataReaderService::Clone() const { return new GeometryDataReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp b/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp new file mode 100644 index 0000000000..a57c640107 --- /dev/null +++ b/Modules/Core/src/IO/mitkIOMetaInformationPropertyConstants.cpp @@ -0,0 +1,52 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "mitkIOMetaInformationPropertyConstants.h" + +namespace mitk +{ + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_DESCRIPTION() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "description" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_VERSION() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "version" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_MIME_NAME() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "mime", "name" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_MIME_CATEGORY() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "mime", "category" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_INPUTLOCATION() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "inputlocation" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_OPTION_ROOT() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "option" }); + } + + PropertyKeyPath IOMetaInformationPropertyConstants::READER_OPTIONS_ANY() + { + return READER_OPTION_ROOT().AddAnyElement(); + } +} diff --git a/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp b/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp index cc5cb322a4..c7f39ed4d5 100644 --- a/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp +++ b/Modules/Core/src/IO/mitkImageVtkLegacyIO.cpp @@ -1,113 +1,113 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkImageVtkLegacyIO.h" #include "mitkIOMimeTypes.h" #include "mitkImage.h" #include "mitkImageVtkReadAccessor.h" #include #include #include #include #include namespace mitk { ImageVtkLegacyIO::ImageVtkLegacyIO() : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_LEGACY_MIMETYPE(), "VTK Legacy Image") { Options defaultOptions; defaultOptions["Save as binary file"] = false; this->SetDefaultWriterOptions(defaultOptions); this->RegisterService(); } - std::vector ImageVtkLegacyIO::Read() + std::vector ImageVtkLegacyIO::DoRead() { // The legay vtk reader cannot work with input streams const std::string fileName = this->GetLocalFileName(); vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(fileName.c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(reader->GetOutput()); output->SetVolume(reader->GetOutput()->GetScalarPointer()); std::vector result; result.push_back(output.GetPointer()); return result; } else { mitkThrow() << "vtkStructuredPointsReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(this->GetLocalFileName().c_str()); if (reader->IsFileStructuredPoints()) { return Supported; } return Unsupported; } void ImageVtkLegacyIO::Write() { ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); vtkSmartPointer writer = vtkSmartPointer::New(); // The legacy vtk image writer cannot write to streams LocalFile localFile(this); writer->SetFileName(localFile.GetFileName().c_str()); if (us::any_cast(GetWriterOption("Save as binary file"))) { writer->SetFileTypeToBinary(); } ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), nullptr, input->GetVtkImageData()); writer->SetInputData(const_cast(vtkReadAccessor.GetVtkImageData())); if (writer->Write() == 0 || writer->GetErrorCode() != 0) { mitkThrow() << "vtkStructuredPointesWriter error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkLegacyIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const auto *input = static_cast(this->GetInput()); if (input->GetDimension() == 3) return Supported; else if (input->GetDimension() < 3) return PartiallySupported; return Unsupported; } ImageVtkLegacyIO *ImageVtkLegacyIO::IOClone() const { return new ImageVtkLegacyIO(*this); } } diff --git a/Modules/Core/src/IO/mitkImageVtkLegacyIO.h b/Modules/Core/src/IO/mitkImageVtkLegacyIO.h index 7a0256ee21..efffa19b9d 100644 --- a/Modules/Core/src/IO/mitkImageVtkLegacyIO.h +++ b/Modules/Core/src/IO/mitkImageVtkLegacyIO.h @@ -1,42 +1,43 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKIMAGEVTKLEGACYIO_H #define MITKIMAGEVTKLEGACYIO_H #include "mitkAbstractFileIO.h" namespace mitk { class ImageVtkLegacyIO : public mitk::AbstractFileIO { public: ImageVtkLegacyIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; + protected: + std::vector> DoRead() override; private: ImageVtkLegacyIO *IOClone() const override; }; } #endif // MITKIMAGEVTKLEGACYIO_H diff --git a/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp b/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp index 8318508fc1..a7f04fc164 100644 --- a/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp +++ b/Modules/Core/src/IO/mitkImageVtkXmlIO.cpp @@ -1,144 +1,144 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkImageVtkXmlIO.h" #include "mitkIOMimeTypes.h" #include "mitkImage.h" #include "mitkImageVtkReadAccessor.h" #include #include #include #include #include namespace mitk { class VtkXMLImageDataReader : public ::vtkXMLImageDataReader { public: static VtkXMLImageDataReader *New() { return new VtkXMLImageDataReader(); } vtkTypeMacro(VtkXMLImageDataReader, vtkXMLImageDataReader) void SetStream(std::istream *is) { this->Stream = is; } std::istream *GetStream() const { return this->Stream; } }; class VtkXMLImageDataWriter : public ::vtkXMLImageDataWriter { public: static VtkXMLImageDataWriter *New() { return new VtkXMLImageDataWriter(); } vtkTypeMacro(VtkXMLImageDataWriter, vtkXMLImageDataWriter) void SetStream(std::ostream *os) { this->Stream = os; } std::ostream *GetStream() const { return this->Stream; } }; ImageVtkXmlIO::ImageVtkXmlIO() : AbstractFileIO(Image::GetStaticNameOfClass(), IOMimeTypes::VTK_IMAGE_MIMETYPE(), "VTK XML Image") { this->RegisterService(); } - std::vector ImageVtkXmlIO::Read() + std::vector ImageVtkXmlIO::DoRead() { vtkSmartPointer reader = vtkSmartPointer::New(); if (this->GetInputStream()) { reader->SetStream(this->GetInputStream()); } else { reader->SetFileName(this->GetInputLocation().c_str()); } reader->Update(); if (reader->GetOutput() != nullptr) { mitk::Image::Pointer output = mitk::Image::New(); output->Initialize(reader->GetOutput()); output->SetVolume(reader->GetOutput()->GetScalarPointer()); std::vector result; result.push_back(output.GetPointer()); return result; } else { mitkThrow() << "vtkXMLImageDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkXmlIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; if (this->GetInputStream() == nullptr) { // check if the xml vtk reader can handle the file vtkSmartPointer xmlReader = vtkSmartPointer::New(); if (xmlReader->CanReadFile(this->GetInputLocation().c_str()) != 0) { return Supported; } return Unsupported; } // in case of an input stream, VTK does not seem to have methods for // validating it return Supported; } void ImageVtkXmlIO::Write() { ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); vtkSmartPointer writer = vtkSmartPointer::New(); if (this->GetOutputStream()) { writer->SetStream(this->GetOutputStream()); } else { writer->SetFileName(this->GetOutputLocation().c_str()); } ImageVtkReadAccessor vtkReadAccessor(Image::ConstPointer(input), nullptr, input->GetVtkImageData()); writer->SetInputData(const_cast(vtkReadAccessor.GetVtkImageData())); if (writer->Write() == 0 || writer->GetErrorCode() != 0) { mitkThrow() << "vtkXMLImageDataWriter error: " << vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()); } } IFileIO::ConfidenceLevel ImageVtkXmlIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const auto *input = static_cast(this->GetInput()); if (input->GetDimension() == 3) return Supported; else if (input->GetDimension() < 3) return PartiallySupported; return Unsupported; } ImageVtkXmlIO *ImageVtkXmlIO::IOClone() const { return new ImageVtkXmlIO(*this); } } diff --git a/Modules/Core/src/IO/mitkImageVtkXmlIO.h b/Modules/Core/src/IO/mitkImageVtkXmlIO.h index bdfd759adc..5edc030350 100644 --- a/Modules/Core/src/IO/mitkImageVtkXmlIO.h +++ b/Modules/Core/src/IO/mitkImageVtkXmlIO.h @@ -1,42 +1,43 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKIMAGEVTKXMLIO_H #define MITKIMAGEVTKXMLIO_H #include "mitkAbstractFileIO.h" namespace mitk { class ImageVtkXmlIO : public mitk::AbstractFileIO { public: ImageVtkXmlIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; + protected: + std::vector> DoRead() override; private: ImageVtkXmlIO *IOClone() const override; }; } #endif // MITKIMAGEVTKXMLIO_H diff --git a/Modules/Core/src/IO/mitkItkImageIO.cpp b/Modules/Core/src/IO/mitkItkImageIO.cpp index f482ea5f13..d4666d22ed 100644 --- a/Modules/Core/src/IO/mitkItkImageIO.cpp +++ b/Modules/Core/src/IO/mitkItkImageIO.cpp @@ -1,708 +1,708 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkItkImageIO.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { const char *const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type"; const char *const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints"; const char *const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type"; const char *const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints"; ItkImageIO::ItkImageIO(const ItkImageIO &other) : AbstractFileIO(other), m_ImageIO(dynamic_cast(other.m_ImageIO->Clone().GetPointer())) { this->InitializeDefaultMetaDataKeys(); } std::vector ItkImageIO::FixUpImageIOExtensions(const std::string &imageIOName) { std::vector extensions; // Try to fix-up some known ITK image IO classes if (imageIOName == "GiplImageIO") { extensions.push_back("gipl"); extensions.push_back("gipl.gz"); } else if (imageIOName == "GDCMImageIO") { extensions.push_back("gdcm"); extensions.push_back("dcm"); extensions.push_back("DCM"); extensions.push_back("dc3"); extensions.push_back("DC3"); extensions.push_back("ima"); extensions.push_back("img"); } else if (imageIOName == "PNGImageIO") { extensions.push_back("png"); extensions.push_back("PNG"); } else if (imageIOName == "StimulateImageIO") { extensions.push_back("spr"); } else if (imageIOName == "HDF5ImageIO") { extensions.push_back("hdf"); extensions.push_back("h4"); extensions.push_back("hdf4"); extensions.push_back("h5"); extensions.push_back("hdf5"); extensions.push_back("he4"); extensions.push_back("he5"); extensions.push_back("hd5"); } else if ("GE4ImageIO" == imageIOName || "GE5ImageIO" == imageIOName || "Bruker2dseqImageIO" == imageIOName) { extensions.push_back(""); } if (!extensions.empty()) { MITK_DEBUG << "Fixing up known extensions for " << imageIOName; } return extensions; } void ItkImageIO::FixUpCustomMimeTypeName(const std::string &imageIOName, CustomMimeType &customMimeType) { if ("GE4ImageIO" == imageIOName) { customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge4"); } else if ("GE5ImageIO" == imageIOName) { customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "ge5"); } else if ("Bruker2dseqImageIO" == imageIOName) { customMimeType.SetName(this->AbstractFileReader::GetMimeTypePrefix() + "bruker2dseq"); } } ItkImageIO::ItkImageIO(itk::ImageIOBase::Pointer imageIO) : AbstractFileIO(Image::GetStaticNameOfClass()), m_ImageIO(imageIO) { if (m_ImageIO.IsNull()) { mitkThrow() << "ITK ImageIOBase argument must not be nullptr"; } this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image."); this->InitializeDefaultMetaDataKeys(); std::vector readExtensions = m_ImageIO->GetSupportedReadExtensions(); if (readExtensions.empty()) { std::string imageIOName = m_ImageIO->GetNameOfClass(); MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide read extensions"; readExtensions = FixUpImageIOExtensions(imageIOName); } CustomMimeType customReaderMimeType; customReaderMimeType.SetCategory("Images"); for (std::vector::const_iterator iter = readExtensions.begin(), endIter = readExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin() + 1, iter->end()); } customReaderMimeType.AddExtension(extension); } auto extensions = customReaderMimeType.GetExtensions(); if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty())) { std::string imageIOName = m_ImageIO->GetNameOfClass(); FixUpCustomMimeTypeName(imageIOName, customReaderMimeType); } this->AbstractFileReader::SetMimeType(customReaderMimeType); std::vector writeExtensions = imageIO->GetSupportedWriteExtensions(); if (writeExtensions.empty()) { std::string imageIOName = imageIO->GetNameOfClass(); MITK_DEBUG << "ITK ImageIOBase " << imageIOName << " does not provide write extensions"; writeExtensions = FixUpImageIOExtensions(imageIOName); } if (writeExtensions != readExtensions) { CustomMimeType customWriterMimeType; customWriterMimeType.SetCategory("Images"); for (std::vector::const_iterator iter = writeExtensions.begin(), endIter = writeExtensions.end(); iter != endIter; ++iter) { std::string extension = *iter; if (!extension.empty() && extension[0] == '.') { extension.assign(iter->begin() + 1, iter->end()); } customWriterMimeType.AddExtension(extension); } auto extensions = customWriterMimeType.GetExtensions(); if (extensions.empty() || (extensions.size() == 1 && extensions[0].empty())) { std::string imageIOName = m_ImageIO->GetNameOfClass(); FixUpCustomMimeTypeName(imageIOName, customWriterMimeType); } this->AbstractFileWriter::SetMimeType(customWriterMimeType); } std::string description = std::string("ITK ") + imageIO->GetNameOfClass(); this->SetReaderDescription(description); this->SetWriterDescription(description); this->RegisterService(); } ItkImageIO::ItkImageIO(const CustomMimeType &mimeType, itk::ImageIOBase::Pointer imageIO, int rank) : AbstractFileIO(Image::GetStaticNameOfClass(), mimeType, std::string("ITK ") + imageIO->GetNameOfClass()), m_ImageIO(imageIO) { if (m_ImageIO.IsNull()) { mitkThrow() << "ITK ImageIOBase argument must not be nullptr"; } this->AbstractFileReader::SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".image."); this->InitializeDefaultMetaDataKeys(); if (rank) { this->AbstractFileReader::SetRanking(rank); this->AbstractFileWriter::SetRanking(rank); } this->RegisterService(); } std::vector ConvertMetaDataObjectToTimePointList(const itk::MetaDataObjectBase* data) { const auto* timeGeometryTimeData = dynamic_cast*>(data); std::vector result; if (timeGeometryTimeData) { std::string dataStr = timeGeometryTimeData->GetMetaDataObjectValue(); std::stringstream stream(dataStr); TimePointType tp; while (stream >> tp) { result.push_back(tp); } } return result; }; itk::MetaDataObjectBase::Pointer ConvertTimePointListToMetaDataObject(const mitk::TimeGeometry* timeGeometry) { std::stringstream stream; stream << timeGeometry->GetTimeBounds(0)[0]; const auto maxTimePoints = timeGeometry->CountTimeSteps(); for (TimeStepType pos = 0; pos < maxTimePoints; ++pos) { stream << " " << timeGeometry->GetTimeBounds(pos)[1]; } auto result = itk::MetaDataObject::New(); result->SetMetaDataObjectValue(stream.str()); return result.GetPointer(); }; - std::vector ItkImageIO::Read() + std::vector ItkImageIO::DoRead() { std::vector result; mitk::LocaleSwitch localeSwitch("C"); Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; const std::string path = this->GetLocalFileName(); MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << 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 "; } // Got to allocate space for the image. Determine the characteristics of // the image. m_ImageIO->SetFileName(path); m_ImageIO->ReadImageInformation(); unsigned int ndim = m_ImageIO->GetNumberOfDimensions(); if (ndim < MINDIM || ndim > MAXDIM) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion(ndim); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[MAXDIM]; dimensions[0] = 0; dimensions[1] = 0; dimensions[2] = 0; dimensions[3] = 0; ScalarType spacing[MAXDIM]; spacing[0] = 1.0f; spacing[1] = 1.0f; spacing[2] = 1.0f; spacing[3] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for (i = 0; i < ndim; ++i) { ioStart[i] = 0; ioSize[i] = m_ImageIO->GetDimensions(i); if (i < MAXDIM) { dimensions[i] = m_ImageIO->GetDimensions(i); spacing[i] = m_ImageIO->GetSpacing(i); if (spacing[i] <= 0) spacing[i] = 1.0f; } if (i < 3) { origin[i] = m_ImageIO->GetOrigin(i); } } ioRegion.SetSize(ioSize); ioRegion.SetIndex(ioStart); MITK_INFO << "ioRegion: " << ioRegion << std::endl; m_ImageIO->SetIORegion(ioRegion); void *buffer = new unsigned char[m_ImageIO->GetImageSizeInBytes()]; m_ImageIO->Read(buffer); image->Initialize(MakePixelType(m_ImageIO), ndim, dimensions); image->SetImportChannel(buffer, 0, Image::ManageMemory); const itk::MetaDataDictionary &dictionary = m_ImageIO->GetMetaDataDictionary(); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim); for (i = 0; i < itkDimMax3; ++i) for (j = 0; j < itkDimMax3; ++j) matrix[i][j] = m_ImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false); MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true); // re-initialize TimeGeometry TimeGeometry::Pointer timeGeometry; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE)) { // also check for the name because of backwards compatibility. Past code version stored with the name and not with // the key itk::MetaDataObject::ConstPointer timeGeometryTypeData = nullptr; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE)) { timeGeometryTypeData = dynamic_cast *>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE)); } else { timeGeometryTypeData = dynamic_cast *>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE)); } if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass()) { MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass(); typedef std::vector TimePointVector; TimePointVector timePoints; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)); } else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)); } if (timePoints.empty()) { MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback"; } else if (timePoints.size() - 1 != image->GetDimension(3)) { MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension (" << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback"; } else { ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New(); TimePointVector::const_iterator pos = timePoints.begin(); auto prePos = pos++; for (; pos != timePoints.end(); ++prePos, ++pos) { arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos); } timeGeometry = arbitraryTimeGeometry; } } } if (timeGeometry.IsNull()) { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass(); ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); timeGeometry = propTimeGeometry; } image->SetTimeGeometry(timeGeometry); buffer = nullptr; MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents(); for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { const std::string &key = iter->first; std::string assumedPropertyName = key; std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.'); std::string mimeTypeName = GetMimeType()->GetName(); // Check if there is already a info for the key and our mime type. mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key); auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer &x) { return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName; }; auto finding = std::find_if(infoList.begin(), infoList.end(), predicate); if (finding == infoList.end()) { auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer &x) { return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; finding = std::find_if(infoList.begin(), infoList.end(), predicateWild); } PropertyPersistenceInfo::ConstPointer info; if (finding != infoList.end()) { assumedPropertyName = (*finding)->GetName(); info = *finding; } else { // we have not found anything suitable so we generate our own info auto newInfo = PropertyPersistenceInfo::New(); newInfo->SetNameAndKey(assumedPropertyName, key); newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); info = newInfo; } std::string value = dynamic_cast *>(iter->second.GetPointer())->GetMetaDataObjectValue(); mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value); image->SetProperty(assumedPropertyName.c_str(), loadedProp); // Read properties should be persisted unless they are default properties // which are written anyway bool isDefaultKey(false); for (const auto &defaultKey : m_DefaultMetaDataKeys) { if (defaultKey.length() <= assumedPropertyName.length()) { // does the start match the default key if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos) { isDefaultKey = true; break; } } } if (!isDefaultKey) { propPersistenceService->AddInfo(info); } } } MITK_INFO << "...finished!"; result.push_back(image.GetPointer()); return result; } AbstractFileIO::ConfidenceLevel ItkImageIO::GetReaderConfidenceLevel() const { return m_ImageIO->CanReadFile(GetLocalFileName().c_str()) ? IFileReader::Supported : IFileReader::Unsupported; } void ItkImageIO::Write() { const auto *image = dynamic_cast(this->GetInput()); if (image == nullptr) { mitkThrow() << "Cannot write non-image data"; } // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); // Clone the image geometry, because we might have to change it // for writing purposes BaseGeometry::Pointer geometry = image->GetGeometry()->Clone(); // Check if geometry information will be lost if (image->GetDimension() == 2 && !geometry->Is2DConvertable()) { MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might " "consider using Convert2Dto3DImageFilter before saving."; // set matrix to identity mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); mitk::Vector3D spacing = geometry->GetSpacing(); mitk::Point3D origin = geometry->GetOrigin(); geometry->SetIndexToWorldTransform(affTrans); geometry->SetSpacing(spacing); geometry->SetOrigin(origin); } LocalFile localFile(this); const std::string path = localFile.GetFileName(); MITK_INFO << "Writing image: " << path << std::endl; try { // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. const unsigned int dimension = image->GetDimension(); const unsigned int *const dimensions = image->GetDimensions(); const mitk::PixelType pixelType = image->GetPixelType(); const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); const mitk::Point3D mitkOrigin = geometry->GetOrigin(); // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, // though they are not supported in MITK itk::Vector spacing4D; spacing4D[0] = mitkSpacing[0]; spacing4D[1] = mitkSpacing[1]; spacing4D[2] = mitkSpacing[2]; spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here itk::Vector origin4D; origin4D[0] = mitkOrigin[0]; origin4D[1] = mitkOrigin[1]; origin4D[2] = mitkOrigin[2]; origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here // Set the necessary information for imageIO m_ImageIO->SetNumberOfDimensions(dimension); m_ImageIO->SetPixelType(pixelType.GetPixelType()); m_ImageIO->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? static_cast(pixelType.GetComponentType()) : itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); m_ImageIO->SetNumberOfComponents(pixelType.GetNumberOfComponents()); itk::ImageIORegion ioRegion(dimension); for (unsigned int i = 0; i < dimension; i++) { m_ImageIO->SetDimensions(i, dimensions[i]); m_ImageIO->SetSpacing(i, spacing4D[i]); m_ImageIO->SetOrigin(i, origin4D[i]); mitk::Vector3D mitkDirection; mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); itk::Vector direction4D; direction4D[0] = mitkDirection[0]; direction4D[1] = mitkDirection[1]; direction4D[2] = mitkDirection[2]; // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. if (i == 3) { direction4D[3] = 1; // homogenous component } else { direction4D[3] = 0; } vnl_vector axisDirection(dimension); for (unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction4D[j] / spacing4D[i]; } m_ImageIO->SetDirection(i, axisDirection); ioRegion.SetSize(i, image->GetLargestPossibleRegion().GetSize(i)); ioRegion.SetIndex(i, image->GetLargestPossibleRegion().GetIndex(i)); } // use compression if available m_ImageIO->UseCompressionOn(); m_ImageIO->SetIORegion(ioRegion); m_ImageIO->SetFileName(path); // Handle time geometry const auto *arbitraryTG = dynamic_cast(image->GetTimeGeometry()); if (arbitraryTG) { itk::EncapsulateMetaData(m_ImageIO->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TYPE, ArbitraryTimeGeometry::GetStaticNameOfClass()); auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG); m_ImageIO->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints); } // Handle properties mitk::PropertyList::Pointer imagePropertyList = image->GetPropertyList(); for (const auto &property : *imagePropertyList->GetMap()) { mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true); if (infoList.empty()) { continue; } std::string value = infoList.front()->GetSerializationFunction()(property.second); if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING) { continue; } std::string key = infoList.front()->GetKey(); itk::EncapsulateMetaData(m_ImageIO->GetMetaDataDictionary(), key, value); } ImageReadAccessor imageAccess(image); LocaleSwitch localeSwitch2("C"); m_ImageIO->Write(imageAccess.GetData()); } catch (const std::exception &e) { mitkThrow() << e.what(); } } AbstractFileIO::ConfidenceLevel ItkImageIO::GetWriterConfidenceLevel() const { // Check if the image dimension is supported const auto *image = dynamic_cast(this->GetInput()); if (image == nullptr) { // We cannot write a null object, DUH! return IFileWriter::Unsupported; } if (!m_ImageIO->SupportsDimension(image->GetDimension())) { // okay, dimension is not supported. We have to look at a special case: // 3D-Image with one slice. We can treat that as a 2D image. if ((image->GetDimension() == 3) && (image->GetSlicedGeometry()->GetSlices() == 1)) return IFileWriter::Supported; else return IFileWriter::Unsupported; } // Check if geometry information will be lost if (image->GetDimension() == 2 && !image->GetGeometry()->Is2DConvertable()) { return IFileWriter::PartiallySupported; } return IFileWriter::Supported; } ItkImageIO *ItkImageIO::IOClone() const { return new ItkImageIO(*this); } void ItkImageIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); } } diff --git a/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp b/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp index f206c43d22..d9abfa1bae 100644 --- a/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp +++ b/Modules/Core/src/IO/mitkLegacyFileReaderService.cpp @@ -1,113 +1,113 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkLegacyFileReaderService.h" #include #include #include #include mitk::LegacyFileReaderService::LegacyFileReaderService(const mitk::LegacyFileReaderService &other) : mitk::AbstractFileReader(other) { } mitk::LegacyFileReaderService::LegacyFileReaderService(const std::vector &extensions, const std::string &category) : AbstractFileReader() { this->SetMimeTypePrefix(IOMimeTypes::DEFAULT_BASE_NAME() + ".legacy."); CustomMimeType customMimeType; customMimeType.SetCategory(category); for (auto extension : extensions) { if (!extension.empty() && extension[0] == '.') { extension.assign(extension.begin() + 1, extension.end()); } customMimeType.AddExtension(extension); } this->SetDescription(category); this->SetMimeType(customMimeType); m_ServiceReg = this->RegisterService(); } mitk::LegacyFileReaderService::~LegacyFileReaderService() { } ////////////////////// Reading ///////////////////////// -std::vector> mitk::LegacyFileReaderService::Read() +std::vector> mitk::LegacyFileReaderService::DoRead() { std::vector result; std::list possibleIOAdapter; std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("mitkIOAdapter"); for (auto i = allobjects.begin(); i != allobjects.end(); ++i) { auto *io = dynamic_cast(i->GetPointer()); if (io) { possibleIOAdapter.push_back(io); } else { MITK_ERROR << "Error BaseDataIO factory did not return an IOAdapterBase: " << (*i)->GetNameOfClass() << std::endl; } } const std::string path = this->GetLocalFileName(); for (auto k = possibleIOAdapter.begin(); k != possibleIOAdapter.end(); ++k) { bool canReadFile = (*k)->CanReadFile(path, "", ""); // they could read the file if (canReadFile) { BaseDataSource::Pointer ioObject = (*k)->CreateIOProcessObject(path, "", ""); ioObject->Update(); auto numberOfContents = static_cast(ioObject->GetNumberOfOutputs()); if (numberOfContents > 0) { BaseData::Pointer baseData; for (int i = 0; i < numberOfContents; ++i) { baseData = dynamic_cast(ioObject->GetOutputs()[i].GetPointer()); if (baseData) // this is what's wanted, right? { result.push_back(baseData); } } } break; } } if (result.empty()) { mitkThrow() << "Could not read file '" << path << "'"; } return result; } mitk::LegacyFileReaderService *mitk::LegacyFileReaderService::Clone() const { return new LegacyFileReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkLegacyFileReaderService.h b/Modules/Core/src/IO/mitkLegacyFileReaderService.h index 598220201a..096ba02263 100644 --- a/Modules/Core/src/IO/mitkLegacyFileReaderService.h +++ b/Modules/Core/src/IO/mitkLegacyFileReaderService.h @@ -1,42 +1,44 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKLEGACYFILEREADERSERVICE_H #define MITKLEGACYFILEREADERSERVICE_H #include namespace mitk { // This class wraps mitk::FileReader instances registered as // "mitkIOAdapter" via the ITK object factory system as a // micro service. class LegacyFileReaderService : public mitk::AbstractFileReader { public: LegacyFileReaderService(const LegacyFileReaderService &other); LegacyFileReaderService(const std::vector &extensions, const std::string &category); ~LegacyFileReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; + + protected: + std::vector> DoRead() override; private: LegacyFileReaderService *Clone() const override; us::ServiceRegistration m_ServiceReg; }; } // namespace mitk #endif /* MITKLEGACYFILEREADERSERVICE_H */ diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.cpp b/Modules/Core/src/IO/mitkPointSetReaderService.cpp index 24dac6ba8c..68cc84f562 100644 --- a/Modules/Core/src/IO/mitkPointSetReaderService.cpp +++ b/Modules/Core/src/IO/mitkPointSetReaderService.cpp @@ -1,275 +1,275 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkPointSetReaderService.h" #include "mitkGeometry3DToXML.h" #include "mitkIOMimeTypes.h" #include "mitkProportionalTimeGeometry.h" // STL #include #include #include #include mitk::PointSetReaderService::PointSetReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::POINTSET_MIMETYPE()), "MITK Point Set Reader") { RegisterService(); } mitk::PointSetReaderService::~PointSetReaderService() { } -std::vector> mitk::PointSetReaderService::Read() +std::vector> mitk::PointSetReaderService::DoRead() { // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); std::vector> 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 != nullptr; 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") != nullptr) { for (TiXmlElement *currentTimeSeries = currentPointSetElement->FirstChildElement("time_series")->ToElement(); currentTimeSeries != nullptr; 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::BaseGeometry::Pointer mitk::PointSetReaderService::ReadGeometry(TiXmlElement *parentElement) { TiXmlElement *geometryElem = parentElement->FirstChildElement("geometry3d"); if (!geometryElem) return nullptr; // data to generate AffineTransform3D::MatrixType matrix; AffineTransform3D::OffsetType offset; bool isImageGeometry(false); unsigned int frameOfReferenceID(0); BaseGeometry::BoundsArrayType bounds; bool somethingMissing(false); // find data in xml structure TiXmlElement *imageGeometryElem = geometryElem->FirstChildElement("image_geometry"); if (imageGeometryElem) { std::string igs = imageGeometryElem->GetText(); isImageGeometry = igs == "true" || igs == "TRUE" || igs == "1"; } else somethingMissing = true; TiXmlElement *frameOfReferenceElem = geometryElem->FirstChildElement("frame_of_reference_id"); if (frameOfReferenceElem) { frameOfReferenceID = atoi(frameOfReferenceElem->GetText()); } else somethingMissing = true; TiXmlElement *indexToWorldElem = geometryElem->FirstChildElement("index_to_world"); if (indexToWorldElem) { TiXmlElement *matrixElem = indexToWorldElem->FirstChildElement("matrix3x3"); TiXmlElement *offsetElem = indexToWorldElem->FirstChildElement("offset"); if (indexToWorldElem && offsetElem) { TiXmlElement *col0 = matrixElem->FirstChildElement("column_0"); TiXmlElement *col1 = matrixElem->FirstChildElement("column_1"); TiXmlElement *col2 = matrixElem->FirstChildElement("column_2"); if (col0 && col1 && col2) { somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("x", &matrix[0][0]); somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("y", &matrix[1][0]); somethingMissing |= TIXML_SUCCESS != col0->QueryDoubleAttribute("z", &matrix[2][0]); somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("x", &matrix[0][1]); somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("y", &matrix[1][1]); somethingMissing |= TIXML_SUCCESS != col1->QueryDoubleAttribute("z", &matrix[2][1]); somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("x", &matrix[0][2]); somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("y", &matrix[1][2]); somethingMissing |= TIXML_SUCCESS != col2->QueryDoubleAttribute("z", &matrix[2][2]); } else somethingMissing = true; somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("x", &offset[0]); somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("y", &offset[1]); somethingMissing |= TIXML_SUCCESS != offsetElem->QueryDoubleAttribute("z", &offset[2]); } else somethingMissing = true; TiXmlElement *boundsElem = geometryElem->FirstChildElement("bounds"); if (boundsElem) { TiXmlElement *minBoundsElem = boundsElem->FirstChildElement("min"); TiXmlElement *maxBoundsElem = boundsElem->FirstChildElement("max"); if (minBoundsElem && maxBoundsElem) { somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("x", &bounds[0]); somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("y", &bounds[2]); somethingMissing |= TIXML_SUCCESS != minBoundsElem->QueryDoubleAttribute("z", &bounds[4]); somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("x", &bounds[1]); somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("y", &bounds[3]); somethingMissing |= TIXML_SUCCESS != maxBoundsElem->QueryDoubleAttribute("z", &bounds[5]); } else somethingMissing = true; } else somethingMissing = true; } else somethingMissing = true; if (somethingMissing) { MITK_ERROR << "XML structure of geometry inside a PointSet file broken. Refusing to build Geometry3D"; return nullptr; } else { Geometry3D::Pointer g = Geometry3D::New(); g->SetImageGeometry(isImageGeometry); g->SetFrameOfReferenceID(frameOfReferenceID); g->SetBounds(bounds); AffineTransform3D::Pointer transform = AffineTransform3D::New(); transform->SetMatrix(matrix); transform->SetOffset(offset); g->SetIndexToWorldTransform(transform); return g.GetPointer(); } } mitk::PointSet::Pointer mitk::PointSetReaderService::ReadPoints(mitk::PointSet::Pointer newPointSet, TiXmlElement *currentTimeSeries, unsigned int currentTimeStep) { if (currentTimeSeries->FirstChildElement("point") != nullptr) { for (TiXmlElement *currentPoint = currentTimeSeries->FirstChildElement("point")->ToElement(); currentPoint != nullptr; currentPoint = currentPoint->NextSiblingElement()) { unsigned int id(0); auto spec((mitk::PointSpecificationType)0); double x(0.0); double y(0.0); double z(0.0); id = atoi(currentPoint->FirstChildElement("id")->GetText()); if (currentPoint->FirstChildElement("specification") != nullptr) { spec = (mitk::PointSpecificationType)atoi(currentPoint->FirstChildElement("specification")->GetText()); } x = atof(currentPoint->FirstChildElement("x")->GetText()); y = atof(currentPoint->FirstChildElement("y")->GetText()); z = atof(currentPoint->FirstChildElement("z")->GetText()); mitk::Point3D point; mitk::FillVector3D(point, x, y, z); newPointSet->SetPoint(id, point, spec, currentTimeStep); } } else { if (currentTimeStep != newPointSet->GetTimeSteps() + 1) { newPointSet->Expand(currentTimeStep + 1); // expand time step series with empty time step } } return newPointSet; } mitk::PointSetReaderService::PointSetReaderService(const mitk::PointSetReaderService &other) : mitk::AbstractFileReader(other) { } mitk::PointSetReaderService *mitk::PointSetReaderService::Clone() const { return new mitk::PointSetReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkPointSetReaderService.h b/Modules/Core/src/IO/mitkPointSetReaderService.h index 42854d4aec..5aba51b592 100644 --- a/Modules/Core/src/IO/mitkPointSetReaderService.h +++ b/Modules/Core/src/IO/mitkPointSetReaderService.h @@ -1,60 +1,62 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_POINT_SET_READER_SERVICE__H_ #define _MITK_POINT_SET_READER_SERVICE__H_ // MITK #include #include class TiXmlElement; namespace mitk { /** * @internal * * @brief reads xml representations of mitk::PointSets from a file * * Reader for xml files containing one or multiple xml represenations of * mitk::PointSet. If multiple mitk::PointSet objects are stored in one file, * these are assigned to multiple BaseData objects. * * The reader is able to read the old 3D Pointsets without the "specification" and "timeseries" tags and the new 4D * Pointsets. * * @ingroup IO */ class PointSetReaderService : public AbstractFileReader { public: PointSetReaderService(); ~PointSetReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; + + protected: + std::vector> DoRead() override; private: PointSetReaderService(const PointSetReaderService &other); mitk::BaseGeometry::Pointer ReadGeometry(TiXmlElement *parentElement); mitk::PointSet::Pointer ReadPoints(mitk::PointSet::Pointer newPointSet, TiXmlElement *currentTimeSeries, unsigned int currentTimeStep); PointSetReaderService *Clone() const override; }; } #endif diff --git a/Modules/Core/src/IO/mitkRawImageFileReader.cpp b/Modules/Core/src/IO/mitkRawImageFileReader.cpp index 7bb6559e8c..ee98b414be 100644 --- a/Modules/Core/src/IO/mitkRawImageFileReader.cpp +++ b/Modules/Core/src/IO/mitkRawImageFileReader.cpp @@ -1,198 +1,198 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkRawImageFileReader.h" #include "mitkIOConstants.h" #include "mitkIOMimeTypes.h" #include "mitkITKImageImport.h" #include "mitkImageCast.h" #include #include #include mitk::RawImageFileReaderService::RawImageFileReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::RAW_MIMETYPE()), "ITK raw image reader") { Options defaultOptions; defaultOptions[IOConstants::PIXEL_TYPE()] = IOConstants::PIXEL_TYPE_USHORT(); std::vector pixelEnum; pixelEnum.push_back(IOConstants::PIXEL_TYPE_UCHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_CHAR()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_USHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_SHORT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_UINT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_INT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_FLOAT()); pixelEnum.push_back(IOConstants::PIXEL_TYPE_DOUBLE()); defaultOptions[IOConstants::PIXEL_TYPE_ENUM()] = pixelEnum; defaultOptions[IOConstants::DIMENSION()] = std::string("3"); std::vector dimEnum; dimEnum.push_back("2"); dimEnum.push_back("3"); defaultOptions[IOConstants::DIMENSION_ENUM()] = dimEnum; defaultOptions[IOConstants::ENDIANNESS()] = IOConstants::ENDIANNESS_LITTLE(); std::vector endianEnum; endianEnum.push_back(IOConstants::ENDIANNESS_LITTLE()); endianEnum.push_back(IOConstants::ENDIANNESS_BIG()); defaultOptions[IOConstants::ENDIANNESS_ENUM()] = endianEnum; defaultOptions[IOConstants::SIZE_X()] = 0; defaultOptions[IOConstants::SIZE_Y()] = 0; defaultOptions[IOConstants::SIZE_Z()] = 0; // defaultOptions[IOConstants::SIZE_T()] = 0; this->SetDefaultOptions(defaultOptions); this->RegisterService(); } mitk::RawImageFileReaderService::RawImageFileReaderService(const mitk::RawImageFileReaderService &other) : AbstractFileReader(other) { } -std::vector> mitk::RawImageFileReaderService::Read() +std::vector> mitk::RawImageFileReaderService::DoRead() { std::vector result; const std::string path = this->GetLocalFileName(); const Options options = this->GetOptions(); const std::string dimensionality = options.find(IOConstants::DIMENSION())->second.ToString(); const std::string pixelType = options.find(IOConstants::PIXEL_TYPE())->second.ToString(); EndianityType endianity = options.find(IOConstants::ENDIANNESS())->second.ToString() == IOConstants::ENDIANNESS_LITTLE() ? LITTLE : BIG; int dimensions[4]; dimensions[0] = us::any_cast(options.find(IOConstants::SIZE_X())->second); dimensions[1] = us::any_cast(options.find(IOConstants::SIZE_Y())->second); dimensions[2] = us::any_cast(options.find(IOConstants::SIZE_Z())->second); dimensions[3] = 0; // us::any_cast(options.find(IOConstants::SIZE_T())->second); // check file dimensionality and pixel type and perform reading according to it if (dimensionality == "2") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE()) result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else if (dimensionality == "3") { if (pixelType == IOConstants::PIXEL_TYPE_CHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UCHAR()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_SHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_USHORT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_UINT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_INT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_FLOAT()) result.push_back(TypedRead(path, endianity, dimensions)); else if (pixelType == IOConstants::PIXEL_TYPE_DOUBLE()) result.push_back(TypedRead(path, endianity, dimensions)); else { MITK_INFO << "Error while reading raw file: Dimensionality or pixel type not supported or not properly set" << std::endl; } } else { MITK_INFO << "Error while reading raw file: Dimensionality not supported" << std::endl; } return result; } template mitk::BaseData::Pointer mitk::RawImageFileReaderService::TypedRead(const std::string &path, EndianityType endianity, int *size) { typedef itk::Image ImageType; typedef itk::ImageFileReader ReaderType; typedef itk::RawImageIO IOType; typename ReaderType::Pointer reader = ReaderType::New(); typename IOType::Pointer io = IOType::New(); io->SetFileDimensionality(VImageDimensions); for (unsigned short int dim = 0; dim < VImageDimensions; ++dim) { io->SetDimensions(dim, size[dim]); } if (endianity == LITTLE) { io->SetByteOrderToLittleEndian(); } else if (endianity == BIG) { io->SetByteOrderToBigEndian(); } else { MITK_INFO << "Warning: endianity not properly set. Resulting image might be incorrect"; } reader->SetImageIO(io); reader->SetFileName(path); try { reader->Update(); } catch ( const itk::ExceptionObject &err ) { MITK_ERROR << "An error occurred during the raw image reading process: "; MITK_INFO << err.GetDescription() << std::endl; } mitk::Image::Pointer image = mitk::Image::New(); mitk::CastToMitkImage(reader->GetOutput(), image); image->SetVolume(reader->GetOutput()->GetBufferPointer()); return image.GetPointer(); } mitk::RawImageFileReaderService *mitk::RawImageFileReaderService::Clone() const { return new RawImageFileReaderService(*this); } diff --git a/Modules/Core/src/IO/mitkRawImageFileReader.h b/Modules/Core/src/IO/mitkRawImageFileReader.h index 4752290370..3ad97d9199 100644 --- a/Modules/Core/src/IO/mitkRawImageFileReader.h +++ b/Modules/Core/src/IO/mitkRawImageFileReader.h @@ -1,54 +1,54 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKRAWIMAGEFILEREADER_H_ #define MITKRAWIMAGEFILEREADER_H_ #include "mitkAbstractFileReader.h" namespace mitk { /** * The user must set the dimensionality, the dimensions and the pixel type. * If they are incorrect, the image will not be opened or the visualization will be incorrect. */ class RawImageFileReaderService : public AbstractFileReader { public: /** Supported pixel types. */ typedef enum { UCHAR, SCHAR, USHORT, SSHORT, UINT, SINT, FLOAT, DOUBLE } IOPixelType; /** Endianity of bits. */ typedef enum { LITTLE, BIG } EndianityType; RawImageFileReaderService(); protected: RawImageFileReaderService(const RawImageFileReaderService &other); - std::vector> Read() override; + std::vector> DoRead() override; using mitk::AbstractFileReader::Read; private: template mitk::BaseData::Pointer TypedRead(const std::string &path, EndianityType endianity, int *size); RawImageFileReaderService *Clone() const override; /** Vector containing dimensions of image to be read. */ itk::Vector m_Dimensions; }; } // namespace mitk #endif /* MITKRAWIMAGEFILEREADER_H_ */ diff --git a/Modules/Core/src/IO/mitkSurfaceStlIO.cpp b/Modules/Core/src/IO/mitkSurfaceStlIO.cpp index fa919c857a..e64e9a1634 100644 --- a/Modules/Core/src/IO/mitkSurfaceStlIO.cpp +++ b/Modules/Core/src/IO/mitkSurfaceStlIO.cpp @@ -1,160 +1,160 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSurfaceStlIO.h" #include "mitkIOMimeTypes.h" #include "mitkLocaleSwitch.h" #include "mitkSurface.h" #include #include #include #include #include #include #include namespace mitk { std::string SurfaceStlIO::OPTION_MERGE_POINTS() { static std::string s = "Merge points"; return s; } std::string SurfaceStlIO::OPTION_TAG_SOLIDS() { static std::string s = "Tag solids"; return s; } std::string SurfaceStlIO::OPTION_CLEAN() { static std::string s = "Clean poly data"; return s; } SurfaceStlIO::SurfaceStlIO() : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::STEREOLITHOGRAPHY_MIMETYPE(), "Stereolithography") { Options defaultOptions; defaultOptions[OPTION_MERGE_POINTS()] = us::Any(true); defaultOptions[OPTION_TAG_SOLIDS()] = us::Any(false); defaultOptions[OPTION_CLEAN()] = us::Any(true); this->SetDefaultReaderOptions(defaultOptions); this->RegisterService(); } - std::vector> SurfaceStlIO::Read() + std::vector> SurfaceStlIO::DoRead() { LocaleSwitch localeSwitch("C"); Options options = this->GetReaderOptions(); mitk::Surface::Pointer output = mitk::Surface::New(); vtkSmartPointer stlReader = vtkSmartPointer::New(); stlReader->SetFileName(this->GetLocalFileName().c_str()); bool mergePoints = true; bool tagSolids = false; bool cleanData = true; try { mergePoints = us::any_cast(options[OPTION_MERGE_POINTS()]); tagSolids = us::any_cast(options[OPTION_TAG_SOLIDS()]); cleanData = us::any_cast(options[OPTION_CLEAN()]); } catch (const us::BadAnyCastException &e) { MITK_WARN << "Unexpected error: " << e.what(); } stlReader->SetMerging(mergePoints); stlReader->SetScalarTags(tagSolids); vtkSmartPointer normalsGenerator = vtkSmartPointer::New(); normalsGenerator->SetInputConnection(stlReader->GetOutputPort()); vtkSmartPointer algo = normalsGenerator; if (cleanData) { vtkSmartPointer cleanPolyDataFilter = vtkSmartPointer::New(); cleanPolyDataFilter->SetInputConnection(normalsGenerator->GetOutputPort()); cleanPolyDataFilter->PieceInvariantOff(); cleanPolyDataFilter->ConvertLinesToPointsOff(); cleanPolyDataFilter->ConvertPolysToLinesOff(); cleanPolyDataFilter->ConvertStripsToPolysOff(); if (mergePoints) { cleanPolyDataFilter->PointMergingOn(); } algo = cleanPolyDataFilter; } algo->Update(); if (algo->GetOutput() != nullptr) { vtkSmartPointer surfaceWithNormals = algo->GetOutput(); output->SetVtkPolyData(surfaceWithNormals); } std::vector result; result.push_back(output.GetPointer()); return result; } void SurfaceStlIO::Write() { LocaleSwitch localeSwitch("C"); ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps(); for (unsigned int t = 0; t < timesteps; ++t) { std::string fileName; vtkSmartPointer polyData = this->GetPolyData(t, fileName); vtkSmartPointer triangleFilter = vtkSmartPointer::New(); triangleFilter->SetInputData(polyData); vtkSmartPointer writer = vtkSmartPointer::New(); writer->SetInputConnection(triangleFilter->GetOutputPort()); // The vtk stl writer cannot write to streams LocalFile localFile(this); writer->SetFileName(localFile.GetFileName().c_str()); if (writer->Write() == 0 || writer->GetErrorCode() != 0) { mitkThrow() << "Error during surface writing" << (writer->GetErrorCode() ? std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) : std::string()); } if (this->GetOutputStream() && input->GetTimeGeometry()->CountTimeSteps() > 1) { MITK_WARN << "Writing multiple time-steps to output streams is not supported. " << "Only the first time-step will be written"; break; } } } SurfaceStlIO *SurfaceStlIO::IOClone() const { return new SurfaceStlIO(*this); } } diff --git a/Modules/Core/src/IO/mitkSurfaceStlIO.h b/Modules/Core/src/IO/mitkSurfaceStlIO.h index 4d9ef51748..ffe36e1e60 100644 --- a/Modules/Core/src/IO/mitkSurfaceStlIO.h +++ b/Modules/Core/src/IO/mitkSurfaceStlIO.h @@ -1,43 +1,45 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_SURFACE_STL_IO_H_ #define _MITK_SURFACE_STL_IO_H_ #include "mitkSurfaceVtkIO.h" namespace mitk { class SurfaceStlIO : public mitk::SurfaceVtkIO { public: SurfaceStlIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector> Read() override; // -------------- AbstractFileWriter ------------- void Write() override; + protected: + std::vector> DoRead() override; + private: SurfaceStlIO *IOClone() const override; static std::string OPTION_MERGE_POINTS(); static std::string OPTION_TAG_SOLIDS(); static std::string OPTION_CLEAN(); }; } #endif //_MITK_SURFACE_STL_IO_H_ diff --git a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp index 36b25c483a..1dbc32bc49 100644 --- a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp +++ b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.cpp @@ -1,117 +1,117 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSurfaceVtkLegacyIO.h" #include "mitkIOMimeTypes.h" #include "mitkSurface.h" #include #include #include #include #include #include namespace mitk { SurfaceVtkLegacyIO::SurfaceVtkLegacyIO() : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::VTK_POLYDATA_LEGACY_MIMETYPE(), "VTK Legacy PolyData") { Options defaultOptions; defaultOptions["Save as binary file"] = false; this->SetDefaultWriterOptions(defaultOptions); this->RegisterService(); } - std::vector> SurfaceVtkLegacyIO::Read() + std::vector> SurfaceVtkLegacyIO::DoRead() { mitk::Surface::Pointer output = mitk::Surface::New(); // The legay vtk reader cannot work with input streams const std::string fileName = this->GetLocalFileName(); vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(fileName.c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { output->SetVtkPolyData(reader->GetOutput()); } else { mitkThrow() << "vtkPolyDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } std::vector result; result.push_back(output.GetPointer()); return result; } IFileIO::ConfidenceLevel SurfaceVtkLegacyIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(this->GetLocalFileName().c_str()); if (reader->IsFilePolyData()) { if (std::strcmp(reader->GetHeader(), "vtk output") == 0) { return Supported; } else return PartiallySupported; } return Unsupported; } void SurfaceVtkLegacyIO::Write() { ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps(); for (unsigned int t = 0; t < timesteps; ++t) { std::string fileName; vtkSmartPointer polyData = this->GetPolyData(t, fileName); vtkSmartPointer writer = vtkSmartPointer::New(); writer->SetInputData(polyData); if (us::any_cast(GetWriterOption("Save as binary file"))) { writer->SetFileTypeToBinary(); } // The legacy vtk poly data writer cannot write to streams LocalFile localFile(this); writer->SetFileName(localFile.GetFileName().c_str()); if (writer->Write() == 0 || writer->GetErrorCode() != 0) { mitkThrow() << "Error during surface writing" << (writer->GetErrorCode() ? std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) : std::string()); } if (this->GetOutputStream() && input->GetTimeGeometry()->CountTimeSteps() > 1) { MITK_WARN << "Writing multiple time-steps to output streams is not supported. " << "Only the first time-step will be written"; break; } } } SurfaceVtkLegacyIO *SurfaceVtkLegacyIO::IOClone() const { return new SurfaceVtkLegacyIO(*this); } } diff --git a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h index f9e0c062e1..7be88eaceb 100644 --- a/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h +++ b/Modules/Core/src/IO/mitkSurfaceVtkLegacyIO.h @@ -1,43 +1,45 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_SURFACE_VTK_LEGACY_IO_H_ #define _MITK_SURFACE_VTK_LEGACY_IO_H_ #include "mitkSurfaceVtkIO.h" #include "mitkBaseData.h" namespace mitk { class SurfaceVtkLegacyIO : public mitk::SurfaceVtkIO { public: SurfaceVtkLegacyIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; + protected: + std::vector> DoRead() override; + private: SurfaceVtkLegacyIO *IOClone() const override; }; } #endif //_MITK_SURFACE_VTK_LEGACY_IO_H_ diff --git a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp index 394ab06b25..5b05614279 100644 --- a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp +++ b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.cpp @@ -1,152 +1,152 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSurfaceVtkXmlIO.h" #include "mitkIOMimeTypes.h" #include "mitkSurface.h" #include #include #include #include namespace mitk { class VtkXMLPolyDataReader : public ::vtkXMLPolyDataReader { public: static VtkXMLPolyDataReader *New() { return new VtkXMLPolyDataReader(); } vtkTypeMacro(VtkXMLPolyDataReader, vtkXMLPolyDataReader) void SetStream(std::istream *is) { this->Stream = is; } std::istream *GetStream() const { return this->Stream; } }; class VtkXMLPolyDataWriter : public ::vtkXMLPolyDataWriter { public: static VtkXMLPolyDataWriter *New() { return new VtkXMLPolyDataWriter(); } vtkTypeMacro(VtkXMLPolyDataWriter, vtkXMLPolyDataWriter) void SetStream(std::ostream *os) { this->Stream = os; } std::ostream *GetStream() const { return this->Stream; } }; SurfaceVtkXmlIO::SurfaceVtkXmlIO() : SurfaceVtkIO(Surface::GetStaticNameOfClass(), IOMimeTypes::VTK_POLYDATA_MIMETYPE(), "VTK XML PolyData") { this->RegisterService(); } - std::vector> SurfaceVtkXmlIO::Read() + std::vector> SurfaceVtkXmlIO::DoRead() { mitk::Surface::Pointer output = mitk::Surface::New(); vtkSmartPointer reader = vtkSmartPointer::New(); if (this->GetInputStream()) { reader->SetStream(this->GetInputStream()); } else { reader->SetFileName(this->GetInputLocation().c_str()); } reader->Update(); if (reader->GetOutput() != nullptr) { output->SetVtkPolyData(reader->GetOutput()); } else { mitkThrow() << "vtkXMLPolyDataReader error: " << vtkErrorCode::GetStringFromErrorCode(reader->GetErrorCode()); } std::vector result; result.push_back(output.GetPointer()); return result; } IFileIO::ConfidenceLevel SurfaceVtkXmlIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; if (this->GetInputStream() == nullptr) { // check if the xml vtk reader can handle the file vtkSmartPointer xmlReader = vtkSmartPointer::New(); if (xmlReader->CanReadFile(this->GetInputLocation().c_str()) != 0) { return Supported; } return Unsupported; } // in case of an input stream, VTK does not seem to have methods for // validating it return Supported; } void SurfaceVtkXmlIO::Write() { ValidateOutputLocation(); const auto *input = dynamic_cast(this->GetInput()); const unsigned int timesteps = input->GetTimeGeometry()->CountTimeSteps(); for (unsigned int t = 0; t < timesteps; ++t) { std::string fileName; vtkSmartPointer polyData = this->GetPolyData(t, fileName); if (polyData.Get() == nullptr) { mitkThrow() << "Cannot write empty surface"; } vtkSmartPointer writer = vtkSmartPointer::New(); writer->SetInputData(polyData); if (this->GetOutputStream()) { if (input->GetTimeGeometry()->CountTimeSteps() > 1) { MITK_WARN << "Writing multiple time-steps to output streams is not supported. " << "Only the first time-step will be written"; } writer->SetStream(this->GetOutputStream()); } else { writer->SetFileName(fileName.c_str()); } if (writer->Write() == 0 || writer->GetErrorCode() != 0) { mitkThrow() << "Error during surface writing" << (writer->GetErrorCode() ? std::string(": ") + vtkErrorCode::GetStringFromErrorCode(writer->GetErrorCode()) : std::string()); } if (this->GetOutputStream()) break; } } SurfaceVtkXmlIO *SurfaceVtkXmlIO::IOClone() const { return new SurfaceVtkXmlIO(*this); } } diff --git a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h index 5fb62f41d6..ed4daa3a49 100644 --- a/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h +++ b/Modules/Core/src/IO/mitkSurfaceVtkXmlIO.h @@ -1,43 +1,45 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_SURFACE_VTK_XML_IO_H_ #define _MITK_SURFACE_VTK_XML_IO_H_ #include "mitkSurfaceVtkIO.h" #include "mitkBaseData.h" namespace mitk { class SurfaceVtkXmlIO : public mitk::SurfaceVtkIO { public: SurfaceVtkXmlIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; + protected: + std::vector> DoRead() override; + private: SurfaceVtkXmlIO *IOClone() const override; }; } #endif //_MITK_SURFACE_VTK_XML_IO_H_ diff --git a/Modules/Core/src/mitkCoreActivator.cpp b/Modules/Core/src/mitkCoreActivator.cpp index 17a64bf8ae..4e2a3363d9 100644 --- a/Modules/Core/src/mitkCoreActivator.cpp +++ b/Modules/Core/src/mitkCoreActivator.cpp @@ -1,321 +1,357 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkCoreActivator.h" +#include +#include + // File IO +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkLegacyFileWriterService.h" #include #include #include // Micro Services #include #include #include #include #include #include #include #include #include #include // ITK "injects" static initialization code for IO factories // via the itkImageIOFactoryRegisterManager.h header (which // is generated in the application library build directory). // To ensure that the code is called *before* the CppMicroServices // static initialization code (which triggers the Activator::Start // method), we include the ITK header here. #include void HandleMicroServicesMessages(us::MsgType type, const char *msg) { switch (type) { case us::DebugMsg: MITK_DEBUG << msg; break; case us::InfoMsg: MITK_INFO << msg; break; case us::WarningMsg: MITK_WARN << msg; break; case us::ErrorMsg: MITK_ERROR << msg; break; } } void AddMitkAutoLoadPaths(const std::string &programPath) { us::ModuleSettings::AddAutoLoadPath(programPath); #ifdef __APPLE__ // Walk up three directories since that is where the .dylib files are located // for build trees. std::string additionalPath = programPath; bool addPath = true; for (int i = 0; i < 3; ++i) { std::size_t index = additionalPath.find_last_of('/'); if (index != std::string::npos) { additionalPath = additionalPath.substr(0, index); } else { addPath = false; break; } } if (addPath) { us::ModuleSettings::AddAutoLoadPath(additionalPath); } #endif } +void AddPropertyPersistence(const mitk::PropertyKeyPath& propPath) +{ + mitk::CoreServicePointer persistenceService(mitk::CoreServices::GetPropertyPersistence()); + + auto info = mitk::PropertyPersistenceInfo::New(); + if (propPath.IsExplicit()) + { + std::string name = mitk::PropertyKeyPathToPropertyName(propPath); + std::string key = name; + std::replace(key.begin(), key.end(), '.', '_'); + info->SetNameAndKey(name, key); + } + else + { + std::string key = mitk::PropertyKeyPathToPersistenceKeyRegEx(propPath); + std::string keyTemplate = mitk::PropertyKeyPathToPersistenceKeyTemplate(propPath); + std::string propRegEx = mitk::PropertyKeyPathToPropertyRegEx(propPath); + std::string propTemplate = mitk::PropertyKeyPathToPersistenceNameTemplate(propPath); + info->UseRegEx(propRegEx, propTemplate, key, keyTemplate); + } + + persistenceService->AddInfo(info); +} + class FixedNiftiImageIO : public itk::NiftiImageIO { public: /** Standard class typedefs. */ typedef FixedNiftiImageIO Self; typedef itk::NiftiImageIO Superclass; typedef itk::SmartPointer Pointer; /** Method for creation through the object factory. */ itkNewMacro(Self) /** Run-time type information (and related methods). */ itkTypeMacro(FixedNiftiImageIO, Superclass) bool SupportsDimension(unsigned long dim) override { return dim > 1 && dim < 5; } }; void MitkCoreActivator::Load(us::ModuleContext *context) { // Handle messages from CppMicroServices us::installMsgHandler(HandleMicroServicesMessages); this->m_Context = context; // Add the current application directory to the auto-load paths. // This is useful for third-party executables. std::string programPath = mitk::IOUtil::GetProgramPath(); if (programPath.empty()) { MITK_WARN << "Could not get the program path."; } else { AddMitkAutoLoadPaths(programPath); } // m_RenderingManager = mitk::RenderingManager::New(); // context->RegisterService(renderingManager.GetPointer()); m_PlanePositionManager.reset(new mitk::PlanePositionManagerService); context->RegisterService(m_PlanePositionManager.get()); m_PropertyAliases.reset(new mitk::PropertyAliases); context->RegisterService(m_PropertyAliases.get()); m_PropertyDescriptions.reset(new mitk::PropertyDescriptions); context->RegisterService(m_PropertyDescriptions.get()); m_PropertyExtensions.reset(new mitk::PropertyExtensions); context->RegisterService(m_PropertyExtensions.get()); m_PropertyFilters.reset(new mitk::PropertyFilters); context->RegisterService(m_PropertyFilters.get()); m_PropertyPersistence.reset(new mitk::PropertyPersistence); context->RegisterService(m_PropertyPersistence.get()); m_PropertyRelations.reset(new mitk::PropertyRelations); context->RegisterService(m_PropertyRelations.get()); m_MimeTypeProvider.reset(new mitk::MimeTypeProvider); m_MimeTypeProvider->Start(); m_MimeTypeProviderReg = context->RegisterService(m_MimeTypeProvider.get()); this->RegisterDefaultMimeTypes(); this->RegisterItkReaderWriter(); this->RegisterVtkReaderWriter(); // Add custom Reader / Writer Services m_FileReaders.push_back(new mitk::PointSetReaderService()); m_FileWriters.push_back(new mitk::PointSetWriterService()); m_FileReaders.push_back(new mitk::GeometryDataReaderService()); m_FileWriters.push_back(new mitk::GeometryDataWriterService()); m_FileReaders.push_back(new mitk::RawImageFileReaderService()); + //add properties that should be persistent (if possible/supported by the writer) + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()); + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()); + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()); + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME()); + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_VERSION()); + AddPropertyPersistence(mitk::IOMetaInformationPropertyConstants::READER_OPTIONS_ANY()); + /* There IS an option to exchange ALL vtkTexture instances against vtkNeverTranslucentTextureFactory. This code is left here as a reminder, just in case we might need to do that some time. vtkNeverTranslucentTextureFactory* textureFactory = vtkNeverTranslucentTextureFactory::New(); vtkObjectFactory::RegisterFactory( textureFactory ); textureFactory->Delete(); */ this->RegisterLegacyWriter(); } void MitkCoreActivator::Unload(us::ModuleContext *) { for (auto &elem : m_FileReaders) { delete elem; } for (auto &elem : m_FileWriters) { delete elem; } for (auto &elem : m_FileIOs) { delete elem; } for (auto &elem : m_LegacyWriters) { delete elem; } // The mitk::ModuleContext* argument of the Unload() method // will always be 0 for the Mitk library. It makes no sense // to use it at this stage anyway, since all libraries which // know about the module system have already been unloaded. // we need to close the internal service tracker of the // MimeTypeProvider class here. Otherwise it // would hold on to the ModuleContext longer than it is // actually valid. m_MimeTypeProviderReg.Unregister(); m_MimeTypeProvider->Stop(); for (std::vector::const_iterator mimeTypeIter = m_DefaultMimeTypes.begin(), iterEnd = m_DefaultMimeTypes.end(); mimeTypeIter != iterEnd; ++mimeTypeIter) { delete *mimeTypeIter; } } void MitkCoreActivator::RegisterDefaultMimeTypes() { // Register some default mime-types std::vector mimeTypes = mitk::IOMimeTypes::Get(); for (std::vector::const_iterator mimeTypeIter = mimeTypes.begin(), iterEnd = mimeTypes.end(); mimeTypeIter != iterEnd; ++mimeTypeIter) { m_DefaultMimeTypes.push_back(*mimeTypeIter); m_Context->RegisterService(m_DefaultMimeTypes.back()); } } void MitkCoreActivator::RegisterItkReaderWriter() { std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("itkImageIOBase"); for (auto &allobject : allobjects) { auto *io = dynamic_cast(allobject.GetPointer()); // NiftiImageIO does not provide a correct "SupportsDimension()" methods // and the supported read/write extensions are not ordered correctly if (dynamic_cast(io)) continue; // Use a custom mime-type for GDCMImageIO below if (dynamic_cast(allobject.GetPointer())) { // MITK provides its own DICOM reader (which internally uses GDCMImageIO). continue; } if (io) { m_FileIOs.push_back(new mitk::ItkImageIO(io)); } else { MITK_WARN << "Error ImageIO factory did not return an ImageIOBase: " << (allobject)->GetNameOfClass(); } } FixedNiftiImageIO::Pointer itkNiftiIO = FixedNiftiImageIO::New(); mitk::ItkImageIO *niftiIO = new mitk::ItkImageIO(mitk::IOMimeTypes::NIFTI_MIMETYPE(), itkNiftiIO.GetPointer(), 0); m_FileIOs.push_back(niftiIO); } void MitkCoreActivator::RegisterVtkReaderWriter() { m_FileIOs.push_back(new mitk::SurfaceVtkXmlIO()); m_FileIOs.push_back(new mitk::SurfaceStlIO()); m_FileIOs.push_back(new mitk::SurfaceVtkLegacyIO()); m_FileIOs.push_back(new mitk::ImageVtkXmlIO()); m_FileIOs.push_back(new mitk::ImageVtkLegacyIO()); } void MitkCoreActivator::RegisterLegacyWriter() { std::list allobjects = itk::ObjectFactoryBase::CreateAllInstance("IOWriter"); for (auto i = allobjects.begin(); i != allobjects.end(); ++i) { mitk::FileWriter::Pointer io = dynamic_cast(i->GetPointer()); if (io) { std::string description = std::string("Legacy ") + io->GetNameOfClass() + " Writer"; mitk::IFileWriter *writer = new mitk::LegacyFileWriterService(io, description); m_LegacyWriters.push_back(writer); } else { MITK_ERROR << "Error IOWriter override is not of type mitk::FileWriter: " << (*i)->GetNameOfClass() << std::endl; } } } US_EXPORT_MODULE_ACTIVATOR(MitkCoreActivator) // Call CppMicroservices initialization code at the end of the file. // This especially ensures that VTK object factories have already // been registered (VTK initialization code is injected by implicitly // include VTK header files at the top of this file). US_INITIALIZE_MODULE diff --git a/Modules/Core/test/mitkFileReaderRegistryTest.cpp b/Modules/Core/test/mitkFileReaderRegistryTest.cpp index 66670f36c3..94b414c0fc 100644 --- a/Modules/Core/test/mitkFileReaderRegistryTest.cpp +++ b/Modules/Core/test/mitkFileReaderRegistryTest.cpp @@ -1,212 +1,212 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkAbstractFileReader.h" #include "mitkFileReaderRegistry.h" #include "mitkIFileReader.h" #include "mitkTestingMacros.h" #include #include #include class DummyReader : public mitk::AbstractFileReader { public: DummyReader(const DummyReader &other) : mitk::AbstractFileReader(other) {} DummyReader(const std::string &mimeTypeName, const std::string &extension, int priority) : mitk::AbstractFileReader() { mitk::CustomMimeType mimeType(mimeTypeName); mimeType.AddExtension(extension); mimeType.SetComment("This is a dummy description"); this->SetMimeType(mimeType); this->SetRanking(priority); m_ServiceReg = this->RegisterService(); } ~DummyReader() override { if (m_ServiceReg) m_ServiceReg.Unregister(); } using mitk::AbstractFileReader::Read; - std::vector> Read() override + std::vector> DoRead() override { std::vector result; return result; } private: DummyReader *Clone() const override { return new DummyReader(*this); } us::ServiceRegistration m_ServiceReg; }; // End of internal dummy reader class DummyReader2 : public mitk::AbstractFileReader { public: DummyReader2(const DummyReader2 &other) : mitk::AbstractFileReader(other) {} DummyReader2(const std::string &mimeTypeName, const std::string &extension, int priority) : mitk::AbstractFileReader() { mitk::CustomMimeType mimeType(mimeTypeName); mimeType.AddExtension(extension); mimeType.SetComment("This is a second dummy description"); this->SetMimeType(mimeType); this->SetRanking(priority); m_ServiceReg = this->RegisterService(); } ~DummyReader2() override { if (m_ServiceReg) m_ServiceReg.Unregister(); } using mitk::AbstractFileReader::Read; - std::vector> Read() override + std::vector> DoRead() override { std::vector result; return result; } private: DummyReader2 *Clone() const override { return new DummyReader2(*this); } us::ServiceRegistration m_ServiceReg; }; // End of internal dummy reader 2 /** * TODO */ int mitkFileReaderRegistryTest(int /*argc*/, char * /*argv*/ []) { // always start with this! MITK_TEST_BEGIN("FileReaderRegistry"); // mitk::FileReaderRegistry::Pointer frm = mitk::FileReaderRegistry::New(); // MITK_TEST_CONDITION_REQUIRED(argc == 2,"Testing FileReaderRegistry instantiation"); // DummyReader testDR("application/dummy", "test",1); // DummyReader otherDR("application/dummy2", "other",1); // MITK_TEST_CONDITION_REQUIRED(!testDR.CanRead("/this/is/a/folder/file.tes"),"Negative test of default CanRead() // implementation"); // mitk::FileReaderRegistry* readerRegistry = new mitk::FileReaderRegistry; // mitk::IFileReader* returned = readerRegistry->GetReader("bla.test"); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(testDR) != returned,"Testing correct // retrieval of FileReader 1/2"); // returned = readerRegistry->GetReader("other"); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(otherDR) != returned,"Testing correct // retrieval of FileReader 2/2"); // DummyReader mediocreTestDR("application/dummy", "test", 20); // DummyReader prettyFlyTestDR("application/dummy", "test", 50); // DummyReader2 awesomeTestDR("application/dummy", "test", 100); // returned = readerRegistry->GetReader("test"); // MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returned), "Testing correct priorized retrieval of // FileReader: Best reader"); // Now to give those readers some options, then we will try again // mitk::IFileReader::OptionList options; // options.push_back(std::make_pair("isANiceGuy", true)); // mediocreTestDR.SetOptions(options); // options.clear(); // options.push_back(std::make_pair("canFly", true)); // prettyFlyTestDR.SetOptions(options); // options.push_back(std::make_pair("isAwesome", true)); // awesomeTestDR.SetOptions(options); //note: awesomeReader canFly and isAwesome // // Reset Options, use to define what we want the reader to do // options.clear(); // mitk::IFileReader::OptionNames optionsFilter; // optionsFilter.push_back("canFly"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(awesomeTestDR) != returned, "Testing // correct retrieval of FileReader with Options: Best reader with options"); // optionsFilter.push_back("isAwesome"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(awesomeTestDR) != returned, "Testing // correct retrieval of FileReader with multiple Options: Best reader with options"); // optionsFilter.clear(); // optionsFilter.push_back("isANiceGuy"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned && &static_cast(mediocreTestDR) != returned, "Testing // correct retrieval of specific FileReader with Options: Low priority reader with specific option"); // optionsFilter.push_back("canFly"); // returned = readerRegistry->GetReader("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returned == nullptr, "Testing correct return of 0 value when no matching reader was // found"); // // Onward to test the retrieval of multiple readers // std::vector< mitk::IFileReader* > returnedList; // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.empty(), "Testing correct return of zero readers when no matching reader // was found, asking for all compatibles"); // optionsFilter.clear(); // optionsFilter.push_back("canFly"); // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 2, "Testing correct return of two readers when two matching // reader was found, asking for all compatibles"); // MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returnedList.front()), "Testing correct priorization of // returned Readers with options 1/2"); // optionsFilter.clear(); // optionsFilter.push_back("isAwesome"); // returnedList = readerRegistry->GetReaders("test", optionsFilter); // MITK_TEST_CONDITION_REQUIRED(returnedList.size() == 1, "Testing correct return of one readers when one matching // reader was found, asking for all compatibles"); // MITK_TEST_CONDITION_REQUIRED(dynamic_cast(returnedList.front()), "Testing correctness of result // from former query"); // And now to verify a working read chain for a mps file: // mitk::PointSetReader::Pointer psr = mitk::PointSetReader::New(); // std::vector basedata; // basedata = mitk::FileReaderRegistry::Read("F://Build//MITK-Data//pointSet.mps"); // MITK_TEST_CONDITION_REQUIRED(basedata.size() > 0, "Testing correct read of PointSet"); // Testing templated call to ReaderRegistry // mitk::PointSet::Pointer pointset = mitk::FileReaderRegistry::Read< mitk::PointSet // >("F://Build//MITK-Data//pointSet.mps"); // MITK_TEST_CONDITION_REQUIRED(pointset.IsNotNull(), "Testing templated call of Read()"); // And now for something completely different... (Debug) // mitk::LegacyFileReaderService::Pointer lfr = mitk::LegacyFileReaderService::New(".nrrd", "Nearly Raw Raster Data"); // returned = mitk::FileReaderRegistry::GetReader(".nrrd"); // MITK_TEST_CONDITION_REQUIRED(lfr == returned, "Testing correct retrieval of specific FileReader with Options: Low // priority reader with specific option"); // std::vector image = // mitk::FileReaderRegistry::Read("F://Build//MITK-Data//Pic2DplusT.nrrd"); // MITK_TEST_CONDITION_REQUIRED(image.size() > 0, "Testing whether image was returned or not"); // mitk::Image::Pointer image2 = dynamic_cast (image.front().GetPointer()); // MITK_TEST_CONDITION_REQUIRED(image2.IsNotNull(), "Testing if BaseData is an image"); // Delete this here because it will call the PrototypeServiceFactory::Unget() method // of the dummy readers. // delete readerRegistry; // always end with this! MITK_TEST_END(); } diff --git a/Modules/Core/test/mitkIOUtilTest.cpp b/Modules/Core/test/mitkIOUtilTest.cpp index e1e1f73e98..1a7ddd83f3 100644 --- a/Modules/Core/test/mitkIOUtilTest.cpp +++ b/Modules/Core/test/mitkIOUtilTest.cpp @@ -1,231 +1,293 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkTestingMacros.h" #include #include #include #include +#include +#include +#include +#include #include class mitkIOUtilTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkIOUtilTestSuite); MITK_TEST(TestTempMethods); MITK_TEST(TestSaveEmptyData); MITK_TEST(TestLoadAndSaveImage); MITK_TEST(TestNullLoad); MITK_TEST(TestNullSave); MITK_TEST(TestLoadAndSavePointSet); MITK_TEST(TestLoadAndSaveSurface); MITK_TEST(TestTempMethodsForUniqueFilenames); MITK_TEST(TestTempMethodsForUniqueFilenames); + MITK_TEST(TestIOMetaInformation); CPPUNIT_TEST_SUITE_END(); private: std::string m_ImagePath; std::string m_SurfacePath; std::string m_PointSetPath; public: void setUp() override { m_ImagePath = GetTestDataFilePath("Pic3D.nrrd"); m_SurfacePath = GetTestDataFilePath("binary.stl"); m_PointSetPath = GetTestDataFilePath("pointSet.mps"); } void TestSaveEmptyData() { mitk::Surface::Pointer data = mitk::Surface::New(); CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(data, "/tmp/dummy"), mitk::Exception); } void TestTempMethods() { std::string tmpPath = mitk::IOUtil::GetTempPath(); CPPUNIT_ASSERT(!tmpPath.empty()); std::ofstream tmpFile; std::string tmpFilePath = mitk::IOUtil::CreateTemporaryFile(tmpFile); CPPUNIT_ASSERT(tmpFile && tmpFile.is_open()); CPPUNIT_ASSERT(tmpFilePath.size() > tmpPath.size()); CPPUNIT_ASSERT(tmpFilePath.substr(0, tmpPath.size()) == tmpPath); tmpFile.close(); CPPUNIT_ASSERT(std::remove(tmpFilePath.c_str()) == 0); std::string programPath = mitk::IOUtil::GetProgramPath(); CPPUNIT_ASSERT(!programPath.empty()); std::ofstream tmpFile2; std::string tmpFilePath2 = mitk::IOUtil::CreateTemporaryFile(tmpFile2, "my-XXXXXX", programPath); CPPUNIT_ASSERT(tmpFile2 && tmpFile2.is_open()); CPPUNIT_ASSERT(tmpFilePath2.size() > programPath.size()); CPPUNIT_ASSERT(tmpFilePath2.substr(0, programPath.size()) == programPath); tmpFile2.close(); CPPUNIT_ASSERT(std::remove(tmpFilePath2.c_str()) == 0); std::ofstream tmpFile3; std::string tmpFilePath3 = mitk::IOUtil::CreateTemporaryFile(tmpFile3, std::ios_base::binary, "my-XXXXXX.TXT", programPath); CPPUNIT_ASSERT(tmpFile3 && tmpFile3.is_open()); CPPUNIT_ASSERT(tmpFilePath3.size() > programPath.size()); CPPUNIT_ASSERT(tmpFilePath3.substr(0, programPath.size()) == programPath); CPPUNIT_ASSERT(tmpFilePath3.substr(tmpFilePath3.size() - 13, 3) == "my-"); CPPUNIT_ASSERT(tmpFilePath3.substr(tmpFilePath3.size() - 4) == ".TXT"); tmpFile3.close(); // CPPUNIT_ASSERT(std::remove(tmpFilePath3.c_str()) == 0) std::string tmpFilePath4 = mitk::IOUtil::CreateTemporaryFile(); std::ofstream file; file.open(tmpFilePath4.c_str()); CPPUNIT_ASSERT_MESSAGE("Testing if file exists after CreateTemporaryFile()", file.is_open()); CPPUNIT_ASSERT_THROW(mitk::IOUtil::CreateTemporaryFile(tmpFile2, "XX"), mitk::Exception); std::string tmpDir = mitk::IOUtil::CreateTemporaryDirectory(); CPPUNIT_ASSERT(tmpDir.size() > tmpPath.size()); CPPUNIT_ASSERT(tmpDir.substr(0, tmpPath.size()) == tmpPath); CPPUNIT_ASSERT(itksys::SystemTools::RemoveADirectory(tmpDir.c_str())); std::string tmpDir2 = mitk::IOUtil::CreateTemporaryDirectory("my-XXXXXX", programPath); CPPUNIT_ASSERT(tmpDir2.size() > programPath.size()); CPPUNIT_ASSERT(tmpDir2.substr(0, programPath.size()) == programPath); CPPUNIT_ASSERT(itksys::SystemTools::RemoveADirectory(tmpDir2.c_str())); } void TestTempMethodsForUniqueFilenames() { int numberOfFiles = 100; // create 100 empty files std::vector v100filenames; for (int i = 0; i < numberOfFiles; i++) { v100filenames.push_back(mitk::IOUtil::CreateTemporaryFile()); } // check if all of them are unique for (int i = 0; i < numberOfFiles; i++) for (int j = 0; j < numberOfFiles; j++) { if (i != j) { std::stringstream message; message << "Checking if file " << i << " and file " << j << " are different, which should be the case because each of them should be unique."; CPPUNIT_ASSERT_MESSAGE(message.str(), (v100filenames.at(i) != v100filenames.at(j))); } } // delete all the files / clean up for (int i = 0; i < numberOfFiles; i++) { std::remove(v100filenames.at(i).c_str()); } } void TestLoadAndSaveImage() { mitk::Image::Pointer img1 = mitk::IOUtil::Load(m_ImagePath); CPPUNIT_ASSERT(img1.IsNotNull()); std::ofstream tmpStream; std::string imagePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffpic3d-XXXXXX.nrrd"); tmpStream.close(); std::string imagePath2 = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffpic3d-XXXXXX.nii.gz"); tmpStream.close(); // the cases where no exception should be thrown CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(img1, imagePath)); CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(img1.GetPointer(), imagePath2)); // load data which does not exist CPPUNIT_ASSERT_THROW(mitk::IOUtil::Load("fileWhichDoesNotExist.nrrd"), mitk::Exception); // delete the files after the test is done std::remove(imagePath.c_str()); std::remove(imagePath2.c_str()); mitk::Image::Pointer relativImage = mitk::ImageGenerator::GenerateGradientImage(4, 4, 4, 1); std::string imagePath3 = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.nrrd"); tmpStream.close(); mitk::IOUtil::Save(relativImage, imagePath3); CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Load(imagePath3)); std::remove(imagePath3.c_str()); } /** * \brief This method calls all available load methods with a nullpointer and an empty pathand expects an exception **/ void TestNullLoad() { CPPUNIT_ASSERT_THROW(mitk::IOUtil::Load(""), mitk::Exception); } /** * \brief This method calls the save method (to which all other convenience save methods reference) with null *parameters **/ void TestNullSave() { CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(nullptr, mitk::IOUtil::CreateTemporaryFile()), mitk::Exception); CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(mitk::Image::New().GetPointer(), ""), mitk::Exception); } void TestLoadAndSavePointSet() { mitk::PointSet::Pointer pointset = mitk::IOUtil::Load(m_PointSetPath); CPPUNIT_ASSERT(pointset.IsNotNull()); std::ofstream tmpStream; std::string pointSetPath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.mps"); tmpStream.close(); std::string pointSetPathWithDefaultExtension = mitk::IOUtil::CreateTemporaryFile(tmpStream, "XXXXXX.mps"); tmpStream.close(); std::string pointSetPathWithoutDefaultExtension = mitk::IOUtil::CreateTemporaryFile(tmpStream); tmpStream.close(); // the cases where no exception should be thrown CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(pointset, pointSetPathWithDefaultExtension)); // test if defaultextension is inserted if no extension is present CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(pointset, pointSetPathWithoutDefaultExtension.c_str())); // delete the files after the test is done std::remove(pointSetPath.c_str()); std::remove(pointSetPathWithDefaultExtension.c_str()); std::remove(pointSetPathWithoutDefaultExtension.c_str()); } void TestLoadAndSaveSurface() { mitk::Surface::Pointer surface = mitk::IOUtil::Load(m_SurfacePath); CPPUNIT_ASSERT(surface.IsNotNull()); std::ofstream tmpStream; std::string surfacePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "diffsurface-XXXXXX.stl"); // the cases where no exception should be thrown CPPUNIT_ASSERT_NO_THROW(mitk::IOUtil::Save(surface, surfacePath)); // test if exception is thrown as expected on unknown extsension CPPUNIT_ASSERT_THROW(mitk::IOUtil::Save(surface, "testSurface.xXx"), mitk::Exception); // delete the files after the test is done std::remove(surfacePath.c_str()); } + + std::string GenerateMetaDictKey(const mitk::PropertyKeyPath& propKey) + { + auto result = mitk::PropertyKeyPathToPropertyName(propKey); + std::replace(result.begin(), result.end(), '.', '_'); + return result; + } + + std::string GetValueFromMetaDict(const itk::MetaDataDictionary& dict, const mitk::PropertyKeyPath& propKey) + { + auto metaValueBase = dict.Get(GenerateMetaDictKey(propKey)); + auto metaValue = dynamic_cast*>(metaValueBase); + return metaValue->GetMetaDataObjectValue(); + } + + void TestIOMetaInformation() + { + mitk::Image::Pointer img = mitk::IOUtil::Load(m_ImagePath); + CPPUNIT_ASSERT(img.IsNotNull()); + + auto value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()).c_str())->GetValueAsString(); + CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), value); + value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()).c_str())->GetValueAsString(); + CPPUNIT_ASSERT_EQUAL(m_ImagePath, value); + value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()).c_str())->GetValueAsString(); + CPPUNIT_ASSERT_EQUAL(std::string("Images"), value); + value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME()).c_str())->GetValueAsString(); + CPPUNIT_ASSERT_EQUAL(std::string("application/vnd.mitk.image.nrrd"), value); + value = img->GetProperty(mitk::PropertyKeyPathToPropertyName(mitk::IOMetaInformationPropertyConstants::READER_VERSION()).c_str())->GetValueAsString(); + CPPUNIT_ASSERT_EQUAL(std::string(MITK_VERSION_STRING), value); + + //check if the information is persistet correctly on save. + std::ofstream tmpStream; + std::string imagePath = mitk::IOUtil::CreateTemporaryFile(tmpStream, "ioMeta_XXXXXX.nrrd"); + tmpStream.close(); + mitk::IOUtil::Save(img, imagePath); + + auto io = itk::NrrdImageIO::New(); + io->SetFileName(imagePath); + io->ReadImageInformation(); + auto metaDict = io->GetMetaDataDictionary(); + + auto metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_DESCRIPTION()); + CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), metaValue); + metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_INPUTLOCATION()); + CPPUNIT_ASSERT_EQUAL(m_ImagePath, metaValue); + metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_MIME_CATEGORY()); + CPPUNIT_ASSERT_EQUAL(std::string("Images"), metaValue); + metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_MIME_NAME()); + CPPUNIT_ASSERT_EQUAL(std::string("application/vnd.mitk.image.nrrd"), metaValue); + metaValue = GetValueFromMetaDict(metaDict, mitk::IOMetaInformationPropertyConstants::READER_VERSION()); + CPPUNIT_ASSERT_EQUAL(std::string(MITK_VERSION_STRING), metaValue); + + // delete the files after the test is done + std::remove(imagePath.c_str()); + } + }; MITK_TEST_SUITE_REGISTRATION(mitkIOUtil) diff --git a/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp index c779a6aefc..c4af10cd1c 100644 --- a/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp +++ b/Modules/Core/test/mitkPreferenceListReaderOptionsFunctorTest.cpp @@ -1,199 +1,199 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPreferenceListReaderOptionsFunctor.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include #include #include #include #include namespace mitk { class TestFileReaderService : public mitk::AbstractFileReader { public: TestFileReaderService(const std::string &description) : AbstractFileReader(CustomMimeType("TestMimeType"), description) { m_ServiceRegistration = RegisterService(); }; ~TestFileReaderService() override { }; using AbstractFileReader::Read; - std::vector> Read() override + std::vector> DoRead() override { std::vector> result; return result; }; ConfidenceLevel GetConfidenceLevel() const override { return Supported; }; private: TestFileReaderService * Clone() const override { return new TestFileReaderService(*this); }; us::ServiceRegistration m_ServiceRegistration; }; } // namespace mitk class mitkPreferenceListReaderOptionsFunctorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPreferenceListReaderOptionsFunctorTestSuite); MITK_TEST(UsePreferenceList); MITK_TEST(UseBlackList); MITK_TEST(UseNoList); MITK_TEST(UseBlackAndPreferenceList); MITK_TEST(UseOverlappingBlackAndPreferenceList); MITK_TEST(UsePreferenceListWithInexistantReaders); MITK_TEST(UseAllBlackedList); CPPUNIT_TEST_SUITE_END(); private: std::string m_ImagePath; mitk::PreferenceListReaderOptionsFunctor::ListType preference; mitk::PreferenceListReaderOptionsFunctor::ListType black; mitk::PreferenceListReaderOptionsFunctor::ListType emptyList; mitk::TestFileReaderService* m_NormalService; mitk::TestFileReaderService* m_PrefService; mitk::TestFileReaderService* m_BlackService; mitk::CustomMimeType* m_TestMimeType; public: void setUp() override { m_ImagePath = GetTestDataFilePath("BallBinary30x30x30.nrrd"); preference = { "Prefered Test Service" }; black = { "Unwanted Test Service" }; emptyList = {}; m_TestMimeType = new mitk::CustomMimeType("TestMimeType"); m_TestMimeType->AddExtension("nrrd"); m_TestMimeType->SetCategory(mitk::IOMimeTypes::CATEGORY_IMAGES()); m_TestMimeType->SetComment("Test mime type"); us::ModuleContext *context = us::GetModuleContext(); us::ServiceProperties props; props[us::ServiceConstants::SERVICE_RANKING()] = 10; context->RegisterService(m_TestMimeType, props); m_NormalService = new mitk::TestFileReaderService("Normal Test Service"); m_PrefService = new mitk::TestFileReaderService("Prefered Test Service"); m_BlackService = new mitk::TestFileReaderService("Unwanted Test Service"); } void tearDown() override { delete m_PrefService; delete m_BlackService; delete m_NormalService; delete m_TestMimeType; } void UsePreferenceList() { mitk::IOUtil::LoadInfo info(m_ImagePath); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description); } void UseNoList() { mitk::IOUtil::LoadInfo info(m_ImagePath); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, emptyList); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT_EQUAL(std::string("Normal Test Service"), description); } void UseBlackList() { mitk::IOUtil::LoadInfo info(m_ImagePath); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT(description != "Unwanted Test Service"); } void UseBlackAndPreferenceList() { mitk::IOUtil::LoadInfo info(m_ImagePath); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description); } void UseOverlappingBlackAndPreferenceList() { mitk::IOUtil::LoadInfo info(m_ImagePath); black.push_back("Prefered Test Service"); black.push_back("Normal Test Service"); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, black); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT_EQUAL(std::string("ITK NrrdImageIO"), description); } void UsePreferenceListWithInexistantReaders() { mitk::IOUtil::LoadInfo info(m_ImagePath); preference.push_back("InexistantReader"); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(preference, emptyList); CPPUNIT_ASSERT(true == functor(info)); auto description = info.m_ReaderSelector.GetSelected().GetDescription(); CPPUNIT_ASSERT_EQUAL(std::string("Prefered Test Service"), description); } void UseAllBlackedList() { mitk::IOUtil::LoadInfo info(m_ImagePath); for (auto reader : info.m_ReaderSelector.Get()) { black.push_back(reader.GetDescription()); } mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor(emptyList, black); CPPUNIT_ASSERT_THROW(functor(info), mitk::Exception); } }; MITK_TEST_SUITE_REGISTRATION(mitkPreferenceListReaderOptionsFunctor) diff --git a/Modules/Core/test/mitkPropertyKeyPathTest.cpp b/Modules/Core/test/mitkPropertyKeyPathTest.cpp index 338df2a20f..2ef686768e 100644 --- a/Modules/Core/test/mitkPropertyKeyPathTest.cpp +++ b/Modules/Core/test/mitkPropertyKeyPathTest.cpp @@ -1,314 +1,321 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPropertyKeyPath.h" #include "mitkTestFixture.h" #include "mitkTestingMacros.h" #include class mitkPropertyKeyPathTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkPropertyKeyPathTestSuite); MITK_TEST(AccessFunctions); MITK_TEST(PropertyKeyPathToPropertyRegEx); MITK_TEST(PropertyKeyPathToPersistenceKeyRegEx); MITK_TEST(PropertyKeyPathToPersistenceKeyTemplate); MITK_TEST(PropertyKeyPathToPersistenceNameTemplate); MITK_TEST(PropertyNameToPropertyKeyPath); MITK_TEST(PropertyKeyPathToPropertyName); MITK_TEST(ExecutePropertyRegEx); MITK_TEST(Comparison); + MITK_TEST(InitializerList); CPPUNIT_TEST_SUITE_END(); private: mitk::PropertyKeyPath simplePath; mitk::PropertyKeyPath simplePath2; mitk::PropertyKeyPath deepPath; mitk::PropertyKeyPath deepPath_withAnyElement; mitk::PropertyKeyPath deepPath_withAnySelection; mitk::PropertyKeyPath deepPath_withSelection; mitk::PropertyKeyPath verydeepPath; mitk::PropertyKeyPath emptyPath; public: void setUp() override { simplePath.AddElement("simple"); simplePath2.AddElement("AA-11"); deepPath.AddElement("a").AddElement("b2").AddElement("c3"); deepPath_withAnyElement.AddElement("a"); deepPath_withAnyElement.AddAnyElement(); deepPath_withAnyElement.AddElement("c3"); deepPath_withAnySelection.AddElement("a"); deepPath_withAnySelection.AddAnySelection("b"); deepPath_withAnySelection.AddElement("c"); deepPath_withSelection.AddElement("a"); deepPath_withSelection.AddSelection("b", 6); deepPath_withSelection.AddElement("c"); verydeepPath.AddAnySelection("a"); verydeepPath.AddAnyElement(); verydeepPath.AddElement("c"); verydeepPath.AddSelection("d", 4); verydeepPath.AddElement("e"); } void tearDown() override {} void AccessFunctions() { const auto constEmptyPath = emptyPath; const auto constVerydeepPath = verydeepPath; CPPUNIT_ASSERT_THROW(emptyPath.GetFirstNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(emptyPath.GetLastNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(emptyPath.GetNode(0), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetFirstNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetLastNode(), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_THROW(constEmptyPath.GetNode(0), mitk::InvalidPathNodeException); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), verydeepPath.GetFirstNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing const GetFirstNode with 'a.[*].*.c.d.[4].e'", std::string("a"), constVerydeepPath.GetFirstNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), verydeepPath.GetLastNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetLastNode with 'a.[*].*.c.d.[4].e'", std::string("e"), constVerydeepPath.GetLastNode().name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), verydeepPath.GetNode(3).name); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing GetNode(3) with 'a.[*].*.c.d.[4].e'", std::string("d"), constVerydeepPath.GetNode(3).name); CPPUNIT_ASSERT(5 == constVerydeepPath.GetSize()); CPPUNIT_ASSERT(0 == emptyPath.GetSize()); } void PropertyKeyPathToPropertyRegEx() { std::string result = mitk::PropertyKeyPathToPropertyRegEx(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b2.c3'", std::string("a\\.b2\\.c3"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.*.c3'", std::string("a\\.([a-zA-Z0-9- ]+)\\.c3"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[*].c'", std::string("a\\.b\\.\\[(\\d*)\\]\\.c"), result); result = mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyRegEx() with 'a.b.[6].c'", std::string("a\\.b\\.\\[6\\]\\.c"), result); result = mitk::PropertyKeyPathToPropertyRegEx(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPropertyRegEx() with 'a.[*].*.c.d.[4].e'", std::string("a\\.\\[(\\d*)\\]\\.([a-zA-Z0-9- ]+)\\.c\\.d\\.\\[4\\]\\.e"), result); } void PropertyKeyPathToPersistenceKeyRegEx() { std::string result = mitk::PropertyKeyPathToPersistenceKeyRegEx(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b2.c3'", std::string("a_b2_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.*.c3'", std::string("a_([a-zA-Z0-9- ]+)_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[*].c'", std::string("a_b_\\[(\\d*)\\]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.b.[6].c'", std::string("a_b_\\[6\\]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyRegEx(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyRegEx() with 'a.[*].*.c.d.[4].e'", std::string("a_\\[(\\d*)\\]_([a-zA-Z0-9- ]+)_c_d_\\[4\\]_e"), result); } void PropertyKeyPathToPersistenceKeyTemplate() { std::string result = mitk::PropertyKeyPathToPersistenceKeyTemplate(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b2.c3'", std::string("a_b2_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.*.c3'", std::string("a_$1_c3"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[*].c'", std::string("a_b_[$1]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.b.[6].c'", std::string("a_b_[6]_c"), result); result = mitk::PropertyKeyPathToPersistenceKeyTemplate(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceKeyTemplate() with 'a.[*].*.c.d.[4].e'", std::string("a_[$1]_$2_c_d_[4]_e"), result); } void PropertyKeyPathToPersistenceNameTemplate() { std::string result = mitk::PropertyKeyPathToPersistenceNameTemplate(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'simple'", std::string("simple"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b2.c3'", std::string("a.b2.c3"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.*.c3'", std::string("a.$1.c3"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[*].c'", std::string("a.b.[$1].c"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.b.[6].c'", std::string("a.b.[6].c"), result); result = mitk::PropertyKeyPathToPersistenceNameTemplate(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyKeyPathToPersistenceNameTemplate() with 'a.[*].*.c.d.[4].e'", std::string("a.[$1].$2.c.d.[4].e"), result); } void PropertyNameToPropertyKeyPath() { mitk::PropertyKeyPath result = mitk::PropertyNameToPropertyKeyPath("simple"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'simple'", simplePath, result); result = mitk::PropertyNameToPropertyKeyPath("a.b2.c3"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'a.b2.c3'", deepPath, result); result = mitk::PropertyNameToPropertyKeyPath("a.*.c3"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.*.c3'", deepPath_withAnyElement, result); result = mitk::PropertyNameToPropertyKeyPath("a.b.[*].c"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.b.[*].c'", deepPath_withAnySelection, result); result = mitk::PropertyNameToPropertyKeyPath("a.b.[6].c"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.b.[6].c'", deepPath_withSelection, result); result = mitk::PropertyNameToPropertyKeyPath("a.[*].*.c.d.[4].e"); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyNameToPropertyKeyPath() with 'a.[*].*.c.d.[4].e'", verydeepPath, result); result = mitk::PropertyNameToPropertyKeyPath("AA-11"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with 'AA-11'", simplePath2, result); result = mitk::PropertyNameToPropertyKeyPath("$$$IlligalNameChar.sub"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); result = mitk::PropertyNameToPropertyKeyPath("emptyNode..sub"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); result = mitk::PropertyNameToPropertyKeyPath("wrongIndex.[d]"); CPPUNIT_ASSERT_EQUAL_MESSAGE("Testing PropertyNameToPropertyKeyPath() with wrong path", emptyPath, result); } void PropertyKeyPathToPropertyName() { std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'simple'", result, std::string("simple")); result = mitk::PropertyKeyPathToPropertyName(deepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b2.c3'", result, std::string("a.b2.c3")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.*.c3'", result, std::string("a.*.c3")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b.[*].c'", result, std::string("a.b.[*].c")); result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.b.[6].c'", result, std::string("a.b.[6].c")); result = mitk::PropertyKeyPathToPropertyName(verydeepPath); CPPUNIT_ASSERT_EQUAL_MESSAGE( "Testing PropertyKeyPathToPropertyName() with 'a.[*].*.c.d.[4].e'", result, std::string("a.[*].*.c.d.[4].e")); } void Comparison() { mitk::PropertyKeyPath deepPath_noSelection = mitk::PropertyKeyPath().AddElement("a").AddElement("b").AddElement("c"); CPPUNIT_ASSERT(deepPath_noSelection < deepPath); CPPUNIT_ASSERT(deepPath_noSelection < deepPath_withSelection); CPPUNIT_ASSERT(deepPath_withSelection < deepPath); CPPUNIT_ASSERT(deepPath_withSelection < deepPath_withAnySelection); CPPUNIT_ASSERT(deepPath_withAnyElement < deepPath_noSelection); CPPUNIT_ASSERT(!(deepPath_noSelection < deepPath_noSelection)); CPPUNIT_ASSERT(!(deepPath_noSelection > deepPath_noSelection)); CPPUNIT_ASSERT(deepPath_noSelection <= deepPath_noSelection); CPPUNIT_ASSERT(deepPath_noSelection >= deepPath_noSelection); } void ExecutePropertyRegEx() { std::regex regEx(mitk::PropertyKeyPathToPropertyRegEx(simplePath)); std::string result = mitk::PropertyKeyPathToPropertyName(simplePath); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath)); result = mitk::PropertyKeyPathToPropertyName(deepPath); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnyElement)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnyElement); auto position = result.find("*"); if (std::string::npos != position) { result.replace(position, 1, "ConcreteNode1"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withAnySelection)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withAnySelection); position = result.find("[*]"); if (std::string::npos != position) { result.replace(position, 3, "[10]"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(deepPath_withSelection)); result = mitk::PropertyKeyPathToPropertyName(deepPath_withSelection); CPPUNIT_ASSERT(std::regex_match(result, regEx)); regEx = std::regex(mitk::PropertyKeyPathToPropertyRegEx(verydeepPath)); result = mitk::PropertyKeyPathToPropertyName(verydeepPath); position = result.find("[*]"); if (std::string::npos != position) { result.replace(position, 3, "[1]"); position = result.find("*"); if (std::string::npos != position) { result.replace(position, 1, "ConcreteNode2"); CPPUNIT_ASSERT(std::regex_match(result, regEx)); } } } + + void InitializerList() + { + mitk::PropertyKeyPath newPath = {"a","b2","c3"}; + CPPUNIT_ASSERT(newPath == deepPath); + } }; MITK_TEST_SUITE_REGISTRATION(mitkPropertyKeyPath) diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp index 643fd7dc94..b03d29e22e 100644 --- a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp +++ b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.cpp @@ -1,217 +1,217 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkDICOMPMIO__cpp #define __mitkDICOMPMIO__cpp #include "mitkDICOMPMIO.h" #include "mitkDICOMPMIOMimeTypes.h" #include #include #include #include #include #include #include #include #include #include "mitkParamapPresetsParser.h" // us #include #include // model fit parameters #include "mitkModelFitConstants.h" namespace mitk { DICOMPMIO::DICOMPMIO() : AbstractFileIO(Image::GetStaticNameOfClass(), mitk::MitkDICOMPMIOMimeTypes::DICOMPM_MIMETYPE_NAME(), "DICOM PM") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel DICOMPMIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const Image *PMinput = static_cast(this->GetInput()); if (PMinput) { auto modalityProperty = PMinput->GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x0060).c_str()); if (modalityProperty.IsNotNull()) { std::string modality = modalityProperty->GetValueAsString(); if (modality == "PM") { return Supported; } else return Unsupported; } else return Unsupported; } else return Unsupported; } void DICOMPMIO::Write() { ValidateOutputLocation(); mitk::LocaleSwitch localeSwitch("C"); LocalFile localFile(this); const std::string path = localFile.GetFileName(); auto PMinput = dynamic_cast(this->GetInput()); if (PMinput == nullptr) mitkThrow() << "Cannot write non-image data"; // Get DICOM information from referenced image vector> dcmDatasetsSourceImage; std::unique_ptr readFileFormat(new DcmFileFormat()); try { // Generate dcmdataset witk DICOM tags from property list; ATM the source are the filepaths from the // property list mitk::StringLookupTableProperty::Pointer filesProp = dynamic_cast(PMinput->GetProperty("referenceFiles").GetPointer()); if (filesProp.IsNull()) { mitkThrow() << "No property with dicom file path."; return; } // returns a list of all referenced files 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()) { std::unique_ptr readDCMDataset(readFileFormat->getAndRemoveDataset()); dcmDatasetsSourceImage.push_back(std::move(readDCMDataset)); } } } catch (const std::exception &e) { MITK_ERROR << "An error occurred while getting the dicom information: " << e.what() << endl; return; } mitk::Image *mitkPMImage = const_cast(PMinput); // Cast input PMinput to itk image ImageToItk::Pointer PMimageToItkFilter = ImageToItk::New(); PMimageToItkFilter->SetInput(mitkPMImage); // Cast from original itk type to dcmqi input itk image type typedef itk::CastImageFilter castItkImageFilterType; castItkImageFilterType::Pointer castFilter = castItkImageFilterType::New(); castFilter->SetInput(PMimageToItkFilter->GetOutput()); castFilter->Update(); PMitkInternalImageType::Pointer itkParamapImage = castFilter->GetOutput(); // Create PM meta information const std::string tmpMetaInfoFile = this->CreateMetaDataJsonFilePM(); // Convert itk PM images to dicom image MITK_INFO << "Writing PM image: " << path << std::endl; try { // convert from unique to raw pointer vector rawVecDataset; for ( const auto& dcmDataSet : dcmDatasetsSourceImage ) { rawVecDataset.push_back( dcmDataSet.get() ); } std::unique_ptr PMconverter(new dcmqi::ParaMapConverter()); std::unique_ptr PMresult (PMconverter->itkimage2paramap(itkParamapImage, rawVecDataset, tmpMetaInfoFile)); // Write dicom file DcmFileFormat dcmFileFormat(PMresult.get()); std::string filePath = path.substr(0, path.find_last_of(".")); filePath = filePath + ".dcm"; dcmFileFormat.saveFile(filePath.c_str(), EXS_LittleEndianExplicit); } catch (const std::exception &e) { MITK_ERROR << "An error occurred during writing the DICOM Paramap: " << e.what() << endl; return; } } const std::string mitk::DICOMPMIO::CreateMetaDataJsonFilePM() const { const mitk::Image *PMimage = dynamic_cast(this->GetInput()); dcmqi::JSONParametricMapMetaInformationHandler PMhandler; // Get Metadata from modelFitConstants std::string parameterName; PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::PARAMETER_NAME_PROPERTY_NAME().c_str(), parameterName); std::string modelName; PMimage->GetPropertyList()->GetStringProperty(ModelFitConstants::MODEL_NAME_PROPERTY_NAME().c_str(), modelName); mitk::ParamapPresetsParser* pmPresets = mitk::ParamapPresetsParser::New(); // Here the mitkParamapPresets.xml file containing the Coding Schmeme Designator and Code Value are parsed and the relevant values extracted pmPresets->LoadPreset(); auto pmType_parameterName = pmPresets->GetType(parameterName); auto pmType_modelName = pmPresets->GetType(modelName); // Pass codes to Paramap Converter PMhandler.setDerivedPixelContrast("TCS"); PMhandler.setFrameLaterality("U"); PMhandler.setQuantityValueCode(pmType_parameterName.codeValue, pmType_parameterName.codeScheme, parameterName); PMhandler.setMeasurementMethodCode(pmType_modelName.codeValue, pmType_modelName.codeScheme, modelName); PMhandler.setMeasurementUnitsCode("/min", "UCUM", "/m"); PMhandler.setSeriesNumber("1"); PMhandler.setInstanceNumber("1"); PMhandler.setDerivationCode("129104", "DCM", "Perfusion image analysis"); PMhandler.setRealWorldValueSlope("1"); return PMhandler.getJSONOutputAsString(); } - std::vector DICOMPMIO::Read() + std::vector DICOMPMIO::DoRead() { mitk::LocaleSwitch localeSwitch("C"); std::vector result; return result; } IFileIO::ConfidenceLevel DICOMPMIO::GetReaderConfidenceLevel() const { return Unsupported; } DICOMPMIO *DICOMPMIO::IOClone() const { return new DICOMPMIO(*this); } } // namespace #endif //__mitkDICOMPMIO__cpp diff --git a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h index f7ecd5cb52..46056c0d3e 100644 --- a/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h +++ b/Modules/DICOMPM/autoload/DICOMPMIO/mitkDICOMPMIO.h @@ -1,68 +1,69 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkDICOMPMIO_h #define __mitkDICOMPMIO_h #include #include #include #include #include namespace mitk { /** * Read and Writes a Parametric map to a dcm file * @ingroup Process */ class DICOMPMIO : public mitk::AbstractFileIO { public: DICOMPMIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - /** - * @brief Reads a DICOM parametric maps from the file system - * @return a mitk::Image - * @throws throws an mitk::Exception if an error ocurrs - */ - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; + protected: + /** + * @brief Reads a DICOM parametric map from the file system + * @return an mitk::Image + * @throws an mitk::Exception if an error ocurrs + */ + std::vector> DoRead() override; private: typedef mitk::Image PMInputType; typedef itk::Image PMitkInputImageType; typedef IODFloatingPointImagePixelModule::value_type PMFloatPixelType; // input type required for DCMQI typedef itk::Image PMitkInternalImageType; DICOMPMIO *IOClone() const override; // -------------- DICOMPMIO specific functions ------------- const std::string CreateMetaDataJsonFilePM() const; }; } // end of namespace mitk #endif // __mitkDICOMPMIO_h diff --git a/Modules/DICOMReader/files.cmake b/Modules/DICOMReader/files.cmake index e72f2b58c1..7218fa0662 100644 --- a/Modules/DICOMReader/files.cmake +++ b/Modules/DICOMReader/files.cmake @@ -1,62 +1,63 @@ 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 + mitkDICOMIOMetaInformationPropertyConstants.cpp legacy/mitkDicomSeriesReader.cpp legacy/mitkDicomSR_GantryTiltInformation.cpp legacy/mitkDicomSR_ImageBlockDescriptor.cpp legacy/mitkDicomSR_LoadDICOMRGBPixel.cpp legacy/mitkDicomSR_LoadDICOMRGBPixel4D.cpp legacy/mitkDicomSR_LoadDICOMScalar.cpp legacy/mitkDicomSR_LoadDICOMScalar4D.cpp legacy/mitkDicomSR_SliceGroupingResult.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/3D/simpleinstancenumber_soft.xml configurations/3DnT/classicreader.xml configurations/3DnT/imageposition.xml configurations/3DnT/imageposition_byacquisition.xml configurations/3DnT/imageposition_bytriggertime.xml ) diff --git a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h index 1acff14ce9..aa56718ad8 100644 --- a/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h +++ b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h @@ -1,70 +1,70 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKBASEDICOMREADERSERVICE_H #define MITKBASEDICOMREADERSERVICE_H #include #include #include "MitkDICOMReaderExports.h" namespace mitk { /** Base class for service wrappers that make DICOMFileReader from the DICOMReader module usable. */ class MITKDICOMREADER_EXPORT BaseDICOMReaderService : public AbstractFileReader { public: BaseDICOMReaderService(const std::string& description); BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description); using AbstractFileReader::Read; - /** Uses this->GetRelevantFile() and this->GetReader to load the image. - * data and puts it into base data instances-*/ - std::vector > Read() override; - IFileReader::ConfidenceLevel GetConfidenceLevel() const override; protected: - /** Returns the list of all DCM files that are in the same directory + /** Uses this->GetRelevantFile() and this->GetReader to load the image. + * data and puts it into base data instances-*/ + std::vector> DoRead() override; + + /** Returns the list of all DCM files that are in the same directory * like this->GetLocalFileName().*/ mitk::StringList GetDICOMFilesInSameDirectory() const; /** Returns the reader instance that should be used. The descission may be based * one the passed relevant file list.*/ virtual mitk::DICOMFileReader::Pointer GetReader(const mitk::StringList& relevantFiles) const = 0; void SetOnlyRegardOwnSeries(bool); bool GetOnlyRegardOwnSeries() const; private: /** Flags that constrols if the read() operation should only regard DICOM files of the same series if the specified GetLocalFileName() is a file. If it is a director, this flag has no impact (it is assumed false then). */ bool m_OnlyRegardOwnSeries = true; }; class IPropertyProvider; /** Helper function that generates a name string (e.g. for DataNode names) from the DICOM properties of the passed provider instance. If the instance is nullptr, or has no dicom properties DataNode::NO_NAME_VALUE() will be returned.*/ std::string MITKDICOMREADER_EXPORT GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider); } #endif // MITKBASEDICOMREADERSERVICE_H diff --git a/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h b/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h new file mode 100644 index 0000000000..5a6bc3eaa7 --- /dev/null +++ b/Modules/DICOMReader/include/mitkDICOMIOMetaInformationPropertyConstants.h @@ -0,0 +1,51 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#ifndef MITKDICOMIOMETAINFORMATIONCONSTANTS_H_ +#define MITKDICOMIOMETAINFORMATIONCONSTANTS_H_ + +#include + +#include "mitkPropertyKeyPath.h" + +namespace mitk +{ + /** + * @ingroup IO + * @brief The IOMetaInformationPropertyConsants struct + */ + struct MITKDICOMREADER_EXPORT DICOMIOMetaInformationPropertyConstants + { + //Path to the property containing the name of the dicom reader configuration used to read the data + static PropertyKeyPath READER_CONFIGURATION(); + //Path to the property containing the files the dicom reader used in a TemporoSpatialProperty + static PropertyKeyPath READER_FILES(); + //Path to the property containing PixelSpacingInterpretationString for the read data + static PropertyKeyPath READER_PIXEL_SPACING_INTERPRETATION_STRING(); + //Path to the property containing PixelSpacingInterpretation for the read data + static PropertyKeyPath READER_PIXEL_SPACING_INTERPRETATION(); + //Path to the property containing ReaderImplementationLevelString for the read data + static PropertyKeyPath READER_IMPLEMENTATION_LEVEL_STRING(); + //Path to the property containing ReaderImplementationLevel for the read data + static PropertyKeyPath READER_IMPLEMENTATION_LEVEL(); + //Path to the property containing the indicator of the gantry tilt was corrected when reading the data + static PropertyKeyPath READER_GANTRY_TILT_CORRECTED(); + //Path to the property containing the indicator of the data was read as 3D+t + static PropertyKeyPath READER_3D_plus_t(); + //Path to the property containing the version of GDCM used to read the data + static PropertyKeyPath READER_GDCM(); + //Path to the property containing the version of DCMTK used to read the data + static PropertyKeyPath READER_DCMTK(); + }; +} + +#endif // MITKIOCONSTANTS_H_ diff --git a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp index aa9d0f3e4b..2163a64b75 100644 --- a/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp +++ b/Modules/DICOMReader/src/mitkBaseDICOMReaderService.cpp @@ -1,221 +1,225 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkBaseDICOMReaderService.h" #include #include #include #include #include #include #include #include "legacy/mitkDicomSeriesReader.h" #include #include #include "mitkIPropertyProvider.h" #include "mitkPropertyNameHelper.h" +#include "mitkPropertyKeyPath.h" +#include "mitkDICOMIOMetaInformationPropertyConstants.h" #include #include #include namespace mitk { BaseDICOMReaderService::BaseDICOMReaderService(const std::string& description) : AbstractFileReader(CustomMimeType(IOMimeTypes::DICOM_MIMETYPE()), description) { } BaseDICOMReaderService::BaseDICOMReaderService(const mitk::CustomMimeType& customType, const std::string& description) : AbstractFileReader(customType, description) { } void BaseDICOMReaderService::SetOnlyRegardOwnSeries(bool regard) { m_OnlyRegardOwnSeries = regard; } bool BaseDICOMReaderService::GetOnlyRegardOwnSeries() const { return m_OnlyRegardOwnSeries; } -std::vector > BaseDICOMReaderService::Read() +std::vector > BaseDICOMReaderService::DoRead() { std::vector result; const std::string fileName = this->GetLocalFileName(); //special handling of Philips 3D US DICOM. //Copied from DICOMSeriesReaderService if (DicomSeriesReader::IsPhilips3DDicom(fileName)) { MITK_INFO << "it is a Philips3D US Dicom file" << std::endl; mitk::LocaleSwitch localeSwitch("C"); std::locale previousCppLocale(std::cin.getloc()); std::locale l("C"); std::cin.imbue(l); DataNode::Pointer node = DataNode::New(); mitk::DicomSeriesReader::StringContainer stringvec; stringvec.push_back(fileName); if (DicomSeriesReader::LoadDicomSeries(stringvec, *node)) { BaseData::Pointer data = node->GetData(); StringProperty::Pointer nameProp = StringProperty::New(itksys::SystemTools::GetFilenameName(fileName)); data->GetPropertyList()->SetProperty("name", nameProp); result.push_back(data); } std::cin.imbue(previousCppLocale); return result; } //Normal DICOM handling (It wasn't a Philips 3D US) mitk::StringList relevantFiles = this->GetDICOMFilesInSameDirectory(); if (relevantFiles.empty()) { MITK_INFO << "DICOMReader service found no relevant files in specified location. No data is loaded. Location: "<GetReader(relevantFiles); if(reader.IsNull()) { MITK_INFO << "DICOMReader service found no suitable reader configuration for relevant files."; } else { if (!pathIsDirectory) { //we ensure that we only load the relevant image block files const auto nrOfOutputs = reader->GetNumberOfOutputs(); for (unsigned int outputIndex = 0; outputIndex < nrOfOutputs; ++outputIndex) { const auto frameList = reader->GetOutput(outputIndex).GetImageFrameList(); auto finding = std::find_if(frameList.begin(), frameList.end(), [&](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename == fileName; }); if (finding != frameList.end()) { //we have the block containing the fileName -> these are the realy relevant files. relevantFiles.resize(frameList.size()); std::transform(frameList.begin(), frameList.end(), relevantFiles.begin(), [](const DICOMImageFrameInfo::Pointer& frame) { return frame->Filename; }); break; } } } const unsigned int ntotalfiles = relevantFiles.size(); for( unsigned int i=0; i< ntotalfiles; i++) { m_ReadFiles.push_back( relevantFiles.at(i) ); } reader->SetAdditionalTagsOfInterest(mitk::GetCurrentDICOMTagsOfInterest()); reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor); reader->SetInputFiles(relevantFiles); mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->AddTagPaths(reader->GetTagsOfInterest()); scanner->SetInputFiles(relevantFiles); scanner->Scan(); reader->SetTagCache(scanner->GetScanCache()); reader->AnalyzeInputFiles(); reader->LoadImages(); for (unsigned int i = 0; i < reader->GetNumberOfOutputs(); ++i) { const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(i); mitk::BaseData::Pointer data = desc.GetMitkImage().GetPointer(); std::string nodeName = GenerateNameFromDICOMProperties(&desc); StringProperty::Pointer nameProp = StringProperty::New(nodeName); data->SetProperty("name", nameProp); + data->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()), StringProperty::New(reader->GetConfigurationLabel())); + result.push_back(data); } } } return result; } StringList BaseDICOMReaderService::GetDICOMFilesInSameDirectory() const { std::string fileName = this->GetLocalFileName(); mitk::StringList relevantFiles = mitk::GetDICOMFilesInSameDirectory(fileName); return relevantFiles; } IFileReader::ConfidenceLevel BaseDICOMReaderService::GetConfidenceLevel() const { IFileReader::ConfidenceLevel abstractConfidence = AbstractFileReader::GetConfidenceLevel(); if (Unsupported == abstractConfidence) { if (itksys::SystemTools::FileIsDirectory(this->GetInputLocation().c_str())) { // In principle we support dicom directories return Supported; } } return abstractConfidence; } std::string GenerateNameFromDICOMProperties(const mitk::IPropertyProvider* provider) { std::string nodeName = mitk::DataNode::NO_NAME_VALUE(); auto studyProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str()); if (studyProp.IsNotNull()) { nodeName = studyProp->GetValueAsString(); } auto seriesProp = provider->GetConstProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103E).c_str()); if (seriesProp.IsNotNull()) { if (studyProp.IsNotNull()) { nodeName += " / "; } else { nodeName = ""; } nodeName += seriesProp->GetValueAsString(); } return nodeName; }; } diff --git a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp index 8e774692e7..1c497e6908 100644 --- a/Modules/DICOMReader/src/mitkDICOMFileReader.cpp +++ b/Modules/DICOMReader/src/mitkDICOMFileReader.cpp @@ -1,225 +1,227 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDICOMFileReader.h" #include mitk::DICOMFileReader ::DICOMFileReader() :itk::Object() { } mitk::DICOMFileReader ::~DICOMFileReader() { } mitk::DICOMFileReader ::DICOMFileReader(const DICOMFileReader& other ) :itk::Object() ,m_InputFilenames( other.m_InputFilenames ) ,m_Outputs( other.m_Outputs ) ,m_ConfigLabel( other.m_ConfigLabel ) ,m_ConfigDescription( other.m_ConfigDescription ) { } mitk::DICOMFileReader& mitk::DICOMFileReader ::operator=(const DICOMFileReader& other) { if (this != &other) { m_InputFilenames = other.m_InputFilenames; m_Outputs = other.m_Outputs; m_ConfigLabel = other.m_ConfigLabel; m_ConfigDescription = other.m_ConfigDescription; + m_AdditionalTagsOfInterest = other.m_AdditionalTagsOfInterest; + m_TagLookupTableToPropertyFunctor = other.m_TagLookupTableToPropertyFunctor; } return *this; } void mitk::DICOMFileReader ::SetConfigurationLabel(const std::string& label) { m_ConfigLabel = label; this->Modified(); } std::string mitk::DICOMFileReader ::GetConfigurationLabel() const { return m_ConfigLabel; } void mitk::DICOMFileReader ::SetConfigurationDescription(const std::string& desc) { m_ConfigDescription = desc; this->Modified(); } std::string mitk::DICOMFileReader ::GetConfigurationDescription() const { return m_ConfigDescription; } void mitk::DICOMFileReader ::SetInputFiles( const StringList& filenames) { m_InputFilenames = filenames; this->Modified(); } const mitk::StringList& mitk::DICOMFileReader ::GetInputFiles() const { return m_InputFilenames; } unsigned int mitk::DICOMFileReader ::GetNumberOfOutputs() const { return m_Outputs.size(); } void mitk::DICOMFileReader ::ClearOutputs() { m_Outputs.clear(); } void mitk::DICOMFileReader ::SetNumberOfOutputs(unsigned int numberOfOutputs) { m_Outputs.resize(numberOfOutputs); } void mitk::DICOMFileReader ::SetOutput(unsigned int index, const mitk::DICOMImageBlockDescriptor& output) { if (index < m_Outputs.size()) { m_Outputs[index] = output; } else { std::stringstream ss; ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)"; throw std::invalid_argument( ss.str() ); } } void mitk::DICOMFileReader ::PrintConfiguration(std::ostream& os) const { os << "---- Configuration of " << this->GetNameOfClass() <<" " << (void*)this << " ----"<< std::endl; this->InternalPrintConfiguration(os); os << "---- End of configuration ----" << std::endl; } void mitk::DICOMFileReader ::PrintOutputs(std::ostream& os, bool filenameDetails) const { os << "---- Outputs of DICOMFilereader " << (void*)this << " ----"<< std::endl; for (unsigned int o = 0; o < m_Outputs.size(); ++o) { os << "-- Output " << o << std::endl; const DICOMImageBlockDescriptor& block = m_Outputs[o]; block.Print(os, filenameDetails); } os << "---- End of output list ----" << std::endl; } const mitk::DICOMImageBlockDescriptor& mitk::DICOMFileReader ::GetOutput(unsigned int index) const { if (index < m_Outputs.size()) { return m_Outputs[index]; } else { std::stringstream ss; ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)"; throw std::invalid_argument( ss.str() ); } } mitk::DICOMImageBlockDescriptor& mitk::DICOMFileReader ::InternalGetOutput(unsigned int index) { if (index < m_Outputs.size()) { return m_Outputs[index]; } else { std::stringstream ss; ss << "Index " << index << " out of range (" << m_Outputs.size() << " indices reserved)"; throw std::invalid_argument( ss.str() ); } } bool mitk::DICOMFileReader ::IsDICOM(const std::string& filename) { itk::GDCMImageIO::Pointer io = itk::GDCMImageIO::New(); return io->CanReadFile( filename.c_str() ); } mitk::DICOMFileReader::AdditionalTagsMapType mitk::DICOMFileReader::GetAdditionalTagsOfInterest() const { return m_AdditionalTagsOfInterest; } void mitk::DICOMFileReader::SetAdditionalTagsOfInterest( const AdditionalTagsMapType& tagList) { m_AdditionalTagsOfInterest = tagList; this->Modified(); } void mitk::DICOMFileReader::SetTagLookupTableToPropertyFunctor( mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor functor ) { m_TagLookupTableToPropertyFunctor = functor; this->Modified(); } mitk::DICOMImageBlockDescriptor::TagLookupTableToPropertyFunctor mitk::DICOMFileReader::GetTagLookupTableToPropertyFunctor() const { return m_TagLookupTableToPropertyFunctor; } diff --git a/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp b/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp new file mode 100644 index 0000000000..beecb531ed --- /dev/null +++ b/Modules/DICOMReader/src/mitkDICOMIOMetaInformationPropertyConstants.cpp @@ -0,0 +1,67 @@ +/*============================================================================ + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center (DKFZ) +All rights reserved. + +Use of this source code is governed by a 3-clause BSD license that can be +found in the LICENSE file. + +============================================================================*/ + +#include "mitkDICOMIOMetaInformationPropertyConstants.h" + +namespace mitk +{ + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_FILES() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "files" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "PixelSpacingInterpretationString" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "PixelSpacingInterpretation" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "ReaderImplementationLevelString" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "ReaderImplementationLevel" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "GantyTiltCorrected" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "3D+t" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_GDCM() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "gdcm" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_DCMTK() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "dcmtk" }); + } + + PropertyKeyPath DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION() + { + return PropertyKeyPath({ "MITK", "IO", "reader", "DICOM", "configuration" }); + } +} diff --git a/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp b/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp index b4244d44d2..69ca0c9109 100644 --- a/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp +++ b/Modules/DICOMReader/src/mitkDICOMImageBlockDescriptor.cpp @@ -1,888 +1,913 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDICOMImageBlockDescriptor.h" #include "mitkStringProperty.h" #include "mitkLevelWindowProperty.h" +#include "mitkPropertyKeyPath.h" +#include "mitkDICOMIOMetaInformationPropertyConstants.h" #include #include +#include +#include mitk::DICOMImageBlockDescriptor::DICOMImageBlockDescriptor() : m_ReaderImplementationLevel( SOPClassUnknown ) , m_PropertyList( PropertyList::New() ) , m_TagCache( nullptr ) , m_PropertiesOutOfDate( true ) { m_PropertyFunctor = &mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues; } mitk::DICOMImageBlockDescriptor::~DICOMImageBlockDescriptor() { } mitk::DICOMImageBlockDescriptor::DICOMImageBlockDescriptor( const DICOMImageBlockDescriptor& other ) : m_ImageFrameList( other.m_ImageFrameList ) , m_MitkImage( other.m_MitkImage ) , m_SliceIsLoaded( other.m_SliceIsLoaded ) , m_ReaderImplementationLevel( other.m_ReaderImplementationLevel ) , m_TiltInformation( other.m_TiltInformation ) , m_PropertyList( other.m_PropertyList->Clone() ) , m_TagCache( other.m_TagCache ) , m_PropertiesOutOfDate( other.m_PropertiesOutOfDate ) , m_AdditionalTagMap(other.m_AdditionalTagMap) , m_FoundAdditionalTags(other.m_FoundAdditionalTags) , m_PropertyFunctor(other.m_PropertyFunctor) { if ( m_MitkImage ) { m_MitkImage = m_MitkImage->Clone(); } - - m_PropertyFunctor = &mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues; } mitk::DICOMImageBlockDescriptor& mitk::DICOMImageBlockDescriptor:: operator=( const DICOMImageBlockDescriptor& other ) { if ( this != &other ) { m_ImageFrameList = other.m_ImageFrameList; m_MitkImage = other.m_MitkImage; m_SliceIsLoaded = other.m_SliceIsLoaded; m_ReaderImplementationLevel = other.m_ReaderImplementationLevel; m_TiltInformation = other.m_TiltInformation; m_AdditionalTagMap = other.m_AdditionalTagMap; m_FoundAdditionalTags = other.m_FoundAdditionalTags; m_PropertyFunctor = other.m_PropertyFunctor; if ( other.m_PropertyList ) { m_PropertyList = other.m_PropertyList->Clone(); } if ( other.m_MitkImage ) { m_MitkImage = other.m_MitkImage->Clone(); } m_TagCache = other.m_TagCache; m_PropertiesOutOfDate = other.m_PropertiesOutOfDate; } return *this; } mitk::DICOMTagList mitk::DICOMImageBlockDescriptor::GetTagsOfInterest() { DICOMTagList completeList; completeList.push_back( DICOMTag( 0x0018, 0x1164 ) ); // pixel spacing completeList.push_back( DICOMTag( 0x0028, 0x0030 ) ); // imager pixel spacing completeList.push_back( DICOMTag( 0x0008, 0x0018 ) ); // sop instance UID completeList.push_back( DICOMTag( 0x0008, 0x0016 ) ); // sop class UID completeList.push_back( DICOMTag( 0x0020, 0x0011 ) ); // series number completeList.push_back( DICOMTag( 0x0008, 0x1030 ) ); // study description completeList.push_back( DICOMTag( 0x0008, 0x103e ) ); // series description completeList.push_back( DICOMTag( 0x0008, 0x0060 ) ); // modality completeList.push_back( DICOMTag( 0x0018, 0x0024 ) ); // sequence name completeList.push_back( DICOMTag( 0x0020, 0x0037 ) ); // image orientation completeList.push_back( DICOMTag( 0x0020, 0x1041 ) ); // slice location completeList.push_back( DICOMTag( 0x0020, 0x0012 ) ); // acquisition number completeList.push_back( DICOMTag( 0x0020, 0x0013 ) ); // instance number completeList.push_back( DICOMTag( 0x0020, 0x0032 ) ); // image position patient completeList.push_back( DICOMTag( 0x0028, 0x1050 ) ); // window center completeList.push_back( DICOMTag( 0x0028, 0x1051 ) ); // window width completeList.push_back( DICOMTag( 0x0008, 0x0008 ) ); // image type completeList.push_back( DICOMTag( 0x0028, 0x0004 ) ); // photometric interpretation return completeList; } void mitk::DICOMImageBlockDescriptor::SetAdditionalTagsOfInterest( const AdditionalTagsMapType& tagMap) { m_AdditionalTagMap = tagMap; } void mitk::DICOMImageBlockDescriptor::SetTiltInformation( const GantryTiltInformation& info ) { m_TiltInformation = info; } const mitk::GantryTiltInformation mitk::DICOMImageBlockDescriptor::GetTiltInformation() const { return m_TiltInformation; } void mitk::DICOMImageBlockDescriptor::SetImageFrameList( const DICOMImageFrameList& framelist ) { m_ImageFrameList = framelist; m_SliceIsLoaded.resize( framelist.size() ); m_SliceIsLoaded.assign( framelist.size(), false ); m_PropertiesOutOfDate = true; } const mitk::DICOMImageFrameList& mitk::DICOMImageBlockDescriptor::GetImageFrameList() const { return m_ImageFrameList; } void mitk::DICOMImageBlockDescriptor::SetMitkImage( Image::Pointer image ) { if ( m_MitkImage != image ) { if ( m_TagCache.IsExpired() ) { MITK_ERROR << "Unable to describe MITK image with properties without a tag-cache object!"; m_MitkImage = nullptr; return; } if ( m_ImageFrameList.empty() ) { MITK_ERROR << "Unable to describe MITK image with properties without a frame list!"; m_MitkImage = nullptr; return; } // Should verify that the image matches m_ImageFrameList and m_TagCache // however, this is hard to do without re-analyzing all // TODO we should at least make sure that the number of frames is identical (plus rows/columns, // orientation) // without gantry tilt correction, we can also check image origin m_MitkImage = this->DescribeImageWithProperties( this->FixupSpacing( image ) ); } } mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::GetMitkImage() const { return m_MitkImage; } mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::FixupSpacing( Image* mitkImage ) { if ( mitkImage ) { Vector3D imageSpacing = mitkImage->GetGeometry()->GetSpacing(); ScalarType desiredSpacingX = imageSpacing[0]; ScalarType desiredSpacingY = imageSpacing[1]; this->GetDesiredMITKImagePixelSpacing( desiredSpacingX, desiredSpacingY ); // prefer pixel spacing over imager pixel spacing if ( desiredSpacingX <= 0 || desiredSpacingY <= 0 ) { return mitkImage; } MITK_DEBUG << "Loaded image with spacing " << imageSpacing[0] << ", " << imageSpacing[1]; MITK_DEBUG << "Found correct spacing info " << desiredSpacingX << ", " << desiredSpacingY; imageSpacing[0] = desiredSpacingX; imageSpacing[1] = desiredSpacingY; mitkImage->GetGeometry()->SetSpacing( imageSpacing ); } return mitkImage; } void mitk::DICOMImageBlockDescriptor::SetSliceIsLoaded( unsigned int index, bool isLoaded ) { if ( index < m_SliceIsLoaded.size() ) { m_SliceIsLoaded[index] = isLoaded; } else { std::stringstream ss; ss << "Index " << index << " out of range (" << m_SliceIsLoaded.size() << " indices reserved)"; throw std::invalid_argument( ss.str() ); } } bool mitk::DICOMImageBlockDescriptor::IsSliceLoaded( unsigned int index ) const { if ( index < m_SliceIsLoaded.size() ) { return m_SliceIsLoaded[index]; } else { std::stringstream ss; ss << "Index " << index << " out of range (" << m_SliceIsLoaded.size() << " indices reserved)"; throw std::invalid_argument( ss.str() ); } } bool mitk::DICOMImageBlockDescriptor::AllSlicesAreLoaded() const { bool allLoaded = true; for ( auto iter = m_SliceIsLoaded.cbegin(); iter != m_SliceIsLoaded.cend(); ++iter ) { allLoaded &= *iter; } return allLoaded; } /* PS defined IPS defined PS==IPS 0 0 --> UNKNOWN spacing, loader will invent 0 1 --> spacing as at detector surface 1 0 --> spacing as in patient 1 1 0 --> detector surface spacing CORRECTED for geometrical magnifications: spacing as in patient 1 1 1 --> detector surface spacing NOT corrected for geometrical magnifications: spacing as at detector */ mitk::PixelSpacingInterpretation mitk::DICOMImageBlockDescriptor::GetPixelSpacingInterpretation() const { if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() ) { MITK_ERROR << "Invalid call to GetPixelSpacingInterpretation. Need to have initialized tag-cache!"; return SpacingUnknown; } const std::string pixelSpacing = this->GetPixelSpacing(); const std::string imagerPixelSpacing = this->GetImagerPixelSpacing(); if ( pixelSpacing.empty() ) { if ( imagerPixelSpacing.empty() ) { return SpacingUnknown; } else { return SpacingAtDetector; } } else // Pixel Spacing defined { if ( imagerPixelSpacing.empty() ) { return SpacingInPatient; } else if ( pixelSpacing != imagerPixelSpacing ) { return SpacingInPatient; } else { return SpacingAtDetector; } } } std::string mitk::DICOMImageBlockDescriptor::GetPixelSpacing() const { if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() ) { MITK_ERROR << "Invalid call to GetPixelSpacing. Need to have initialized tag-cache!"; return std::string( "" ); } static const DICOMTag tagPixelSpacing( 0x0028, 0x0030 ); return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagPixelSpacing ).value; } std::string mitk::DICOMImageBlockDescriptor::GetImagerPixelSpacing() const { if ( m_ImageFrameList.empty() || m_TagCache.IsExpired() ) { MITK_ERROR << "Invalid call to GetImagerPixelSpacing. Need to have initialized tag-cache!"; return std::string( "" ); } static const DICOMTag tagImagerPixelSpacing( 0x0018, 0x1164 ); return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagImagerPixelSpacing ).value; } void mitk::DICOMImageBlockDescriptor::GetDesiredMITKImagePixelSpacing( ScalarType& spacingX, ScalarType& spacingY ) const { const std::string pixelSpacing = this->GetPixelSpacing(); // preference for "in patient" pixel spacing if ( !DICOMStringToSpacing( pixelSpacing, spacingX, spacingY ) ) { const std::string imagerPixelSpacing = this->GetImagerPixelSpacing(); // fallback to "on detector" spacing if ( !DICOMStringToSpacing( imagerPixelSpacing, spacingX, spacingY ) ) { // at this point we have no hints whether the spacing is correct // do a quick sanity check and either trust in the input or set both to 1 // We assume neither spacing to be negative, zero or unexpectedly large for // medical images if (spacingX < mitk::eps || spacingX > 1000 || spacingY < mitk::eps || spacingY > 1000) { spacingX = spacingY = 1.0; } } } } void mitk::DICOMImageBlockDescriptor::SetProperty( const std::string& key, BaseProperty* value ) { m_PropertyList->SetProperty( key, value ); } mitk::BaseProperty* mitk::DICOMImageBlockDescriptor::GetProperty( const std::string& key ) const { this->UpdateImageDescribingProperties(); return m_PropertyList->GetProperty( key ); } std::string mitk::DICOMImageBlockDescriptor::GetPropertyAsString( const std::string& key ) const { this->UpdateImageDescribingProperties(); const mitk::BaseProperty::Pointer property = m_PropertyList->GetProperty( key ); if ( property.IsNotNull() ) { return property->GetValueAsString(); } else { return std::string( "" ); } } void mitk::DICOMImageBlockDescriptor::SetFlag( const std::string& key, bool value ) { m_PropertyList->ReplaceProperty( key, BoolProperty::New( value ) ); } bool mitk::DICOMImageBlockDescriptor::GetFlag( const std::string& key, bool defaultValue ) const { this->UpdateImageDescribingProperties(); BoolProperty::ConstPointer boolProp = dynamic_cast( this->GetProperty( key ) ); if ( boolProp.IsNotNull() ) { return boolProp->GetValue(); } else { return defaultValue; } } void mitk::DICOMImageBlockDescriptor::SetIntProperty( const std::string& key, int value ) { m_PropertyList->ReplaceProperty( key, IntProperty::New( value ) ); } int mitk::DICOMImageBlockDescriptor::GetIntProperty( const std::string& key, int defaultValue ) const { this->UpdateImageDescribingProperties(); IntProperty::ConstPointer intProp = dynamic_cast( this->GetProperty( key ) ); if ( intProp.IsNotNull() ) { return intProp->GetValue(); } else { return defaultValue; } } double mitk::DICOMImageBlockDescriptor::stringtodouble( const std::string& str ) const { double d; std::string trimmedstring( str ); try { trimmedstring = trimmedstring.erase( trimmedstring.find_last_not_of( " \n\r\t" ) + 1 ); } catch ( ... ) { // no last not of } std::string firstcomponent( trimmedstring ); try { firstcomponent = trimmedstring.erase( trimmedstring.find_first_of( "\\" ) ); } catch ( ... ) { // no last not of } std::istringstream converter( firstcomponent ); if ( !firstcomponent.empty() && ( converter >> d ) && converter.eof() ) { return d; } else { throw std::invalid_argument( "Argument is not a convertable number" ); } } mitk::Image::Pointer mitk::DICOMImageBlockDescriptor::DescribeImageWithProperties( Image* mitkImage ) { // TODO: this is a collection of properties that have been provided by the // legacy DicomSeriesReader. // We should at some point clean up this collection and name them in a more // consistent way! if ( !mitkImage ) return mitkImage; + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_FILES()), this->GetProperty("filenamesForSlices")); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING()), + StringProperty::New(PixelSpacingInterpretationToString(this->GetPixelSpacingInterpretation()))); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION()), + GenericProperty::New(this->GetPixelSpacingInterpretation())); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING()), + StringProperty::New(ReaderImplementationLevelToString(m_ReaderImplementationLevel))); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL()), + GenericProperty::New(m_ReaderImplementationLevel)); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED()), + BoolProperty::New(this->GetTiltInformation().IsRegularGantryTilt())); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t()), BoolProperty::New(this->GetFlag("3D+t", false))); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_GDCM()), StringProperty::New(gdcm::Version::GetVersion())); + mitkImage->SetProperty(PropertyKeyPathToPropertyName(DICOMIOMetaInformationPropertyConstants::READER_DCMTK()), StringProperty::New(PACKAGE_VERSION)); + + // get all found additional tags of interest + + for (auto tag : m_FoundAdditionalTags) + { + BaseProperty* prop = this->GetProperty(tag); + if (prop) + { + mitkImage->SetProperty(tag.c_str(), prop); + } + } + + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + //// Deprecated properties should be removed sooner then later (see above) + ///////////////////////////////////////////////////////////////////////////// + ///////////////////////////////////////////////////////////////////////////// + // first part: add some tags that describe individual slices // these propeties are defined at analysis time (see UpdateImageDescribingProperties()) const char* propertyKeySliceLocation = "dicom.image.0020.1041"; const char* propertyKeyInstanceNumber = "dicom.image.0020.0013"; const char* propertyKeySOPInstanceUID = "dicom.image.0008.0018"; mitkImage->SetProperty( propertyKeySliceLocation, this->GetProperty( "sliceLocationForSlices" ) ); mitkImage->SetProperty( propertyKeyInstanceNumber, this->GetProperty( "instanceNumberForSlices" ) ); mitkImage->SetProperty( propertyKeySOPInstanceUID, this->GetProperty( "SOPInstanceUIDForSlices" ) ); - mitkImage->SetProperty( "files", this->GetProperty( "filenamesForSlices" ) ); + mitkImage->SetProperty( "files", this->GetProperty( "filenamesForSlices_deprecated" ) ); // second part: add properties that describe the whole image block mitkImage->SetProperty( "dicomseriesreader.SOPClassUID", StringProperty::New( this->GetSOPClassUID() ) ); mitkImage->SetProperty( "dicomseriesreader.SOPClass", StringProperty::New( this->GetSOPClassUIDAsName() ) ); mitkImage->SetProperty( "dicomseriesreader.PixelSpacingInterpretationString", StringProperty::New( PixelSpacingInterpretationToString( this->GetPixelSpacingInterpretation() ) ) ); mitkImage->SetProperty( "dicomseriesreader.PixelSpacingInterpretation", GenericProperty::New( this->GetPixelSpacingInterpretation() ) ); mitkImage->SetProperty( "dicomseriesreader.ReaderImplementationLevelString", StringProperty::New( ReaderImplementationLevelToString( m_ReaderImplementationLevel ) ) ); mitkImage->SetProperty( "dicomseriesreader.ReaderImplementationLevel", GenericProperty::New( m_ReaderImplementationLevel ) ); mitkImage->SetProperty( "dicomseriesreader.GantyTiltCorrected", BoolProperty::New( this->GetTiltInformation().IsRegularGantryTilt() ) ); mitkImage->SetProperty( "dicomseriesreader.3D+t", BoolProperty::New( this->GetFlag( "3D+t", false ) ) ); // level window const std::string windowCenter = this->GetPropertyAsString( "windowCenter" ); const std::string windowWidth = this->GetPropertyAsString( "windowWidth" ); try { const double level = stringtodouble( windowCenter ); const double window = stringtodouble( windowWidth ); mitkImage->SetProperty( "levelwindow", LevelWindowProperty::New( LevelWindow( level, window ) ) ); } catch ( ... ) { // nothing, no levelwindow to be predicted... } const std::string modality = this->GetPropertyAsString( "modality" ); mitkImage->SetProperty( "modality", StringProperty::New( modality ) ); mitkImage->SetProperty( "dicom.pixel.PhotometricInterpretation", this->GetProperty( "photometricInterpretation" ) ); mitkImage->SetProperty( "dicom.image.imagetype", this->GetProperty( "imagetype" ) ); mitkImage->SetProperty( "dicom.study.StudyDescription", this->GetProperty( "studyDescription" ) ); mitkImage->SetProperty( "dicom.series.SeriesDescription", this->GetProperty( "seriesDescription" ) ); mitkImage->SetProperty( "dicom.pixel.Rows", this->GetProperty( "rows" ) ); mitkImage->SetProperty( "dicom.pixel.Columns", this->GetProperty( "columns" ) ); - // third part: get all found additional tags of interest - - for (auto tag : m_FoundAdditionalTags) - { - BaseProperty* prop = this->GetProperty(tag); - if (prop) - { - mitkImage->SetProperty(tag.c_str(), prop); - } - } - // fourth part: get something from ImageIO. BUT this needs to be created elsewhere. or not at all! return mitkImage; } void mitk::DICOMImageBlockDescriptor::SetReaderImplementationLevel( const ReaderImplementationLevel& level ) { m_ReaderImplementationLevel = level; } mitk::ReaderImplementationLevel mitk::DICOMImageBlockDescriptor::GetReaderImplementationLevel() const { return m_ReaderImplementationLevel; } std::string mitk::DICOMImageBlockDescriptor::GetSOPClassUID() const { if ( !m_ImageFrameList.empty() && !m_TagCache.IsExpired() ) { static const DICOMTag tagSOPClassUID( 0x0008, 0x0016 ); return m_TagCache.Lock()->GetTagValue( m_ImageFrameList.front(), tagSOPClassUID ).value; } else { MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::GetSOPClassUID(). Need to have initialized tag-cache!"; return std::string( "" ); } } std::string mitk::DICOMImageBlockDescriptor::GetSOPClassUIDAsName() const { if ( !m_ImageFrameList.empty() && !m_TagCache.IsExpired() ) { gdcm::UIDs uidKnowledge; uidKnowledge.SetFromUID( this->GetSOPClassUID().c_str() ); const char* name = uidKnowledge.GetName(); if ( name ) { return std::string( name ); } else { return std::string( "" ); } } else { MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::GetSOPClassUIDAsName(). Need to have " "initialized tag-cache!"; return std::string( "" ); } } int mitk::DICOMImageBlockDescriptor::GetNumberOfTimeSteps() const { int result = 1; this->m_PropertyList->GetIntProperty("timesteps", result); return result; }; int mitk::DICOMImageBlockDescriptor::GetNumberOfFramesPerTimeStep() const { const int numberOfTimesteps = this->GetNumberOfTimeSteps(); int numberOfFramesPerTimestep = this->m_ImageFrameList.size() / numberOfTimesteps; assert(int(double((double)this->m_ImageFrameList.size() / (double)numberOfTimesteps)) == numberOfFramesPerTimestep); // this should hold return numberOfFramesPerTimestep; }; void mitk::DICOMImageBlockDescriptor::SetTagCache( DICOMTagCache* privateCache ) { // this must only be used during loading and never afterwards m_TagCache = privateCache; } #define printPropertyRange( label, property_name ) \ \ { \ const std::string first = this->GetPropertyAsString( #property_name "First" ); \ const std::string last = this->GetPropertyAsString( #property_name "Last" ); \ if ( !first.empty() || !last.empty() ) \ { \ if ( first == last ) \ { \ os << " " label ": '" << first << "'" << std::endl; \ } \ else \ { \ os << " " label ": '" << first << "' - '" << last << "'" << std::endl; \ } \ } \ \ } #define printProperty( label, property_name ) \ \ { \ const std::string first = this->GetPropertyAsString( #property_name ); \ if ( !first.empty() ) \ { \ os << " " label ": '" << first << "'" << std::endl; \ } \ \ } #define printBool( label, commands ) \ \ { \ os << " " label ": '" << ( commands ? "yes" : "no" ) << "'" << std::endl; \ \ } void mitk::DICOMImageBlockDescriptor::Print(std::ostream& os, bool filenameDetails) const { os << " Number of Frames: '" << m_ImageFrameList.size() << "'" << std::endl; os << " SOP class: '" << this->GetSOPClassUIDAsName() << "'" << std::endl; printProperty( "Series Number", seriesNumber ); printProperty( "Study Description", studyDescription ); printProperty( "Series Description", seriesDescription ); printProperty( "Modality", modality ); printProperty( "Sequence Name", sequenceName ); printPropertyRange( "Slice Location", sliceLocation ); printPropertyRange( "Acquisition Number", acquisitionNumber ); printPropertyRange( "Instance Number", instanceNumber ); printPropertyRange( "Image Position", imagePositionPatient ); printProperty( "Image Orientation", orientation ); os << " Pixel spacing interpretation: '" << PixelSpacingInterpretationToString( this->GetPixelSpacingInterpretation() ) << "'" << std::endl; printBool( "Gantry Tilt", this->GetTiltInformation().IsRegularGantryTilt() ) // printBool("3D+t", this->GetFlag("3D+t",false)) // os << " MITK image loaded: '" << (this->GetMitkImage().IsNotNull() ? "yes" : "no") << "'" << // std::endl; if ( filenameDetails ) { os << " Files in this image block:" << std::endl; for ( auto frameIter = m_ImageFrameList.begin(); frameIter != m_ImageFrameList.end(); ++frameIter ) { os << " " << ( *frameIter )->Filename; if ( ( *frameIter )->FrameNo > 0 ) { os << ", " << ( *frameIter )->FrameNo; } os << std::endl; } } } #define storeTagValueToProperty( tag_name, tag_g, tag_e ) \ \ { \ const DICOMTag t( tag_g, tag_e ); \ const std::string tagValue = tagCache->GetTagValue( firstFrame, t ).value; \ const_cast( this ) \ ->SetProperty( #tag_name, StringProperty::New( tagValue ) ); \ \ } #define storeTagValueRangeToProperty( tag_name, tag_g, tag_e ) \ \ { \ const DICOMTag t( tag_g, tag_e ); \ const std::string tagValueFirst = tagCache->GetTagValue( firstFrame, t ).value; \ const std::string tagValueLast = tagCache->GetTagValue( lastFrame, t ).value; \ const_cast( this ) \ ->SetProperty( #tag_name "First", StringProperty::New( tagValueFirst ) ); \ const_cast( this ) \ ->SetProperty( #tag_name "Last", StringProperty::New( tagValueLast ) ); \ \ } void mitk::DICOMImageBlockDescriptor::UpdateImageDescribingProperties() const { if ( !m_PropertiesOutOfDate ) return; if ( !m_ImageFrameList.empty() ) { if ( m_TagCache.IsExpired() ) { MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::UpdateImageDescribingProperties(). Need to " "have initialized tag-cache!"; return; } auto tagCache = m_TagCache.Lock(); if (tagCache.IsNull()) { MITK_ERROR << "Invalid call to DICOMImageBlockDescriptor::UpdateImageDescribingProperties(). Need to " "have initialized tag-cache!"; return; } const DICOMImageFrameInfo::Pointer firstFrame = m_ImageFrameList.front(); const DICOMImageFrameInfo::Pointer lastFrame = m_ImageFrameList.back(); // see macros above storeTagValueToProperty( seriesNumber, 0x0020, 0x0011 ); storeTagValueToProperty( studyDescription, 0x0008, 0x1030 ); storeTagValueToProperty( seriesDescription, 0x0008, 0x103e ); storeTagValueToProperty( modality, 0x0008, 0x0060 ); storeTagValueToProperty( sequenceName, 0x0018, 0x0024 ); storeTagValueToProperty( orientation, 0x0020, 0x0037 ); storeTagValueToProperty( rows, 0x0028, 0x0010 ); storeTagValueToProperty( columns, 0x0028, 0x0011 ); storeTagValueRangeToProperty( sliceLocation, 0x0020, 0x1041 ); storeTagValueRangeToProperty( acquisitionNumber, 0x0020, 0x0012 ); storeTagValueRangeToProperty( instanceNumber, 0x0020, 0x0013 ); storeTagValueRangeToProperty( imagePositionPatient, 0x0020, 0x0032 ); storeTagValueToProperty( windowCenter, 0x0028, 0x1050 ); storeTagValueToProperty( windowWidth, 0x0028, 0x1051 ); storeTagValueToProperty( imageType, 0x0008, 0x0008 ); storeTagValueToProperty( photometricInterpretation, 0x0028, 0x0004 ); // some per-image attributes // frames are just numbered starting from 0. timestep 1 (the second time-step) has frames starting at // (number-of-frames-per-timestep) // std::string propertyKeySliceLocation = "dicom.image.0020.1041"; // std::string propertyKeyInstanceNumber = "dicom.image.0020.0013"; // std::string propertyKeySOPInstanceNumber = "dicom.image.0008.0018"; StringLookupTable sliceLocationForSlices; StringLookupTable instanceNumberForSlices; StringLookupTable SOPInstanceUIDForSlices; - StringLookupTable filenamesForSlices; + StringLookupTable filenamesForSlices_deprecated; + DICOMCachedValueLookupTable filenamesForSlices; const DICOMTag tagSliceLocation( 0x0020, 0x1041 ); const DICOMTag tagInstanceNumber( 0x0020, 0x0013 ); const DICOMTag tagSOPInstanceNumber( 0x0008, 0x0018 ); std::unordered_map additionalTagResultList; unsigned int slice(0); int timePoint(-1); const int framesPerTimeStep = this->GetNumberOfFramesPerTimeStep(); for ( auto frameIter = m_ImageFrameList.begin(); frameIter != m_ImageFrameList.end(); ++slice, ++frameIter ) { unsigned int zSlice = slice%framesPerTimeStep; if ( zSlice == 0) { timePoint++; } const std::string sliceLocation = tagCache->GetTagValue( *frameIter, tagSliceLocation ).value; sliceLocationForSlices.SetTableValue( slice, sliceLocation ); const std::string instanceNumber = tagCache->GetTagValue( *frameIter, tagInstanceNumber ).value; instanceNumberForSlices.SetTableValue( slice, instanceNumber ); const std::string sopInstanceUID = tagCache->GetTagValue( *frameIter, tagSOPInstanceNumber ).value; SOPInstanceUIDForSlices.SetTableValue( slice, sopInstanceUID ); const std::string filename = ( *frameIter )->Filename; - filenamesForSlices.SetTableValue( slice, filename ); + filenamesForSlices_deprecated.SetTableValue( slice, filename ); + filenamesForSlices.SetTableValue(slice, { static_cast(timePoint), zSlice, filename }); MITK_DEBUG << "Tag info for slice " << slice << ": SL '" << sliceLocation << "' IN '" << instanceNumber << "' SOP instance UID '" << sopInstanceUID << "'"; for (const auto& tag : m_AdditionalTagMap) { const DICOMTagCache::FindingsListType findings = tagCache->GetTagValue( *frameIter, tag.first ); for (const auto& finding : findings) { if (finding.isValid) { std::string propKey = (tag.second.empty()) ? DICOMTagPathToPropertyName(finding.path) : tag.second; DICOMCachedValueInfo info{ static_cast(timePoint), zSlice, finding.value }; additionalTagResultList[propKey].SetTableValue(slice, info); } } } } // add property or properties with proper names auto* thisInstance = const_cast( this ); thisInstance->SetProperty( "sliceLocationForSlices", StringLookupTableProperty::New( sliceLocationForSlices ) ); thisInstance->SetProperty( "instanceNumberForSlices", StringLookupTableProperty::New( instanceNumberForSlices ) ); thisInstance->SetProperty( "SOPInstanceUIDForSlices", StringLookupTableProperty::New( SOPInstanceUIDForSlices ) ); - thisInstance->SetProperty( "filenamesForSlices", StringLookupTableProperty::New( filenamesForSlices ) ); - + thisInstance->SetProperty( "filenamesForSlices_deprecated", StringLookupTableProperty::New( filenamesForSlices_deprecated ) ); + thisInstance->SetProperty("filenamesForSlices", m_PropertyFunctor(filenamesForSlices)); //add properties for additional tags of interest for ( auto iter = additionalTagResultList.cbegin(); iter != additionalTagResultList.cend(); ++iter ) { thisInstance->SetProperty( iter->first, m_PropertyFunctor( iter->second ) ); thisInstance->m_FoundAdditionalTags.insert(m_FoundAdditionalTags.cend(),iter->first); } m_PropertiesOutOfDate = false; } } mitk::BaseProperty::Pointer mitk::DICOMImageBlockDescriptor::GetPropertyForDICOMValues(const DICOMCachedValueLookupTable& cacheLookupTable) { const auto& lookupTable = cacheLookupTable.GetLookupTable(); typedef std::pair PairType; if ( std::adjacent_find( lookupTable.cbegin(), lookupTable.cend(), []( const PairType& lhs, const PairType& rhs ) { return lhs.second.Value != rhs.second.Value; } ) == lookupTable.cend() ) { return static_cast( mitk::StringProperty::New(cacheLookupTable.GetTableValue(0).Value).GetPointer()); } StringLookupTable stringTable; for (auto element : lookupTable) { stringTable.SetTableValue(element.first, element.second.Value); } return static_cast( mitk::StringLookupTableProperty::New(stringTable).GetPointer()); } void mitk::DICOMImageBlockDescriptor::SetTagLookupTableToPropertyFunctor( TagLookupTableToPropertyFunctor functor ) { if ( functor != nullptr ) { m_PropertyFunctor = functor; } } mitk::BaseProperty::ConstPointer mitk::DICOMImageBlockDescriptor::GetConstProperty(const std::string &propertyKey, const std::string &/*contextName*/, bool /*fallBackOnDefaultContext*/) const { this->UpdateImageDescribingProperties(); return m_PropertyList->GetConstProperty(propertyKey); }; std::vector mitk::DICOMImageBlockDescriptor::GetPropertyKeys(const std::string &/*contextName*/, bool /*includeDefaultContext*/) const { this->UpdateImageDescribingProperties(); return m_PropertyList->GetPropertyKeys(); }; std::vector mitk::DICOMImageBlockDescriptor::GetPropertyContextNames() const { return std::vector(); }; diff --git a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp index 6da162eeb6..8896d2b9a9 100644 --- a/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp +++ b/Modules/DICOMReaderServices/src/mitkDICOMReaderServicesActivator.cpp @@ -1,45 +1,93 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkDICOMReaderServicesActivator.h" #include "mitkAutoSelectingDICOMReaderService.h" #include "mitkClassicDICOMSeriesReaderService.h" #include "mitkDICOMTagsOfInterestService.h" #include "mitkSimpleVolumeDICOMSeriesReaderService.h" +#include "mitkCoreServices.h" +#include "mitkPropertyPersistenceInfo.h" +#include "mitkDICOMIOMetaInformationPropertyConstants.h" +#include "mitkIPropertyPersistence.h" +#include "mitkTemporoSpatialStringProperty.h" #include +void AddPropertyPersistence(const mitk::PropertyKeyPath& propPath, bool temporoSpatial = false) +{ + mitk::CoreServicePointer persistenceService(mitk::CoreServices::GetPropertyPersistence()); + + mitk::PropertyPersistenceInfo::Pointer info = mitk::PropertyPersistenceInfo::New(); + if (propPath.IsExplicit()) + { + std::string name = mitk::PropertyKeyPathToPropertyName(propPath); + std::string key = name; + std::replace(key.begin(), key.end(), '.', '_'); + info->SetNameAndKey(name, key); + } + else + { + std::string key = mitk::PropertyKeyPathToPersistenceKeyRegEx(propPath); + std::string keyTemplate = mitk::PropertyKeyPathToPersistenceKeyTemplate(propPath); + std::string propRegEx = mitk::PropertyKeyPathToPropertyRegEx(propPath); + std::string propTemplate = mitk::PropertyKeyPathToPersistenceNameTemplate(propPath); + info->UseRegEx(propRegEx, propTemplate, key, keyTemplate); + } + + if (temporoSpatial) + { + info->SetDeserializationFunction(mitk::PropertyPersistenceDeserialization::deserializeJSONToTemporoSpatialStringProperty); + info->SetSerializationFunction(mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON); + } + + persistenceService->AddInfo(info); +} + namespace mitk { void DICOMReaderServicesActivator::Load(us::ModuleContext* context) { m_AutoSelectingDICOMReader.reset(new AutoSelectingDICOMReaderService()); m_SimpleVolumeDICOMSeriesReader.reset(new SimpleVolumeDICOMSeriesReaderService()); m_DICOMTagsOfInterestService.reset(new DICOMTagsOfInterestService()); context->RegisterService(m_DICOMTagsOfInterestService.get()); DICOMTagPathMapType tagmap = GetDefaultDICOMTagsOfInterest(); for (auto tag : tagmap) { m_DICOMTagsOfInterestService->AddTagOfInterest(tag.first); } + + //add properties that should be persistent (if possible/supported by the writer) + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES(), true); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION()); + AddPropertyPersistence(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING()); + } void DICOMReaderServicesActivator::Unload(us::ModuleContext*) { } } US_EXPORT_MODULE_ACTIVATOR(mitk::DICOMReaderServicesActivator) diff --git a/Modules/DICOMTesting/CMakeLists.txt b/Modules/DICOMTesting/CMakeLists.txt index 69d2fcb943..256daf6b3b 100644 --- a/Modules/DICOMTesting/CMakeLists.txt +++ b/Modules/DICOMTesting/CMakeLists.txt @@ -1,41 +1,43 @@ if(BUILD_TESTING) if(GDCM_DIR) # clear variables from prior files.cmake # Else CMake would use the content of these variables and would try to create tests (which are not present in DICOMTesting). set(MODULE_TESTS) set(MODULE_IMAGE_TESTS) set(MODULE_SURFACE_TESTS) set(MODULE_TESTIMAGE) set(MODULE_TESTSURFACE) set(MODULE_CUSTOM_TESTS) set(H_FILES) set(CPP_FILES) # now create a new module only for testing purposes MITK_CREATE_MODULE( DEPENDS MitkDICOMReader + PACKAGE_DEPENDS + PRIVATE GDCM DCMTK ITK|ITKIOGDCM ) mitk_check_module_dependencies(MODULES MitkDICOMTesting MISSING_DEPENDENCIES_VAR _missing_deps) if(_missing_deps) message(STATUS "mitkDICOMTesting module helper applications won't be built. Missing: ${_missing_deps}") else(_missing_deps) # dumps out image information add_executable(DumpDICOMMitkImage src/DumpDICOMMitkImage.cpp) mitk_use_modules(TARGET DumpDICOMMitkImage MODULES MitkDICOMTesting) # compares dumped out image information against reference dump add_executable(VerifyDICOMMitkImageDump src/VerifyDICOMMitkImageDump.cpp) mitk_use_modules(TARGET VerifyDICOMMitkImageDump MODULES MitkDICOMTesting) set_property(TARGET DumpDICOMMitkImage VerifyDICOMMitkImageDump PROPERTY FOLDER "${MITK_ROOT_FOLDER}/Modules/Tests") add_subdirectory(test) endif() endif() endif() diff --git a/Modules/DICOMTesting/include/mitkTestDICOMLoading.h b/Modules/DICOMTesting/include/mitkTestDICOMLoading.h index f1d8cd2f56..63289abc0b 100644 --- a/Modules/DICOMTesting/include/mitkTestDICOMLoading.h +++ b/Modules/DICOMTesting/include/mitkTestDICOMLoading.h @@ -1,108 +1,111 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkTestDICOMLoading_h #define mitkTestDICOMLoading_h #include "mitkClassicDICOMSeriesReader.h" +#include "mitkPropertyKeyPath.h" #include "MitkDICOMTestingExports.h" namespace mitk { class MITKDICOMTESTING_EXPORT TestDICOMLoading { public: typedef std::list ImageList; TestDICOMLoading(); ImageList LoadFiles( const StringList & files ); Image::Pointer DecorateVerifyCachedImage( const StringList& files, mitk::Image::Pointer cachedImage ); Image::Pointer DecorateVerifyCachedImage( const StringList& files, DICOMTagCache*, mitk::Image::Pointer cachedImage ); /** \brief Dump relevant image information for later comparison. \sa CompareImageInformationDumps */ std::string DumpImageInformation( const Image* image ); /** \brief Compare two image information dumps. \return true, if dumps are sufficiently equal (see parameters) \sa DumpImageInformation */ bool CompareImageInformationDumps( const std::string& reference, const std::string& test ); private: typedef std::map KeyValueMap; ClassicDICOMSeriesReader::Pointer BuildDICOMReader(); void SetDefaultLocale(); void ResetUserLocale(); std::string ComponentTypeToString( int type ); KeyValueMap ParseDump( const std::string& dump ); bool CompareSpacedValueFields( const std::string& reference, const std::string& test, double eps = mitk::eps ); /** Compress whitespace in string \param pString input string \param pFill replacement whitespace (only whitespace in string after reduction) \param pWhitespace characters handled as whitespace */ std::string reduce(const std::string& pString, const std::string& pFill = " ", const std::string& pWhitespace = " \t"); /** Remove leading and trailing whitespace \param pString input string \param pWhitespace characters handled as whitespace */ std::string trim(const std::string& pString, const std::string& pWhitespace = " \t"); template bool StringToNumber(const std::string& s, T& value) { std::stringstream stream(s); stream >> value; return (!stream.fail()) && (std::abs(value) <= std::numeric_limits::max()); } + static void AddPropertyToDump(const mitk::PropertyKeyPath& key, const mitk::Image* image, std::stringstream& result); + const char* m_PreviousCLocale; std::locale m_PreviousCppLocale; }; } #endif diff --git a/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp b/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp index 240a316037..681794ef6e 100644 --- a/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp +++ b/Modules/DICOMTesting/src/DumpDICOMMitkImage.cpp @@ -1,36 +1,50 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkTestDICOMLoading.h" #include "mitkImage.h" int main(int argc, char** argv) { mitk::TestDICOMLoading loader; mitk::StringList files; - for (int arg = 1; arg < argc; ++arg) files.push_back( argv[arg] ); + if (argc < 2) + { + std::cerr << "Wrong usage of DumpDICOMMitkImage. Call it like VerifyDICOMMitkImageDump [ [... ]]."; + return 1; + } + + std::string dumpPath = argv[1]; + + for (int arg = 2; arg < argc; ++arg) files.push_back( argv[arg] ); mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files); + std::ostringstream sstream; // combine individual dumps in a way that VerifyDICOMMitkImageDump is able to separate again. // I.e.: when changing this piece of code, always change VerifyDICOMMitkImageDump, too. unsigned int imageCounter(0); for ( mitk::TestDICOMLoading::ImageList::const_iterator imageIter = images.begin(); imageIter != images.end(); ++imageIter ) { - std::cout << "-- Image " << ++imageCounter << "\n"; - std::cout << loader.DumpImageInformation( *imageIter ) << "\n"; + sstream << "-- Image " << ++imageCounter << "\n"; + sstream << loader.DumpImageInformation( *imageIter ) << "\n"; } + std::cout << sstream.str(); + std::ofstream out(dumpPath, ios::trunc | ios::out); + out << sstream.str(); + out.close(); + } diff --git a/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp b/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp index 532204de0e..ed2c8e71b0 100644 --- a/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp +++ b/Modules/DICOMTesting/src/mitkTestDICOMLoading.cpp @@ -1,488 +1,572 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ //#define MBILOG_ENABLE_DEBUG #include "mitkTestDICOMLoading.h" +#include "mitkDICOMIOMetaInformationPropertyConstants.h" +#include "mitkDICOMProperty.h" #include +#include +#include +#include "itksys/SystemTools.hxx" + mitk::TestDICOMLoading::TestDICOMLoading() :m_PreviousCLocale(nullptr) { } void mitk::TestDICOMLoading::SetDefaultLocale() { // remember old locale only once if (m_PreviousCLocale == nullptr) { m_PreviousCLocale = setlocale(LC_NUMERIC, nullptr); // set to "C" setlocale(LC_NUMERIC, "C"); m_PreviousCppLocale = std::cin.getloc(); std::locale l( "C" ); std::cin.imbue(l); std::cout.imbue(l); } } void mitk::TestDICOMLoading::ResetUserLocale() { if (m_PreviousCLocale) { setlocale(LC_NUMERIC, m_PreviousCLocale); std::cin.imbue(m_PreviousCppLocale); std::cout.imbue(m_PreviousCppLocale); m_PreviousCLocale = nullptr; } } mitk::TestDICOMLoading::ImageList mitk::TestDICOMLoading ::LoadFiles( const StringList& files ) { for (auto iter = files.begin(); iter != files.end(); ++iter) { MITK_DEBUG << "File " << *iter; } ImageList result; ClassicDICOMSeriesReader::Pointer reader = this->BuildDICOMReader(); + reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor); reader->SetInputFiles( files ); reader->AnalyzeInputFiles(); reader->PrintOutputs(std::cout,true); reader->LoadImages(); unsigned int numberOfImages = reader->GetNumberOfOutputs(); for (unsigned imageIndex = 0; imageIndex < numberOfImages; ++imageIndex) { const DICOMImageBlockDescriptor& block = reader->GetOutput(imageIndex); result.push_back( block.GetMitkImage() ); } return result; } mitk::ClassicDICOMSeriesReader::Pointer mitk::TestDICOMLoading ::BuildDICOMReader() { ClassicDICOMSeriesReader::Pointer reader = ClassicDICOMSeriesReader::New(); reader->SetFixTiltByShearing(true); return reader; } mitk::Image::Pointer mitk::TestDICOMLoading ::DecorateVerifyCachedImage( const StringList& files, mitk::DICOMTagCache* tagCache, mitk::Image::Pointer cachedImage ) { DICOMImageBlockDescriptor block; DICOMImageFrameList framelist; for (auto iter = files.begin(); iter != files.end(); ++iter) { framelist.push_back( DICOMImageFrameInfo::New(*iter) ); } block.SetImageFrameList( framelist ); block.SetTagCache( tagCache ); block.SetMitkImage( cachedImage ); // this should/will create a propertylist describing the image slices return block.GetMitkImage(); } mitk::Image::Pointer mitk::TestDICOMLoading ::DecorateVerifyCachedImage( const StringList& files, mitk::Image::Pointer cachedImage ) { ClassicDICOMSeriesReader::Pointer reader = this->BuildDICOMReader(); + reader->SetTagLookupTableToPropertyFunctor(mitk::GetDICOMPropertyForDICOMValuesFunctor); reader->SetInputFiles( files ); reader->AnalyzeInputFiles(); // This just creates a "tag cache and a nice DICOMImageBlockDescriptor. // Both of these could also be produced in a different way. The only // important thing is, that the DICOMImageBlockDescriptor knows a // tag-cache object when PropertyDecorateCachedMitkImageForImageBlockDescriptor // is called. if ( reader->GetNumberOfOutputs() != 1 ) { MITK_ERROR << "Reader produce " << reader->GetNumberOfOutputs() << " images instead of 1 expected.."; return nullptr; } DICOMImageBlockDescriptor block = reader->GetOutput(0); // creates a block copy block.SetMitkImage( cachedImage ); // this should/will create a propertylist describing the image slices return block.GetMitkImage(); } std::string mitk::TestDICOMLoading::ComponentTypeToString(int type) { if (type == itk::ImageIOBase::UCHAR) return "UCHAR"; else if (type == itk::ImageIOBase::CHAR) return "CHAR"; else if (type == itk::ImageIOBase::USHORT) return "USHORT"; else if (type == itk::ImageIOBase::SHORT) return "SHORT"; else if (type == itk::ImageIOBase::UINT) return "UINT"; else if (type == itk::ImageIOBase::INT) return "INT"; else if (type == itk::ImageIOBase::ULONG) return "ULONG"; else if (type == itk::ImageIOBase::LONG) return "LONG"; else if (type == itk::ImageIOBase::FLOAT) return "FLOAT"; else if (type == itk::ImageIOBase::DOUBLE) return "DOUBLE"; else return "UNKNOWN"; } // add a line to stringstream result (see DumpImageInformation #define DumpLine(field, data) DumpILine(0, field, data) // add an indented(!) line to stringstream result (see DumpImageInformation #define DumpILine(indent, field, data) \ { \ std::string DumpLine_INDENT; DumpLine_INDENT.resize(indent, ' ' ); \ result << DumpLine_INDENT << field << ": " << data << "\n"; \ } std::string mitk::TestDICOMLoading::DumpImageInformation( const Image* image ) { std::stringstream result; if (image == nullptr) return result.str(); SetDefaultLocale(); // basic image data DumpLine( "Pixeltype", ComponentTypeToString(image->GetPixelType().GetComponentType()) ); DumpLine( "BitsPerPixel", image->GetPixelType().GetBpe() ); DumpLine( "Dimension", image->GetDimension() ); result << "Dimensions: "; for (unsigned int dim = 0; dim < image->GetDimension(); ++dim) result << image->GetDimension(dim) << " "; result << "\n"; // geometry data result << "Geometry: \n"; const TimeGeometry* timeGeometry = image->GetTimeGeometry(); BaseGeometry* geometry = timeGeometry->GetGeometryForTimeStep(0); if (geometry) { AffineTransform3D* transform = geometry->GetIndexToWorldTransform(); if (transform) { result << " " << "Matrix: "; const AffineTransform3D::MatrixType& matrix = transform->GetMatrix(); for (unsigned int i = 0; i < 3; ++i) for (unsigned int j = 0; j < 3; ++j) result << matrix[i][j] << " "; result << "\n"; result << " " << "Offset: "; const AffineTransform3D::OutputVectorType& offset = transform->GetOffset(); for (unsigned int i = 0; i < 3; ++i) result << offset[i] << " "; result << "\n"; result << " " << "Center: "; const AffineTransform3D::InputPointType& center = transform->GetCenter(); for (unsigned int i = 0; i < 3; ++i) result << center[i] << " "; result << "\n"; result << " " << "Translation: "; const AffineTransform3D::OutputVectorType& translation = transform->GetTranslation(); for (unsigned int i = 0; i < 3; ++i) result << translation[i] << " "; result << "\n"; result << " " << "Scale: "; const double* scale = transform->GetScale(); for (unsigned int i = 0; i < 3; ++i) result << scale[i] << " "; result << "\n"; result << " " << "Origin: "; const Point3D& origin = geometry->GetOrigin(); for (unsigned int i = 0; i < 3; ++i) result << origin[i] << " "; result << "\n"; result << " " << "Spacing: "; const Vector3D& spacing = geometry->GetSpacing(); for (unsigned int i = 0; i < 3; ++i) result << spacing[i] << " "; result << "\n"; result << " " << "TimeBounds: "; const TimeBounds timeBounds = timeGeometry->GetTimeBounds(); for (unsigned int i = 0; i < 2; ++i) result << timeBounds[i] << " "; result << "\n"; } } + // io dicom meta information + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_CONFIGURATION(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_GANTRY_TILT_CORRECTED(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_IMPLEMENTATION_LEVEL_STRING(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_PIXEL_SPACING_INTERPRETATION_STRING(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_3D_plus_t(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK(), image, result); + AddPropertyToDump(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM(), image, result); + ResetUserLocale(); return result.str(); } +void mitk::TestDICOMLoading::AddPropertyToDump(const mitk::PropertyKeyPath& key, const mitk::Image* image, std::stringstream& result) +{ + auto propKey = mitk::PropertyKeyPathToPropertyName(key); + auto prop = image->GetProperty(propKey.c_str()); + if (prop.IsNotNull()) + { + auto value = prop->GetValueAsString(); + auto dicomProp = dynamic_cast< mitk::DICOMProperty*>(prop.GetPointer()); + if (dicomProp != nullptr) + { + auto strippedProp = dicomProp->Clone(); + if (key == mitk::DICOMIOMetaInformationPropertyConstants::READER_FILES()) + {//strip dicom file information from path to ensure generalized dump files + auto timePoints = strippedProp->GetAvailableTimeSteps(); + for (auto timePoint : timePoints) + { + auto slices = strippedProp->GetAvailableSlices(timePoint); + for (auto slice : slices) + { + auto value = strippedProp->GetValue(timePoint, slice); + value = itksys::SystemTools::GetFilenameName(value); + strippedProp->SetValue(timePoint, slice, value); + } + } + } + value = mitk::PropertyPersistenceSerialization::serializeTemporoSpatialStringPropertyToJSON(strippedProp); + } + result << propKey << ": " << value << "\n"; + } +} + std::string mitk::TestDICOMLoading::trim(const std::string& pString, const std::string& pWhitespace) { const size_t beginStr = pString.find_first_not_of(pWhitespace); if (beginStr == std::string::npos) { // no content return ""; } const size_t endStr = pString.find_last_not_of(pWhitespace); const size_t range = endStr - beginStr + 1; return pString.substr(beginStr, range); } std::string mitk::TestDICOMLoading::reduce(const std::string& pString, const std::string& pFill, const std::string& pWhitespace) { // trim first std::string result(trim(pString, pWhitespace)); // replace sub ranges size_t beginSpace = result.find_first_of(pWhitespace); while (beginSpace != std::string::npos) { const size_t endSpace = result.find_first_not_of(pWhitespace, beginSpace); const size_t range = endSpace - beginSpace; result.replace(beginSpace, range, pFill); const size_t newStart = beginSpace + pFill.length(); beginSpace = result.find_first_of(pWhitespace, newStart); } return result; } bool mitk::TestDICOMLoading::CompareSpacedValueFields( const std::string& reference, const std::string& test, double /*eps*/ ) { bool result(true); // tokenize string, compare each token, if possible by float comparison std::stringstream referenceStream(reduce(reference)); std::stringstream testStream(reduce(test)); std::string refToken; std::string testToken; while ( std::getline( referenceStream, refToken, ' ' ) && std::getline ( testStream, testToken, ' ' ) ) { float refNumber; float testNumber; if ( this->StringToNumber(refToken, refNumber) ) { if ( this->StringToNumber(testToken, testNumber) ) { // print-out compared tokens if DEBUG output allowed MITK_DEBUG << "Reference Token '" << refToken << "'" << " value " << refNumber << ", test Token '" << testToken << "'" << " value " << testNumber; bool old_result = result; result &= ( std::abs(refNumber - testNumber) < 0.0001f /*mitk::eps*/ ); // log the token/number which causes the test to fail if( old_result != result) { MITK_ERROR << std::setprecision(16) << "Reference Token '" << refToken << "'" << " value " << refNumber << ", test Token '" << testToken << "'" << " value " << testNumber; MITK_ERROR << "[FALSE] - difference: " << std::setprecision(16) << std::abs(refNumber - testNumber) << " EPS: " << 0.0001f; //mitk::eps; } } else { MITK_ERROR << refNumber << " cannot be compared to '" << testToken << "'"; } } else { MITK_DEBUG << "Token '" << refToken << "'" << " handled as string"; result &= refToken == testToken; } } if ( std::getline( referenceStream, refToken, ' ' ) ) { MITK_ERROR << "Reference string still had values when test string was already parsed: ref '" << reference << "', test '" << test << "'"; result = false; } else if ( std::getline( testStream, testToken, ' ' ) ) { MITK_ERROR << "Test string still had values when reference string was already parsed: ref '" << reference << "', test '" << test << "'"; result = false; } return result; } bool mitk::TestDICOMLoading::CompareImageInformationDumps( const std::string& referenceDump, const std::string& testDump ) { KeyValueMap reference = ParseDump(referenceDump); KeyValueMap test = ParseDump(testDump); bool testResult(true); // verify all expected values for (KeyValueMap::const_iterator refIter = reference.begin(); refIter != reference.end(); ++refIter) { const std::string& refKey = refIter->first; const std::string& refValue = refIter->second; if ( test.find(refKey) != test.end() ) { const std::string& testValue = test[refKey]; + if (refKey == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK())) + { //check dcmtk version always against the current version of the system + bool thisTestResult = testValue == std::string(" ") + PACKAGE_VERSION; + testResult &= thisTestResult; - bool thisTestResult = CompareSpacedValueFields( refValue, testValue ); - testResult &= thisTestResult; + MITK_DEBUG << refKey << ": '" << PACKAGE_VERSION << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO"); + } + else if (refKey == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM())) + {//check gdcm version always against the current version of the system + bool thisTestResult = testValue == std::string(" ") + gdcm::Version::GetVersion(); + testResult &= thisTestResult; + + MITK_DEBUG << refKey << ": '" << gdcm::Version::GetVersion() << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO"); + } + else + { + bool thisTestResult = CompareSpacedValueFields(refValue, testValue); + testResult &= thisTestResult; - MITK_DEBUG << refKey << ": '" << refValue << "' == '" << testValue << "' ? " << (thisTestResult?"YES":"NO"); + MITK_DEBUG << refKey << ": '" << refValue << "' == '" << testValue << "' ? " << (thisTestResult ? "YES" : "NO"); + } } else { MITK_ERROR << "Reference dump contains a key'" << refKey << "' (value '" << refValue << "')." ; MITK_ERROR << "This key is expected to be generated for tests (but was not). Most probably you need to update your test data."; return false; } } // now check test dump does not contain any additional keys for (KeyValueMap::const_iterator testIter = test.begin(); testIter != test.end(); ++testIter) { const std::string& key = testIter->first; const std::string& value = testIter->second; - if ( reference.find(key) == reference.end() ) + if (key == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_DCMTK())) + {//check dcmtk version always against the current version of the system + bool thisTestResult = value == std::string(" ")+PACKAGE_VERSION; + testResult &= thisTestResult; + + MITK_DEBUG << key << ": '" << PACKAGE_VERSION << "' == '" << value << "' ? " << (thisTestResult ? "YES" : "NO"); + } + else if (key == mitk::PropertyKeyPathToPropertyName(mitk::DICOMIOMetaInformationPropertyConstants::READER_GDCM())) + {//check gdcm version always against the current version of the system + bool thisTestResult = value == std::string(" ") + gdcm::Version::GetVersion(); + testResult &= thisTestResult; + + MITK_DEBUG << key << ": '" << gdcm::Version::GetVersion() << "' == '" << value << "' ? " << (thisTestResult ? "YES" : "NO"); + } + else if ( reference.find(key) == reference.end() ) { MITK_ERROR << "Test dump contains an unexpected key'" << key << "' (value '" << value << "')." ; MITK_ERROR << "This key is not expected. Most probably you need to update your test data."; return false; } } return testResult; } mitk::TestDICOMLoading::KeyValueMap mitk::TestDICOMLoading::ParseDump( const std::string& dump ) { KeyValueMap parsedResult; std::string shredder(dump); std::stack surroundingKeys; std::stack expectedIndents; expectedIndents.push(0); while (true) { std::string::size_type newLinePos = shredder.find( '\n' ); if (newLinePos == std::string::npos || newLinePos == 0) break; std::string line = shredder.substr( 0, newLinePos ); shredder = shredder.erase( 0, newLinePos+1 ); std::string::size_type keyPosition = line.find_first_not_of( ' ' ); std::string::size_type colonPosition = line.find( ':' ); std::string key = line.substr(keyPosition, colonPosition - keyPosition); std::string::size_type firstSpacePosition = key.find_first_of(" "); if (firstSpacePosition != std::string::npos) { key.erase(firstSpacePosition); } if ( keyPosition > expectedIndents.top() ) { // more indent than before expectedIndents.push(keyPosition); } - else if (keyPosition == expectedIndents.top() ) + else { if (!surroundingKeys.empty()) { surroundingKeys.pop(); // last of same length } - } - else - { - // less indent than before - do expectedIndents.pop(); - while (expectedIndents.top() != keyPosition); // unwind until current indent is found + + while (expectedIndents.top() != keyPosition) + { + expectedIndents.pop(); + if (!surroundingKeys.empty()) + { + surroundingKeys.pop(); + } + }; // unwind until current indent is found } if (!surroundingKeys.empty()) { key = surroundingKeys.top() + "." + key; // construct current key name } surroundingKeys.push(key); // this is the new embracing key std::string value = line.substr(colonPosition+1); MITK_DEBUG << " Key: '" << key << "' value '" << value << "'" ; parsedResult[key] = value; // store parsing result } return parsedResult; } diff --git a/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp b/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp index 69c68e14a3..19ca2db8e3 100644 --- a/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp +++ b/Modules/DICOMTesting/test/mitkDICOMPreloadedVolumeTest.cpp @@ -1,112 +1,114 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkTestDICOMLoading.h" #include "mitkTestingMacros.h" #include "mitkDICOMTagCache.h" bool CheckAllPropertiesAreInOtherList(const mitk::PropertyList* list, const mitk::PropertyList* otherList) { MITK_TEST_CONDITION_REQUIRED(list && otherList, "Comparison is passed two non-empty property lists") const mitk::PropertyList::PropertyMap* listM = list->GetMap(); const mitk::PropertyList::PropertyMap* otherListM = otherList->GetMap(); bool equal = true; for ( auto iter = listM->begin(); iter != listM->end(); ++iter ) { std::string key = iter->first; mitk::BaseProperty* property = iter->second; auto otherEntry = otherListM->find( key ); MITK_TEST_CONDITION( otherEntry != otherListM->end(), " Property '" << key << "' is contained in other list" ) mitk::BaseProperty* otherProperty = otherEntry->second; - MITK_TEST_CONDITION( equal &= (*property == *otherProperty), " Property '" << key << "' is equal in both list" ) + auto propEqual = (*property == *otherProperty); + MITK_TEST_CONDITION(propEqual, " Property '" << key << "' is equal in both list"); + equal &= propEqual; } return equal; } bool VerifyPropertyListsEquality(const mitk::PropertyList* testList, const mitk::PropertyList* referenceList) { bool allTestPropsInReference = CheckAllPropertiesAreInOtherList(testList, referenceList); MITK_TEST_CONDITION(allTestPropsInReference, "All test properties found in reference properties") bool allReferencePropsInTest = CheckAllPropertiesAreInOtherList(referenceList, testList); MITK_TEST_CONDITION(allReferencePropsInTest, "All reference properties found in test properties") return allTestPropsInReference && allReferencePropsInTest; } // !!! we expect that this tests get a list of files that load as ONE SINGLE mitk::Image! int mitkDICOMPreloadedVolumeTest(int argc, char** const argv) { MITK_TEST_BEGIN("DICOMPreloadedVolume") mitk::TestDICOMLoading loader; mitk::StringList files; // load files from commandline for (int arg = 1; arg < argc; ++arg) { MITK_TEST_OUTPUT(<< "Test file " << argv[arg]) files.push_back( argv[arg] ); } // verify all files are DICOM for (mitk::StringList::const_iterator fileIter = files.begin(); fileIter != files.end(); ++fileIter) { MITK_TEST_CONDITION_REQUIRED( mitk::DICOMFileReader::IsDICOM(*fileIter) , *fileIter << " is recognized as loadable DICOM object" ) } // load for a first time mitk::TestDICOMLoading::ImageList images = loader.LoadFiles(files); MITK_TEST_OUTPUT(<< "Loaded " << images.size() << " images. Remembering properties of the first one for later comparison.") mitk::Image::Pointer firstImage = images.front(); mitk::PropertyList::Pointer originalProperties = firstImage->GetPropertyList(); // save the original firstImage->SetPropertyList( mitk::PropertyList::New() ); // clear image properties // what about DEFAULT properties? currently ONLY nodes get default properties // load for a second time, this time provide the image volume as a pointer // expectation is that the reader will provide the same properties to this image (without actually loading a new mitk::Image) // !!! we expect that this tests get a list of files that load as ONE SINGLE mitk::Image! MITK_TEST_CONDITION_REQUIRED( images.size() == 1, "Not more than 1 images loaded." ); // otherwise, we would need to determine the correct set of files here MITK_TEST_OUTPUT(<< "Generating properties via reader. Comparing new properties to previously loaded version.") mitk::Image::Pointer reloadedImage = loader.DecorateVerifyCachedImage(files, firstImage); MITK_TEST_CONDITION_REQUIRED(reloadedImage.IsNotNull(), "Reader was able to property-decorate image."); mitk::PropertyList::Pointer regeneratedProperties = reloadedImage->GetPropertyList(); // get the version of the second load attempt bool listsAreEqual = VerifyPropertyListsEquality(regeneratedProperties, originalProperties); MITK_TEST_CONDITION(listsAreEqual, "DICOM file reader generates a valid property list when provided a pre-loaded image"); // test again, this time provide a tag cache. // expectation is, that an empty tag cache will lead to NO image mitk::DICOMTagCache::Pointer tagCache; // empty MITK_TEST_OUTPUT(<< "Generating properties via reader. Comparing new properties to previously loaded version.") firstImage->SetPropertyList( mitk::PropertyList::New() ); // clear image properties reloadedImage = loader.DecorateVerifyCachedImage(files, tagCache, firstImage); MITK_TEST_CONDITION_REQUIRED(reloadedImage.IsNull(), "Reader was able to detect missing tag-cache."); MITK_TEST_END() } diff --git a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp index a1e45309f7..7406172d13 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp @@ -1,168 +1,168 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace mitk { RTDoseReaderService::RTDoseReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::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 > RTDoseReaderService::DoRead() { 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/mitkRTDoseReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h index 112f8da28c..ad24fd6011 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h +++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.h @@ -1,64 +1,66 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkRTDoseReaderService_h #define mitkRTDoseReaderService_h #include #include #include #include namespace mitk { /** * \brief RTDoseReaderService reads DICOM files of modality RTDOSE. */ class MITKDICOMRTIO_EXPORT RTDoseReaderService : public mitk::AbstractFileReader { public: RTDoseReaderService(const RTDoseReaderService& other); RTDoseReaderService(); ~RTDoseReaderService() override; using AbstractFileReader::Read; - /** - * @brief Reads a dicom dataset from a RTDOSE file - * The method reads the PixelData from the DicomRT dose file and scales - * them with a factor for getting Gray-values instead of pixel-values. - * The Gray-values are stored in a mitkImage with a vtkColorTransferFunc. - * Relative values are used for coloring the image. The relative values are - * relative to a PrescriptionDose defined in the RT-Plan. If there is no - * RT-Plan file PrescriptionDose is set to 80% of the maximum dose. - */ - std::vector > Read() override; + + protected: + /** + * @brief Reads a dicom dataset from a RTDOSE file + * The method reads the PixelData from the DicomRT dose file and scales + * them with a factor for getting Gray-values instead of pixel-values. + * The Gray-values are stored in a mitkImage with a vtkColorTransferFunc. + * Relative values are used for coloring the image. The relative values are + * relative to a PrescriptionDose defined in the RT-Plan. If there is no + * RT-Plan file PrescriptionDose is set to 80% of the maximum dose. + */ + std::vector> DoRead() override; private: RTDoseReaderService* Clone() const override; /** * \brief Scales an image with a factor * * \param gridscale the factor to scale with */ template void MultiplyGridScaling(itk::Image< TPixel, VImageDimension>* image, float gridscale); mitk::Image::Pointer scaledDoseImage; us::ServiceRegistration m_FileReaderServiceReg; }; } #endif diff --git a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp index d5d2879a6c..c1d8686b03 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.cpp @@ -1,82 +1,82 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include #include #include #include #include #include namespace mitk { RTPlanReaderService::RTPlanReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_PLAN_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::DICOMRT_PLAN_MIMETYPE_DESCRIPTION()) { m_FileReaderServiceReg = RegisterService(); } RTPlanReaderService::RTPlanReaderService(const RTPlanReaderService& other) : mitk::AbstractFileReader(other) { } RTPlanReaderService::~RTPlanReaderService() {} - std::vector > RTPlanReaderService::Read() + std::vector > RTPlanReaderService::DoRead() { 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/mitkRTPlanReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h index dd29b2af7d..c2653f2991 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h +++ b/Modules/DicomRT/autoload/IO/mitkRTPlanReaderService.h @@ -1,61 +1,63 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkRTPlanReaderService_h #define mitkRTPlanReaderService_h #include "mitkAbstractFileReader.h" #include #include "mitkIDICOMTagsOfInterest.h" #include "mitkDICOMDatasetAccessingImageFrameInfo.h" #include #include "MitkDicomRTIOExports.h" namespace mitk { /** * \brief RTPlanReaderService reads DICOM files of modality RTPLAN. \details The tags are defined in mitk::GetDefaultDICOMTagsOfInterest() in Module MitkDicomReader. They are stored as TemporoSpatialStringProperty. with the key as their respective DICOM tags. \note No image information is in RTPLAN. */ class MITKDICOMRTIO_EXPORT RTPlanReaderService : public mitk::AbstractFileReader { public: RTPlanReaderService(); RTPlanReaderService(const RTPlanReaderService& other); using AbstractFileReader::Read; + + ~RTPlanReaderService() override; + + protected: /** * \brief Reads the file (only tags). @details DICOMDCMTKTagScanner is used to read the tags \note No image information is in RTPLAN. \sa mitk::GetDefaultDICOMTagsOfInterest() for tags that are read */ - std::vector > Read() override; - - ~RTPlanReaderService() override; + std::vector> DoRead() override; private: RTPlanReaderService* Clone() const override; us::ServiceRegistration m_FileReaderServiceReg; }; } #endif diff --git a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp index ef2a5132ef..f4c4bcb794 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.cpp @@ -1,288 +1,288 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkRTStructureSetReaderService.h" #include #include #include #include #include "dcmtk/dcmrt/drtstrct.h" namespace mitk { RTStructureSetReaderService::RTStructureSetReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTMimeTypes::DICOMRT_STRUCT_MIMETYPE_NAME()), mitk::DicomRTMimeTypes::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 > RTStructureSetReaderService::DoRead() { 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 == nullptr) { 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); } } diff --git a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h index 8986c6366f..8fcf2e8efb 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h +++ b/Modules/DicomRT/autoload/IO/mitkRTStructureSetReaderService.h @@ -1,85 +1,87 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKRTSTRUCTURESETREADER_H #define MITKRTSTRUCTURESETREADER_H #include #include "MitkDicomRTIOExports.h" #include #include namespace mitk { class MITKDICOMRTIO_EXPORT RTStructureSetReaderService : public mitk::AbstractFileReader { /** * Represent a region of interest (ROI) */ class RoiEntry { public: RoiEntry(); RoiEntry(const RoiEntry& src); virtual ~RoiEntry(); RoiEntry& operator=(const RoiEntry& src); void SetPolyData(ContourModelSet::Pointer roiPolyData); unsigned int Number; std::string Name; std::string Description; double DisplayColor[3]; mitk::ContourModelSet::Pointer ContourModelSet; }; public: RTStructureSetReaderService(); RTStructureSetReaderService(const RTStructureSetReaderService& other); ~RTStructureSetReaderService() override; /** * @brief Reading a RT StructureSet from the DICOM file and returns the ROIs * (region of interest) as a ContourModelSet. One ContourModelSet represent * one ROI. A ContourModelSet contains ContourModels which represent the * single structures. */ using AbstractFileReader::Read; - std::vector > Read() override; + + protected: + std::vector> DoRead() override; private: RTStructureSetReaderService* Clone() const override; /** * containing the ROIs meta information like name number and description */ std::vector ROISequenceVector; /** * Returns the number of ROIs from the ROISequenceVector */ size_t GetNumberOfROIs() const; /** * Returns the relevant ROI from the ROISequenceVector by its number */ RoiEntry* FindRoiByNumber(unsigned int roiNum); us::ServiceRegistration m_FileReaderServiceReg; }; } #endif // MITKRTSTRUCTURESETREADER_H diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp index 3587fc8277..1a5362d805 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.cpp @@ -1,169 +1,169 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkNavigationDataReaderCSV.h" #include #include // STL #include mitk::NavigationDataReaderCSV::NavigationDataReaderCSV() : AbstractFileReader( mitk::IGTMimeTypes::NAVIGATIONDATASETCSV_MIMETYPE(), "MITK NavigationData Reader (CSV)") { RegisterService(); } mitk::NavigationDataReaderCSV::NavigationDataReaderCSV(const mitk::NavigationDataReaderCSV& other) : AbstractFileReader(other) { } mitk::NavigationDataReaderCSV::~NavigationDataReaderCSV() { } mitk::NavigationDataReaderCSV* mitk::NavigationDataReaderCSV::Clone() const { return new NavigationDataReaderCSV(*this); } -std::vector> mitk::NavigationDataReaderCSV::Read() +std::vector> mitk::NavigationDataReaderCSV::DoRead() { std::vector fileContent = GetFileContentLineByLine(GetInputLocation()); int NumOfTools = getNumberOfToolsInLine(fileContent[0]); mitk::NavigationDataSet::Pointer returnValue = mitk::NavigationDataSet::New(NumOfTools); std::vector result; result.push_back(returnValue.GetPointer()); // start from line 1 to leave out header for (unsigned int i = 1; iAddNavigationDatas(parseLine(fileContent[i], NumOfTools)); } return result; } int mitk::NavigationDataReaderCSV::getNumberOfToolsInLine(std::string line) { std::vector tokens=splitLine(line); int size = tokens.size(); int NumOfTools = (size)/9; if ( (size)%9 != 0 ) { MITK_ERROR("mitkNavigationDataReader") << "Illegal csv-file! Unexpected number of columns found! Assuming " << NumOfTools << " tools!"; } return NumOfTools ; } std::vector mitk::NavigationDataReaderCSV::splitLine(std::string line) { std::vector elems; std::stringstream ss(line); std::string item; while (std::getline(ss, item, ';')) { elems.push_back(item); } return elems; } mitk::NavigationData::Pointer mitk::NavigationDataReaderCSV::CreateNd(std::string timestamp, std::string valid, std::string X, std::string Y, std::string Z, std::string QX, std::string QY, std::string QZ, std::string QR) { mitk::NavigationData::Pointer result= mitk::NavigationData::New(); mitk::Point3D position; mitk::Quaternion orientation; bool isValid = false; double time; time = StringToDouble(timestamp); if (valid == "1") isValid = true; else isValid = false; position[0] = StringToDouble(X); position[1] = StringToDouble(Y); position[2] = StringToDouble(Z); orientation[0] = StringToDouble(QX); orientation[1] = StringToDouble(QY); orientation[2] = StringToDouble(QZ); orientation[3] = StringToDouble(QR); result->SetIGTTimeStamp(time); result->SetDataValid(isValid); result->SetPosition(position); result->SetOrientation(orientation); return result; } double mitk::NavigationDataReaderCSV::StringToDouble( const std::string& s ) { std::istringstream i(s); double x; if (!(i >> x)) return 0; return x; } std::vector mitk::NavigationDataReaderCSV::parseLine(std::string line, int NumOfTools) { std::vector parts = splitLine(line); std::vector result; for (int n = 0; n < NumOfTools; n++) { mitk::NavigationData::Pointer nd; int offset = n * 9; nd = CreateNd(parts[offset], parts[offset + 1], parts[offset + 2], parts[offset + 3], parts[offset + 4], parts[offset + 5], parts[offset + 6], parts[offset + 7], parts[offset + 8]); result.push_back(nd); } return result; } std::vector mitk::NavigationDataReaderCSV::GetFileContentLineByLine(std::string filename) { std::vector readData = std::vector(); //define own locale mitk::LocaleSwitch localeSwitch("C"); //read file std::ifstream file; file.open(filename.c_str(), std::ios::in); if (file.good()) { //read out file file.seekg(0L, std::ios::beg); // move to begin of file while (! file.eof()) { std::string buffer; std::getline(file,buffer); // read out file line by line if (buffer.size() > 0) readData.push_back(buffer); } } file.close(); return readData; } diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h index 7a9527c492..462a6b4ca1 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderCSV.h @@ -1,80 +1,80 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_ #define MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_ #include #include #include namespace mitk { /** This class reads csv logged navigation datas from the hard disc and returns * the navigation data set. * * Caution: at the moment only one navigation data is supported which means that only * the data of the first navigation tool in the file is read! */ class MITKIGTIO_EXPORT NavigationDataReaderCSV : public AbstractFileReader { public: NavigationDataReaderCSV(); ~NavigationDataReaderCSV() override; /** @return Returns the NavigationDataSet of the first tool in the given file. * Returns an empty NavigationDataSet if the file could not be read. */ using AbstractFileReader::Read; - std::vector> Read() override; protected: + std::vector> DoRead() override; /** * /brief Creates a NavigationData Pointer based on the given Input. */ mitk::NavigationData::Pointer CreateNd(std::string timestamp, std::string valid, std::string X, std::string Y, std::string Z, std::string QX, std::string QY, std::string QZ, std::string QR); /** * /brief Presents File Content line by line */ std::vector GetFileContentLineByLine(std::string filename); /** * /brief Calculates the Number of Tools based on the number of colums per line. */ int getNumberOfToolsInLine(std::string line); /** * /brief Converts string to double returns zero if failing */ std::vector parseLine(std::string line, int NumOfTools); /** * /brief Converts string to double returns zero if failing */ double StringToDouble( const std::string& s ); /** * /brief Split line in elemens based on a given delim */ std::vector splitLine(std::string line); NavigationDataReaderCSV(const NavigationDataReaderCSV& other); mitk::NavigationDataReaderCSV* Clone() const override; }; } #endif // MITKNavigationDataReaderCSV_H_HEADER_INCLUDED_ diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp index 004ed0a49a..24551b7f0a 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.cpp @@ -1,364 +1,364 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkNavigationDataReaderXML.h" #include #include // Third Party #include #include #include mitk::NavigationDataReaderXML::NavigationDataReaderXML() : AbstractFileReader( mitk::IGTMimeTypes::NAVIGATIONDATASETXML_MIMETYPE(), "MITK NavigationData Reader (XML)"), m_parentElement(nullptr), m_currentNode(nullptr) { RegisterService(); } mitk::NavigationDataReaderXML::~NavigationDataReaderXML() { } mitk::NavigationDataReaderXML::NavigationDataReaderXML(const mitk::NavigationDataReaderXML& other) : AbstractFileReader(other), m_parentElement(nullptr), m_currentNode(nullptr) { } mitk::NavigationDataReaderXML* mitk::NavigationDataReaderXML::Clone() const { return new NavigationDataReaderXML(*this); } -std::vector> mitk::NavigationDataReaderXML::Read() +std::vector> mitk::NavigationDataReaderXML::DoRead() { mitk::NavigationDataSet::Pointer dataset; std::istream* in = GetInputStream(); if (in == nullptr) { dataset = Read(GetInputLocation()); } else { dataset = Read(in); } std::vector result; mitk::BaseData::Pointer base = dataset.GetPointer(); result.push_back(base); return result; } mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::string fileName) { //define own locale mitk::LocaleSwitch localeSwitch("C"); m_FileName = fileName; TiXmlDocument document; if (!document.LoadFile(fileName)) { mitkThrowException(mitk::IGTIOException) << "File '" << fileName << "' could not be loaded."; } TiXmlElement* m_DataElem = document.FirstChildElement("Version"); if (!m_DataElem) { // for backwards compatibility of version tag m_DataElem = document.FirstChildElement("Data"); if (!m_DataElem) { mitkThrowException(mitk::IGTIOException) << "Data element not found."; } } if (m_DataElem->QueryIntAttribute("Ver", &m_FileVersion) != TIXML_SUCCESS) { if (m_DataElem->QueryIntAttribute("version", &m_FileVersion) != TIXML_SUCCESS) { mitkThrowException(mitk::IGTIOException) << "Version not specified in XML file."; } } if (m_FileVersion != 1) { mitkThrowException(mitk::IGTIOException) << "File format version " << m_FileVersion << " is not supported."; } m_parentElement = document.FirstChildElement("Data"); if (!m_parentElement) { mitkThrowException(mitk::IGTIOException) << "Data element not found."; } m_parentElement->QueryIntAttribute("ToolCount", &m_NumberOfOutputs); mitk::NavigationDataSet::Pointer navigationDataSet = this->ReadNavigationDataSet(); return navigationDataSet; } mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::Read(std::istream* stream) { //define own locale mitk::LocaleSwitch localeSwitch("C"); // first get the file version m_FileVersion = this->GetFileVersion(stream); // check if we have a valid version: m_FileVersion has to be always bigger than 1 for playing if (m_FileVersion < 1) { StreamInvalid("Playing not possible. Invalid file version!"); return nullptr; } m_NumberOfOutputs = this->GetNumberOfNavigationDatas(stream); if (m_NumberOfOutputs == 0) { return nullptr; } mitk::NavigationDataSet::Pointer dataSet = this->ReadNavigationDataSet(); return dataSet; } mitk::NavigationDataSet::Pointer mitk::NavigationDataReaderXML::ReadNavigationDataSet() { mitk::NavigationDataSet::Pointer navigationDataSet = mitk::NavigationDataSet::New(m_NumberOfOutputs); mitk::NavigationData::Pointer curNavigationData; do { std::vector navDatas(m_NumberOfOutputs); for (int n = 0; n < m_NumberOfOutputs; ++n) { curNavigationData = this->ReadVersion1(); if (curNavigationData.IsNull()) { if (n != 0) { MITK_WARN("mitkNavigationDataReaderXML") << "Different number of NavigationData objects for different tools. Ignoring last ones."; } break; } navDatas.at(n) = curNavigationData; } if (curNavigationData.IsNotNull()) { navigationDataSet->AddNavigationDatas(navDatas); } } while (curNavigationData.IsNotNull()); return navigationDataSet; } mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadVersion1() { if ( !m_parentElement ) { mitkThrowException(mitk::IGTIOException) << "Reading XML is not possible. Parent element is not set."; } TiXmlElement* elem; m_currentNode = m_parentElement->IterateChildren(m_currentNode); bool delElem; if(m_currentNode) { elem = m_currentNode->ToElement(); if(elem==nullptr) { mitkThrowException(mitk::IGTException) << "Cannot find element: Is this file damaged?"; } delElem = false; } else { elem = new TiXmlElement(""); delElem = true; } mitk::NavigationData::Pointer nd = this->ReadNavigationData(elem); if(delElem) { delete elem; } return nd; } mitk::NavigationData::Pointer mitk::NavigationDataReaderXML::ReadNavigationData(TiXmlElement* elem) { if (elem == nullptr) {mitkThrow() << "Error: Element is nullptr!";} mitk::NavigationData::Pointer nd = mitk::NavigationData::New(); mitk::NavigationData::PositionType position; mitk::NavigationData::OrientationType orientation(0.0,0.0,0.0,0.0); mitk::NavigationData::TimeStampType timestamp = -1; mitk::NavigationData::CovarianceMatrixType matrix; bool hasPosition = true; bool hasOrientation = true; bool dataValid = false; position.Fill(0.0); matrix.SetIdentity(); elem->QueryDoubleAttribute("Time",×tamp); if (timestamp == -1) { return nullptr; //the calling method should check the return value if it is valid/not nullptr } elem->QueryDoubleAttribute("X", &position[0]); elem->QueryDoubleAttribute("Y", &position[1]); elem->QueryDoubleAttribute("Z", &position[2]); elem->QueryDoubleAttribute("QX", &orientation[0]); elem->QueryDoubleAttribute("QY", &orientation[1]); elem->QueryDoubleAttribute("QZ", &orientation[2]); elem->QueryDoubleAttribute("QR", &orientation[3]); elem->QueryDoubleAttribute("C00", &matrix[0][0]); elem->QueryDoubleAttribute("C01", &matrix[0][1]); elem->QueryDoubleAttribute("C02", &matrix[0][2]); elem->QueryDoubleAttribute("C03", &matrix[0][3]); elem->QueryDoubleAttribute("C04", &matrix[0][4]); elem->QueryDoubleAttribute("C05", &matrix[0][5]); elem->QueryDoubleAttribute("C10", &matrix[1][0]); elem->QueryDoubleAttribute("C11", &matrix[1][1]); elem->QueryDoubleAttribute("C12", &matrix[1][2]); elem->QueryDoubleAttribute("C13", &matrix[1][3]); elem->QueryDoubleAttribute("C14", &matrix[1][4]); elem->QueryDoubleAttribute("C15", &matrix[1][5]); int tmpval = 0; elem->QueryIntAttribute("Valid", &tmpval); if (tmpval == 0) dataValid = false; else dataValid = true; tmpval = 0; elem->QueryIntAttribute("hO", &tmpval); if (tmpval == 0) hasOrientation = false; else hasOrientation = true; tmpval = 0; elem->QueryIntAttribute("hP", &tmpval); if (tmpval == 0) hasPosition = false; else hasPosition = true; nd->SetIGTTimeStamp(timestamp); nd->SetPosition(position); nd->SetOrientation(orientation); nd->SetCovErrorMatrix(matrix); nd->SetDataValid(dataValid); nd->SetHasOrientation(hasOrientation); nd->SetHasPosition(hasPosition); return nd; } // -- deprecated | begin unsigned int mitk::NavigationDataReaderXML::GetFileVersion(std::istream* stream) { if (stream==nullptr) { MITK_ERROR << "No input stream set!"; mitkThrowException(mitk::IGTIOException)<<"No input stream set!"; } if (!stream->good()) { MITK_ERROR << "Stream is not good!"; mitkThrowException(mitk::IGTIOException)<<"Stream is not good!"; } int version = 1; auto dec = new TiXmlDeclaration(); *stream >> *dec; if(strcmp(dec->Version(),"") == 0) { MITK_ERROR << "The input stream seems to have XML incompatible format"; mitkThrowException(mitk::IGTIOException) << "The input stream seems to have XML incompatible format"; } m_parentElement = new TiXmlElement(""); *stream >> *m_parentElement; //2nd line this is the file version std::string tempValue = m_parentElement->Value(); if(tempValue != "Version") { if(tempValue == "Data"){ m_parentElement->QueryIntAttribute("version",&version); } } else { m_parentElement->QueryIntAttribute("Ver",&version); } if (version > 0) { return version; } else { return 0; } } unsigned int mitk::NavigationDataReaderXML::GetNumberOfNavigationDatas(std::istream* stream) { if (stream == nullptr) { MITK_ERROR << "No input stream set!"; mitkThrowException(mitk::IGTException)<<"No input stream set!"; } if (!stream->good()) { MITK_ERROR << "Stream not good!"; mitkThrowException(mitk::IGTException)<<"Stream not good!"; } //If something has changed in a future version of the XML definition e.g. navigationcount or addional parameters //catch this here with a select case block (see GenerateData() method) int numberOfTools = 0; std::string tempValue = m_parentElement->Value(); if(tempValue == "Version"){ *stream >> *m_parentElement; } m_parentElement->QueryIntAttribute("ToolCount",&numberOfTools); if (numberOfTools > 0) { return numberOfTools; } return 0; } void mitk::NavigationDataReaderXML::StreamInvalid(std::string message) { m_StreamEnd = true; m_ErrorMessage = message; m_StreamValid = false; mitkThrowException(mitk::IGTIOException) << "Invalid stream!"; } // -- deprecated | end diff --git a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h index 5d5b5d81f4..8c6dc89b47 100644 --- a/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h +++ b/Modules/IGTBase/autoload/IO/mitkNavigationDataReaderXML.h @@ -1,106 +1,106 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ #define MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ #include #include #include // includes for exceptions #include #include class TiXmlElement; class TiXmlNode; namespace mitk { class MITKIGTIO_EXPORT NavigationDataReaderXML : public AbstractFileReader { public: NavigationDataReaderXML(); ~NavigationDataReaderXML() override; using AbstractFileReader::Read; - std::vector> Read() override; protected: + std::vector> DoRead() override; NavigationDataReaderXML(const NavigationDataReaderXML& other); mitk::NavigationDataReaderXML* Clone() const override; NavigationDataSet::Pointer ReadNavigationDataSet(); /** * \brief This method reads one line of the XML document and returns the data as a NavigationData object * If there is a new file version another method must be added which reads this data. * @throw mitk::IGTException Throws an exceptions if file is damaged. */ mitk::NavigationData::Pointer ReadVersion1(); mitk::NavigationData::Pointer ReadNavigationData(TiXmlElement* elem); std::string m_FileName; TiXmlElement* m_parentElement; TiXmlNode* m_currentNode; int m_FileVersion; ///< indicates which XML encoding is used int m_NumberOfOutputs; ///< stores the number of outputs known from the XML document // -- deprecated | begin //std::istream* m_Stream; ///< stores a pointer to the input stream bool m_StreamEnd; ///< stores if the input stream arrived at end bool m_StreamValid; ///< stores if the input stream is valid or not std::string m_ErrorMessage; ///< stores the error message if the stream is invalid /** * \brief Creates a stream out of the filename given by the variable m_FileName. * The stream is then set to m_Stream. * * @throw mitk::IGTIOException Throws an exception if file does not exist * @throw mitk::IGTException Throws an exception if the stream is nullptr */ //void CreateStreamFromFilename(); /** * \brief Returns the file version out of the XML document. * @throw mitk::IGTException Throws an mitk::IGTException an exception if stream is nullptr or not good. * @throw mitk::IGTIOException Throws an mitk::IGTIOException if the stream has an incompatible XML format. */ unsigned int GetFileVersion(std::istream* stream); /** * \brief Returns the number of tracked tools out of the XML document. * @throw Throws an exception if stream is nullptr. * @throw Throws an exception if the input stream has an XML incompatible format. */ unsigned int GetNumberOfNavigationDatas(std::istream* stream); /** * @brief This is a helping method which gives an error message and throws an exception with the given message. * It can be used if a stream is found to be invalid. * * @throw mitk::IGTIOException Always throws an exception. */ void StreamInvalid(std::string message); ///< help method which sets the stream invalid and displays an error // -- deprecated | end private: NavigationDataSet::Pointer Read(std::istream* stream); NavigationDataSet::Pointer Read(std::string fileName); }; } // namespace mitk #endif // MITKNavigationDataReaderXML_H_HEADER_INCLUDED_ diff --git a/Modules/IOExt/Internal/mitkObjFileReaderService.cpp b/Modules/IOExt/Internal/mitkObjFileReaderService.cpp index b60f99fb6d..f5c1919e3c 100644 --- a/Modules/IOExt/Internal/mitkObjFileReaderService.cpp +++ b/Modules/IOExt/Internal/mitkObjFileReaderService.cpp @@ -1,53 +1,53 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkObjFileReaderService.h" #include #include #include // VTK #include #include mitk::ObjFileReaderService::ObjFileReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::WAVEFRONT_OBJ_MIMETYPE()), "Wavefront OBJ Reader") { this->RegisterService(); } mitk::ObjFileReaderService::~ObjFileReaderService() { } -std::vector> mitk::ObjFileReaderService::Read() +std::vector> mitk::ObjFileReaderService::DoRead() { std::vector> result; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(GetInputLocation().c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(reader->GetOutput()); result.push_back(dynamic_cast(surface.GetPointer())); } return result; } mitk::ObjFileReaderService *mitk::ObjFileReaderService::Clone() const { return new ObjFileReaderService(*this); } diff --git a/Modules/IOExt/Internal/mitkObjFileReaderService.h b/Modules/IOExt/Internal/mitkObjFileReaderService.h index 6a059881c8..7a3f3919b2 100644 --- a/Modules/IOExt/Internal/mitkObjFileReaderService.h +++ b/Modules/IOExt/Internal/mitkObjFileReaderService.h @@ -1,45 +1,47 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef ObjFileReaderService_h #define ObjFileReaderService_h #include #include namespace mitk { class BaseData; /** * @brief Used to read surfaces from Wavefront OBJ files. * * @ingroup IOExt */ class ObjFileReaderService : public AbstractFileReader { public: ObjFileReaderService(); ~ObjFileReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; static mitk::CustomMimeType mimeType; + protected: + std::vector> DoRead() override; + private: ObjFileReaderService *Clone() const override; }; } // namespace mitk #endif /* ObjFileReaderService_h */ diff --git a/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp b/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp index 8f6bf4eb1a..bb44d3ed6a 100644 --- a/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp +++ b/Modules/IOExt/Internal/mitkPlyFileReaderService.cpp @@ -1,53 +1,53 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkPlyFileReaderService.h" #include #include #include // VTK #include #include mitk::PlyFileReaderService::PlyFileReaderService() : AbstractFileReader(CustomMimeType(IOMimeTypes::STANFORD_PLY_MIMETYPE()), "Stanford Triangle PLY Reader") { this->RegisterService(); } mitk::PlyFileReaderService::~PlyFileReaderService() { } -std::vector> mitk::PlyFileReaderService::Read() +std::vector> mitk::PlyFileReaderService::DoRead() { std::vector> result; vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(GetInputLocation().c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { mitk::Surface::Pointer surface = mitk::Surface::New(); surface->SetVtkPolyData(reader->GetOutput()); result.push_back(dynamic_cast(surface.GetPointer())); } return result; } mitk::PlyFileReaderService *mitk::PlyFileReaderService::Clone() const { return new PlyFileReaderService(*this); } diff --git a/Modules/IOExt/Internal/mitkPlyFileReaderService.h b/Modules/IOExt/Internal/mitkPlyFileReaderService.h index ac81e403e6..52c1d6b19e 100644 --- a/Modules/IOExt/Internal/mitkPlyFileReaderService.h +++ b/Modules/IOExt/Internal/mitkPlyFileReaderService.h @@ -1,47 +1,49 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef PlyFileReaderService_h #define PlyFileReaderService_h #include #include namespace mitk { class BaseData; /** * @brief Used to read surfaces from the PLY format. * * This reader can read binary and ASCII versions of the format transparently. * * @ingroup IOExt */ class PlyFileReaderService : public AbstractFileReader { public: PlyFileReaderService(); ~PlyFileReaderService() override; using AbstractFileReader::Read; - std::vector> Read() override; static mitk::CustomMimeType mimeType; + protected: + std::vector> DoRead() override; + private: PlyFileReaderService *Clone() const override; }; } // namespace mitk #endif /* PlyFileReaderService_h */ diff --git a/Modules/IOExt/Internal/mitkSceneFileReader.cpp b/Modules/IOExt/Internal/mitkSceneFileReader.cpp index 121c6a3817..62ae6221f4 100644 --- a/Modules/IOExt/Internal/mitkSceneFileReader.cpp +++ b/Modules/IOExt/Internal/mitkSceneFileReader.cpp @@ -1,65 +1,81 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkSceneFileReader.h" #include #include #include +#include namespace mitk { SceneFileReader::SceneFileReader() : AbstractFileReader() { CustomMimeType mimeType(IOMimeTypes::DEFAULT_BASE_NAME() + ".scene"); mimeType.SetComment("MITK Scene Files"); mimeType.SetCategory("MITK Scenes"); mimeType.AddExtension("mitk"); this->SetDescription("MITK Scene Reader"); this->SetMimeType(mimeType); this->RegisterService(); } DataStorage::SetOfObjects::Pointer SceneFileReader::Read(DataStorage &ds) { // const DataStorage::SetOfObjects::STLContainerType& oldNodes = ds.GetAll()->CastToSTLConstContainer(); DataStorage::SetOfObjects::ConstPointer oldNodes = ds.GetAll(); SceneIO::Pointer sceneIO = SceneIO::New(); sceneIO->LoadScene(this->GetLocalFileName(), &ds, false); DataStorage::SetOfObjects::ConstPointer newNodes = ds.GetAll(); // Compute the difference DataStorage::SetOfObjects::Pointer result = DataStorage::SetOfObjects::New(); unsigned int index = 0; for (DataStorage::SetOfObjects::ConstIterator iter = newNodes->Begin(), iterEnd = newNodes->End(); iter != iterEnd; ++iter) { if (!oldNodes->empty()) { if (std::find(oldNodes->begin(), oldNodes->end(), iter.Value()) == oldNodes->end()) result->InsertElement(index++, iter.Value()); } else { result->InsertElement(index++, iter.Value()); } } return result; } - std::vector SceneFileReader::Read() { return AbstractFileReader::Read(); } + std::vector SceneFileReader::DoRead() + { + std::vector result; + + DataStorage::Pointer ds = StandaloneDataStorage::New().GetPointer(); + this->Read(*ds); + DataStorage::SetOfObjects::ConstPointer dataNodes = ds->GetAll(); + for (DataStorage::SetOfObjects::ConstIterator iter = dataNodes->Begin(), iterEnd = dataNodes->End(); + iter != iterEnd; + ++iter) + { + result.push_back(iter.Value()->GetData()); + } + return result; + } + SceneFileReader *SceneFileReader::Clone() const { return new SceneFileReader(*this); } } diff --git a/Modules/IOExt/Internal/mitkSceneFileReader.h b/Modules/IOExt/Internal/mitkSceneFileReader.h index e2c89774a3..efdc7c2f28 100644 --- a/Modules/IOExt/Internal/mitkSceneFileReader.h +++ b/Modules/IOExt/Internal/mitkSceneFileReader.h @@ -1,36 +1,38 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef SceneFileReader_H_HEADER_INCLUDED #define SceneFileReader_H_HEADER_INCLUDED // MITK #include namespace mitk { class SceneFileReader : public mitk::AbstractFileReader { public: SceneFileReader(); using AbstractFileReader::Read; - std::vector> Read() override; DataStorage::SetOfObjects::Pointer Read(DataStorage &ds) override; + protected: + std::vector> DoRead() override; + private: SceneFileReader *Clone() const override; }; } // namespace mitk #endif /* SceneFileReader_H_HEADER_INCLUDED_C1E7E521 */ diff --git a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp index 13481b9963..6836dd7cd1 100644 --- a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp +++ b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.cpp @@ -1,88 +1,88 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkVtkUnstructuredGridReader.h" #include #include #include #include #include #include #include mitk::VtkUnstructuredGridReader::VtkUnstructuredGridReader() : AbstractFileReader() { CustomMimeType mimeType(IOMimeTypes::DEFAULT_BASE_NAME() + ".vtu"); mimeType.SetComment("Vtk Unstructured Grid Files"); mimeType.SetCategory("Vtk Unstructured Grid"); mimeType.AddExtension("vtu"); mimeType.AddExtension("vtk"); this->SetDescription("Vtk Unstructured Grid Files"); this->SetMimeType(mimeType); this->RegisterService(); } mitk::VtkUnstructuredGridReader::~VtkUnstructuredGridReader() { } -std::vector> mitk::VtkUnstructuredGridReader::Read() +std::vector> mitk::VtkUnstructuredGridReader::DoRead() { MITK_INFO << "Loading " << " as vtk unstructured grid"; std::vector> result; MITK_INFO << this->GetLocalFileName(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(GetLocalFileName().c_str()); ext = itksys::SystemTools::LowerCase(ext); if (ext == ".vtk") { vtkDataReader *chooser = vtkDataReader::New(); chooser->SetFileName(GetLocalFileName().c_str()); if (chooser->IsFileUnstructuredGrid()) { vtkUnstructuredGridReader *reader = vtkUnstructuredGridReader::New(); reader->SetFileName(GetLocalFileName().c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { mitk::UnstructuredGrid::Pointer grid = mitk::UnstructuredGrid::New(); grid->SetVtkUnstructuredGrid(reader->GetOutput()); result.push_back(grid.GetPointer()); } reader->Delete(); } } else if (ext == ".vtu") { vtkXMLUnstructuredGridReader *reader = vtkXMLUnstructuredGridReader::New(); reader->SetFileName(GetLocalFileName().c_str()); reader->Update(); if (reader->GetOutput() != nullptr) { mitk::UnstructuredGrid::Pointer grid = mitk::UnstructuredGrid::New(); grid->SetVtkUnstructuredGrid(reader->GetOutput()); result.push_back(grid.GetPointer()); } reader->Delete(); } return result; } mitk::VtkUnstructuredGridReader *mitk::VtkUnstructuredGridReader::Clone() const { return new mitk::VtkUnstructuredGridReader(*this); } diff --git a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h index 1c9fa10f9f..122a715556 100644 --- a/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h +++ b/Modules/IOExt/Internal/mitkVtkUnstructuredGridReader.h @@ -1,36 +1,37 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef VtkUnstructuredGridReader_H_HEADER_INCLUDED #define VtkUnstructuredGridReader_H_HEADER_INCLUDED #include namespace mitk { //##Documentation //## @brief Reader to read unstructured grid files in vtk-format class VtkUnstructuredGridReader : public AbstractFileReader { public: VtkUnstructuredGridReader(); ~VtkUnstructuredGridReader() override; using AbstractFileReader::Read; - std::vector> Read() override; protected: + std::vector> DoRead() override; + VtkUnstructuredGridReader *Clone() const override; }; } // namespace mitk #endif /* VtkUnstructuredGridReader_H_HEADER_INCLUDED */ diff --git a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp index 2a5c956b32..61884011f1 100644 --- a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp +++ b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.cpp @@ -1,299 +1,299 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkPicFileReader.h" #include "mitkPicHelper.h" #include "mitkCustomMimeType.h" #include "mitkImageWriteAccessor.h" #include static mitk::PixelType CastToPixelType(mitkIpPicType_t pictype, size_t bpe) { const bool isSignedIntegralType = (pictype == mitkIpPicInt); const bool isUnsignedIntegralType = (pictype == mitkIpPicUInt); if (isSignedIntegralType) { switch (bpe) { case sizeof(char) : return mitk::MakeScalarPixelType(); case sizeof(short) : return mitk::MakeScalarPixelType(); default: return mitk::MakeScalarPixelType(); } } else if (isUnsignedIntegralType) { switch (bpe) { case sizeof(unsigned char) : return mitk::MakeScalarPixelType(); case sizeof(unsigned short) : return mitk::MakeScalarPixelType(); default: return mitk::MakeScalarPixelType(); } } else // is floating point type { switch (bpe) { case sizeof(float) : return mitk::MakeScalarPixelType(); default: return mitk::MakeScalarPixelType(); } } } static mitk::ImageDescriptor::Pointer CastToImageDescriptor(mitkIpPicDescriptor *desc) { mitk::ImageDescriptor::Pointer imDescriptor = mitk::ImageDescriptor::New(); imDescriptor->Initialize(desc->n, desc->dim); mitk::PixelType ptype = ::CastToPixelType(desc->type, (desc->bpe / 8)); imDescriptor->AddNewChannel(ptype, "imported by pic"); return imDescriptor; } static mitkIpPicType_t CastToIpPicType(int intype) { const bool isSignedIntegralType = (intype == itk::ImageIOBase::INT || intype == itk::ImageIOBase::SHORT || intype == itk::ImageIOBase::CHAR || intype == itk::ImageIOBase::LONG); const bool isUnsignedIntegralType = (intype == itk::ImageIOBase::UINT || intype == itk::ImageIOBase::USHORT || intype == itk::ImageIOBase::UCHAR || intype == itk::ImageIOBase::ULONG); const bool isFloatingPointType = (intype == itk::ImageIOBase::FLOAT || intype == itk::ImageIOBase::DOUBLE); if (isSignedIntegralType) return mitkIpPicInt; if (isUnsignedIntegralType) return mitkIpPicUInt; if (isFloatingPointType) return mitkIpPicFloat; return mitkIpPicUnknown; } static mitkIpPicDescriptor * CastToIpPicDescriptor(mitk::Image::Pointer refImg, mitk::ImageWriteAccessor *imageAccess, mitkIpPicDescriptor *picDesc) { const mitk::ImageDescriptor::Pointer imDesc = refImg->GetImageDescriptor(); // initialize dimension information for (unsigned int i = 0; i < 8; i++) { picDesc->n[i] = 1; } // set dimension information picDesc->dim = refImg->GetDimension(); memcpy(picDesc->n, imDesc->GetDimensions(), picDesc->dim * sizeof(unsigned int)); picDesc->type = ::CastToIpPicType(refImg->GetPixelType().GetComponentType()); picDesc->bpe = refImg->GetPixelType().GetBpe(); if (imageAccess != nullptr) { picDesc->data = imageAccess->GetData(); } return picDesc; } mitk::PicFileReader::PicFileReader() : AbstractFileReader() { CustomMimeType mimeType(this->GetMimeTypePrefix() + "mbipic"); mimeType.AddExtension("pic"); mimeType.AddExtension("pic.gz"); mimeType.AddExtension("PIC"); mimeType.AddExtension("PIC.gz"); mimeType.SetCategory("Images"); mimeType.SetComment("DKFZ Legacy PIC Format"); this->SetMimeType(mimeType); this->SetDescription("DKFZ PIC"); this->RegisterService(); } -std::vector mitk::PicFileReader::Read() +std::vector mitk::PicFileReader::DoRead() { mitk::Image::Pointer image = this->CreateImage(); this->FillImage(image); std::vector result; result.push_back(image.GetPointer()); return result; } mitk::Image::Pointer mitk::PicFileReader::CreateImage() { Image::Pointer output = Image::New(); std::string fileName = this->GetLocalFileName(); mitkIpPicDescriptor *header = mitkIpPicGetHeader(fileName.c_str(), nullptr); if (!header) { mitkThrow() << "File could not be read."; } header = mitkIpPicGetTags(fileName.c_str(), header); int channels = 1; mitkIpPicTSV_t *tsv; if ((tsv = mitkIpPicQueryTag(header, "SOURCE HEADER")) != nullptr) { if (tsv->n[0] > 1e+06) { mitkIpPicTSV_t *tsvSH; tsvSH = mitkIpPicDelTag(header, "SOURCE HEADER"); mitkIpPicFreeTag(tsvSH); } } if ((tsv = mitkIpPicQueryTag(header, "ICON80x80")) != nullptr) { mitkIpPicTSV_t *tsvSH; tsvSH = mitkIpPicDelTag(header, "ICON80x80"); mitkIpPicFreeTag(tsvSH); } if ((tsv = mitkIpPicQueryTag(header, "VELOCITY")) != nullptr) { ++channels; mitkIpPicDelTag(header, "VELOCITY"); } if (header == nullptr || header->bpe == 0) { mitkThrow() << " Could not read file " << fileName; } // if pic image only 2D, the n[2] value is not initialized unsigned int slices = 1; if (header->dim == 2) { header->n[2] = slices; } // First initialize the geometry of the output image by the pic-header SlicedGeometry3D::Pointer slicedGeometry = mitk::SlicedGeometry3D::New(); PicHelper::InitializeEvenlySpaced(header, header->n[2], slicedGeometry); // if pic image only 3D, the n[3] value is not initialized unsigned int timesteps = 1; if (header->dim > 3) { timesteps = header->n[3]; } slicedGeometry->ImageGeometryOn(); ProportionalTimeGeometry::Pointer timeGeometry = ProportionalTimeGeometry::New(); timeGeometry->Initialize(slicedGeometry, timesteps); // Cast the pic descriptor to ImageDescriptor and initialize the output output->Initialize(CastToImageDescriptor(header)); output->SetTimeGeometry(timeGeometry); mitkIpPicFree(header); return output; } void mitk::PicFileReader::ConvertHandedness(mitkIpPicDescriptor *pic) { // left to right handed conversion if (pic->dim >= 3) { mitkIpPicDescriptor *slice = mitkIpPicCopyHeader(pic, nullptr); slice->dim = 2; size_t size = _mitkIpPicSize(slice); slice->data = malloc(size); size_t v, volumes = (pic->dim > 3 ? pic->n[3] : 1); size_t volume_size = size * pic->n[2]; for (v = 0; v < volumes; ++v) { auto *p_first = (unsigned char *)pic->data; auto *p_last = (unsigned char *)pic->data; p_first += v * volume_size; p_last += size * (pic->n[2] - 1) + v * volume_size; size_t i, smid = pic->n[2] / 2; for (i = 0; i < smid; ++i, p_last -= size, p_first += size) { memcpy(slice->data, p_last, size); memcpy(p_last, p_first, size); memcpy(p_first, slice->data, size); } } mitkIpPicFree(slice); } } mitk::PicFileReader *mitk::PicFileReader::Clone() const { return new PicFileReader(*this); } void mitk::PicFileReader::FillImage(Image::Pointer output) { mitkIpPicDescriptor *outputPic = mitkIpPicNew(); outputPic = CastToIpPicDescriptor(output, nullptr, outputPic); mitkIpPicDescriptor *pic = mitkIpPicGet(this->GetLocalFileName().c_str(), outputPic); // comes upside-down (in MITK coordinates) from PIC file ConvertHandedness(pic); mitkIpPicTSV_t *tsv; if ((tsv = mitkIpPicQueryTag(pic, "SOURCE HEADER")) != nullptr) { if (tsv->n[0] > 1e+06) { mitkIpPicTSV_t *tsvSH; tsvSH = mitkIpPicDelTag(pic, "SOURCE HEADER"); mitkIpPicFreeTag(tsvSH); } } if ((tsv = mitkIpPicQueryTag(pic, "ICON80x80")) != nullptr) { mitkIpPicTSV_t *tsvSH; tsvSH = mitkIpPicDelTag(pic, "ICON80x80"); mitkIpPicFreeTag(tsvSH); } if ((tsv = mitkIpPicQueryTag(pic, "VELOCITY")) != nullptr) { mitkIpPicDescriptor *header = mitkIpPicCopyHeader(pic, nullptr); header->data = tsv->value; ConvertHandedness(header); output->SetChannel(header->data, 1); header->data = nullptr; mitkIpPicFree(header); mitkIpPicDelTag(pic, "VELOCITY"); } // Copy the memory to avoid mismatches of malloc() and delete[]. // mitkIpPicGet will always allocate a new memory block with malloc(), // but MITK Images delete the data via delete[]. output->SetImportChannel(pic->data, 0, Image::CopyMemory); pic->data = nullptr; mitkIpPicFree(pic); } diff --git a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h index e22f15614f..f472490732 100644 --- a/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h +++ b/Modules/IpPicSupportIO/Internal/mitkPicFileReader.h @@ -1,47 +1,48 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef PICFILEREADER_H_HEADER_INCLUDED_C1F48A22 #define PICFILEREADER_H_HEADER_INCLUDED_C1F48A22 #include "mitkAbstractFileReader.h" #include "mitkImage.h" #include "mitkIpPic.h" namespace mitk { //##Documentation //## @brief Reader to read files in DKFZ-pic-format class PicFileReader : public AbstractFileReader { public: PicFileReader(); using AbstractFileReader::Read; - std::vector Read() override; protected: void FillImage(Image::Pointer image); Image::Pointer CreateImage(); + std::vector> DoRead() override; + private: static void ConvertHandedness(mitkIpPicDescriptor *pic); PicFileReader *Clone() const override; }; } // namespace mitk #endif /* PICFILEREADER_H_HEADER_INCLUDED_C1F48A22 */ diff --git a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp index 72b1e39152..8e809e044b 100644 --- a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp +++ b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.cpp @@ -1,315 +1,280 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include #include #include #include "mapRegistration.h" #include "mapRegistrationFileWriter.h" #include "mapRegistrationFileReader.h" #include "mapLazyFileFieldKernelLoader.h" #include #include +#include #include "mitkMAPRegistrationWrapperIO.h" #include "mitkMAPRegistrationWrapper.h" namespace mitk { - /** Helper structure to change (and reset) the - * local settings in a function scope*/ - struct LocaleSwitch - { - LocaleSwitch(const std::string& newLocale) - : m_OldLocale(std::setlocale(LC_ALL, nullptr)) - , m_NewLocale(newLocale) - { - if (m_OldLocale == nullptr) - { - m_OldLocale = ""; - } - else if (m_NewLocale != m_OldLocale) - { - // set the locale - if (std::setlocale(LC_ALL, m_NewLocale.c_str()) == nullptr) - { - MITK_INFO << "Could not set locale " << m_NewLocale; - m_OldLocale = nullptr; - } - } - } - - ~LocaleSwitch() - { - if (m_OldLocale != nullptr && std::setlocale(LC_ALL, m_OldLocale) == nullptr) - { - MITK_INFO << "Could not reset locale " << m_OldLocale; - } - } - - private: - const char* m_OldLocale; - const std::string m_NewLocale; - }; - /** Helper class that allows to use an functor in multiple combinations of * moving and target dimensions on a passed MAPRegistrationWrapper instance.\n * DimHelperSub is used DimHelper to iterate in a row of the dimension * combination matrix. */ template< unsigned int i, unsigned int j, template < unsigned int, unsigned int> class TFunctor> class DimHelperSub { public: static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data) { if (TFunctor::Execute(obj, data)) { return true; } return DimHelperSub::Execute(obj, data); } }; /** Specialized template version of DimSubHelper that indicates the end * of the row in the dimension combination matrix, thus does nothing. */ template< unsigned int i, template < unsigned int, unsigned int> class TFunctor> class DimHelperSub { public: static bool Execute(const mitk::MAPRegistrationWrapper*, const map::core::String&) { //just unwind. Go to the next "row" with DimHelper return false; } }; /** Helper class that allows to use an functor in multiple combinations of * moving and target dimensions on a passed MAPRegistrationWrapper instance.\n * It is helpful if you want to ensure that all combinations are checked/touched * (e.g. 3D 3D, 3D 2D, 2D 3D, 2D 2D) without generating a large switch yard. * Think of n*m matrix (indicating the posible combinations). DimHelper walks from * one row to the next and uses DimHelperSub to iterate in a row.\n * For every element of the matrix the functor is executed on the passed object. */ template< unsigned int i, unsigned int j, template < unsigned int, unsigned int> class TFunctor> class DimHelper{ public: static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data = "") { if (DimHelperSub::Execute(obj, data)) { return true; } return DimHelper::Execute(obj, data); } }; /** Specialized template version of DimHelper that indicates the end * of the dimension combination matrix, thus does nothing. */ template< unsigned int j, template < unsigned int, unsigned int> class TFunctor> class DimHelper<1,j, TFunctor > { public: static bool Execute(const mitk::MAPRegistrationWrapper*, const map::core::String&) { //just unwind. We are done. return false; } }; /** Functor that checks of the dimension of the registration is supported and can * be written. */ template class CanWrite { public: static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& = "") { bool result = false; result = dynamic_cast *>(obj->GetRegistration()) != nullptr; return result; } }; /** Functor that writes the registration to a file if it has the right dimensionality. */ template class WriteReg { public: static bool Execute(const mitk::MAPRegistrationWrapper* obj, const map::core::String& data) { const map::core::Registration* pReg = dynamic_cast*>(obj->GetRegistration()); if (pReg == nullptr) { return false; } typedef map::io::RegistrationFileWriter WriterType; typename WriterType::Pointer writer = WriterType::New(); writer->setExpandLazyKernels(false); try { writer->write(pReg,data); } catch (const itk::ExceptionObject& e) { std::cout << e.what() << std::endl; throw; } return true; } }; MAPRegistrationWrapperIO::MAPRegistrationWrapperIO(const MAPRegistrationWrapperIO& other) : AbstractFileIO(other) { } MAPRegistrationWrapperIO::MAPRegistrationWrapperIO() : AbstractFileIO(mitk::MAPRegistrationWrapper::GetStaticNameOfClass()) { std::string category = "MatchPoint Registration File"; CustomMimeType customMimeType; customMimeType.SetCategory(category); customMimeType.AddExtension("mapr"); this->AbstractFileIOWriter::SetMimeType(customMimeType); this->AbstractFileIOWriter::SetDescription(category); customMimeType.AddExtension("mapr.xml"); customMimeType.AddExtension("MAPR"); customMimeType.AddExtension("MAPR.XML"); this->AbstractFileIOReader::SetMimeType(customMimeType); this->AbstractFileIOReader::SetDescription(category); this->RegisterService(); } void MAPRegistrationWrapperIO::Write() { bool success = false; const BaseData* input = this->GetInput(); if (input == nullptr) { mitkThrow() << "Cannot write data. Data pointer is nullptr."; } const mitk::MAPRegistrationWrapper* wrapper = dynamic_cast(input); if (wrapper == nullptr) { mitkThrow() << "Cannot write data. Data pointer is not a Registration wrapper."; } std::ostream* writeStream = this->GetOutputStream(); std::string fileName = this->GetOutputLocation(); if (writeStream) { fileName = this->GetLocalFileName(); } // Switch the current locale to "C" LocaleSwitch localeSwitch("C"); try { success = DimHelper<3,3,WriteReg>::Execute(wrapper, fileName); } catch (const std::exception& e) { mitkThrow() << e.what(); } if (!success) { mitkThrow() << "Cannot write registration. Currently only registrations up to 4D are supported."; } } AbstractFileIO::ConfidenceLevel MAPRegistrationWrapperIO::GetWriterConfidenceLevel() const { const mitk::MAPRegistrationWrapper* regWrapper = dynamic_cast(this->GetInput()); if (regWrapper == nullptr) { return IFileWriter::Unsupported; } // Check if the registration dimension is supported if (! DimHelper<3,3,CanWrite>::Execute(regWrapper)) { return IFileWriter::Unsupported; }; return IFileWriter::Supported; } - std::vector MAPRegistrationWrapperIO::Read() + std::vector MAPRegistrationWrapperIO::DoRead() { std::vector result; LocaleSwitch("C"); std::string fileName = this->GetLocalFileName(); if ( fileName.empty() ) { mitkThrow() << "Cannot read file. Filename has not been set!"; } /* Remove the following kernel loader provider because in MITK no lazy file loading should be used due to conflicts with session loading (end there usage of temporary directories)*/ map::io::RegistrationFileReader::LoaderStackType::unregisterProvider(map::io::LazyFileFieldKernelLoader<2,2>::getStaticProviderName()); map::io::RegistrationFileReader::LoaderStackType::unregisterProvider(map::io::LazyFileFieldKernelLoader<3,3>::getStaticProviderName()); map::io::RegistrationFileReader::Pointer spReader = map::io::RegistrationFileReader::New(); spReader->setPreferLazyLoading(true); map::core::RegistrationBase::Pointer spReg = spReader->read(fileName); mitk::MAPRegistrationWrapper::Pointer spRegWrapper = mitk::MAPRegistrationWrapper::New(); spRegWrapper->SetRegistration(spReg); result.push_back(spRegWrapper.GetPointer()); return result; } AbstractFileIO::ConfidenceLevel MAPRegistrationWrapperIO::GetReaderConfidenceLevel() const { AbstractFileIO::ConfidenceLevel result = IFileReader::Unsupported; std::string fileName = this->GetLocalFileName(); std::ifstream in( fileName.c_str() ); if ( in.good() ) { result = IFileReader::Supported; } in.close(); return result; } MAPRegistrationWrapperIO* MAPRegistrationWrapperIO::IOClone() const { return new MAPRegistrationWrapperIO(*this); } } diff --git a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h index 62f7180a03..cf3042e9ed 100644 --- a/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h +++ b/Modules/MatchPointRegistration/autoload/IO/mitkMAPRegistrationWrapperIO.h @@ -1,49 +1,51 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_MAP_REGISTRATION_WRAPPER_IO_H #define _MITK_MAP_REGISTRATION_WRAPPER_IO_H #include #include "MitkMatchPointRegistrationExports.h" namespace mitk { /** * Offers IO capability for MatchPoint registration wrappers */ class MAPRegistrationWrapperIO : public AbstractFileIO { public: MAPRegistrationWrapperIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector > Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; + protected: + std::vector> DoRead() override; + private: MAPRegistrationWrapperIO(const MAPRegistrationWrapperIO& other); MAPRegistrationWrapperIO* IOClone() const override; }; } // end of namespace mitk #endif diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp index acaa3bc0cb..fb7bc8b6ca 100644 --- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp +++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.cpp @@ -1,707 +1,707 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkDICOMSegmentationIO__cpp #define __mitkDICOMSegmentationIO__cpp #include "mitkDICOMSegmentationIO.h" #include "mitkDICOMSegIOMimeTypes.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::MitkDICOMSEGIOMimeTypes::DICOMSEG_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; // Check if the input file is a segmentation const LabelSetImage *input = static_cast(this->GetInput()); if (input) { if ((input->GetDimension() != 3)) { MITK_INFO << "DICOM segmentation writer is tested only with 3D images, sorry."; return Unsupported; } // Check if input file has dicom information for the referenced image (original DICOM image, e.g. CT) Still necessary, see write() mitk::StringLookupTableProperty::Pointer dicomFilesProp = dynamic_cast(input->GetProperty("referenceFiles").GetPointer()); if (dicomFilesProp.IsNotNull()) return Supported; } 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> dcmDatasetsSourceImage; std::unique_ptr 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()) { std::unique_ptr readDCMDataset(readFileFormat->getAndRemoveDataset()); dcmDatasetsSourceImage.push_back(std::move(readDCMDataset)); } } } 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); // 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 { //TODO is there a better way? Interface expects a vector of raw pointer. vector rawVecDataset; for (const auto& dcmDataSet : dcmDatasetsSourceImage) rawVecDataset.push_back(dcmDataSet.get()); // Convert itk segmentation images to dicom image std::unique_ptr converter = std::make_unique(); std::unique_ptr result(converter->itkimage2dcmSegmentation(rawVecDataset, segmentations, tmpMetaInfoFile)); // Write dicom file DcmFileFormat dcmFileFormat(result.get()); 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) { MITK_ERROR << "An error occurred during writing the DICOM Seg: " << e.what() << endl; return; } } // Write a dcm file for the next layer } 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() + std::vector DICOMSegmentationIO::DoRead() { 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) std::unique_ptr converter = std::make_unique(); 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; } labelSetImage->GetLabelSet()->SetAllLabelsVisible(true); // 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); } catch (const std::exception &e) { MITK_ERROR << "An error occurred while reading the DICOM Seg file: " << e.what(); return result; } catch (...) { MITK_ERROR << "An error occurred in dcmqi while reading the DICOM Seg file"; 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) { TemporoSpatialStringProperty *segmentNumberProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_NUMBER_PATH()).c_str())); TemporoSpatialStringProperty *segmentLabelProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str())); TemporoSpatialStringProperty *algorithmTypeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_ALGORITHM_TYPE_PATH()).c_str())); TemporoSpatialStringProperty *segmentCategoryCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_VALUE_PATH()).c_str())); TemporoSpatialStringProperty *segmentCategoryCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_SCHEME_PATH()).c_str())); TemporoSpatialStringProperty *segmentCategoryCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str())); TemporoSpatialStringProperty *segmentTypeCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_VALUE_PATH()).c_str())); TemporoSpatialStringProperty *segmentTypeCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_SCHEME_PATH()).c_str())); TemporoSpatialStringProperty *segmentTypeCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str())); TemporoSpatialStringProperty *segmentModifierCodeValueProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_VALUE_PATH()).c_str())); TemporoSpatialStringProperty *segmentModifierCodeSchemeProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_SCHEME_PATH()).c_str())); TemporoSpatialStringProperty *segmentModifierCodeMeaningProp = dynamic_cast(label->GetProperty( mitk::DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str())); dcmqi::SegmentAttributes *segmentAttribute = nullptr; if (segmentNumberProp->GetValue() == "") { 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(), TemporoSpatialStringProperty::New(std::to_string(label->GetValue()))); // Segment Label: User-defined label identifying this segment. label->SetProperty(DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_LABEL_PATH()).c_str(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning categoryCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_CATEGORY_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning typeCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_TYPE_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning modifierCodeSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::SEGMENT_MODIFIER_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::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(), TemporoSpatialStringProperty::New(codeScheme.c_str())); OFString codeMeaning; // (0008,0104) Code Meaning atomicRegionSequence->getCodeMeaning(codeMeaning); label->SetProperty( DICOMTagPathToPropertyName(DICOMSegmentationConstants::ANATOMIC_REGION_CODE_MEANING_PATH()).c_str(), TemporoSpatialStringProperty::New(codeMeaning.c_str())); } } DICOMSegmentationIO *DICOMSegmentationIO::IOClone() const { return new DICOMSegmentationIO(*this); } } // namespace #endif //__mitkDICOMSegmentationIO__cpp diff --git a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h index 5767e9f3fe..123bcb803c 100644 --- a/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h +++ b/Modules/Multilabel/autoload/DICOMSegIO/mitkDICOMSegmentationIO.h @@ -1,62 +1,64 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkDICOMSegmentationIO_h #define __mitkDICOMSegmentationIO_h #include #include #include namespace mitk { /** * Read and 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 - */ - std::vector Read() override; + ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; + protected: + /** + * @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 + */ + std::vector> DoRead() override; private: DICOMSegmentationIO *IOClone() const override; // -------------- DICOMSegmentationIO specific functions ------------- const std::string CreateMetaDataJsonFile(int layer); void SetLabelProperties(Label *label, dcmqi::SegmentAttributes *segmentAttribute); void AddDICOMTagsToService(); }; } // end of namespace mitk #endif // __mitkDICOMSegmentationIO_h diff --git a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp index 9990ea7032..9466f4a70e 100644 --- a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp +++ b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.cpp @@ -1,636 +1,636 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkLabelSetImageWriter__cpp #define __mitkLabelSetImageWriter__cpp #include "mitkLabelSetImageIO.h" #include "mitkBasePropertySerializer.h" #include "mitkIOMimeTypes.h" #include "mitkImageAccessByItk.h" #include "mitkLabelSetIOHelper.h" #include "mitkLabelSetImageConverter.h" #include #include #include #include #include // itk #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" namespace mitk { const char* const PROPERTY_NAME_TIMEGEOMETRY_TYPE = "org.mitk.timegeometry.type"; const char* const PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS = "org.mitk.timegeometry.timepoints"; const char* const PROPERTY_KEY_TIMEGEOMETRY_TYPE = "org_mitk_timegeometry_type"; const char* const PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS = "org_mitk_timegeometry_timepoints"; LabelSetImageIO::LabelSetImageIO() : AbstractFileIO(LabelSetImage::GetStaticNameOfClass(), IOMimeTypes::NRRD_MIMETYPE(), "MITK Multilabel Image") { AbstractFileWriter::SetRanking(10); AbstractFileReader::SetRanking(10); this->RegisterService(); } IFileIO::ConfidenceLevel LabelSetImageIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; const auto *input = static_cast(this->GetInput()); if (input) return Supported; else return Unsupported; } void LabelSetImageIO::Write() { ValidateOutputLocation(); auto input = dynamic_cast(this->GetInput()); mitk::LocaleSwitch localeSwitch("C"); mitk::Image::Pointer inputVector = mitk::ConvertLabelSetImageToImage(input); // image write if (inputVector.IsNull()) { mitkThrow() << "Cannot write non-image data"; } itk::NrrdImageIO::Pointer nrrdImageIo = itk::NrrdImageIO::New(); // Clone the image geometry, because we might have to change it // for writing purposes BaseGeometry::Pointer geometry = inputVector->GetGeometry()->Clone(); // Check if geometry information will be lost if (inputVector->GetDimension() == 2 && !geometry->Is2DConvertable()) { MITK_WARN << "Saving a 2D image with 3D geometry information. Geometry information will be lost! You might " "consider using Convert2Dto3DImageFilter before saving."; // set matrix to identity mitk::AffineTransform3D::Pointer affTrans = mitk::AffineTransform3D::New(); affTrans->SetIdentity(); mitk::Vector3D spacing = geometry->GetSpacing(); mitk::Point3D origin = geometry->GetOrigin(); geometry->SetIndexToWorldTransform(affTrans); geometry->SetSpacing(spacing); geometry->SetOrigin(origin); } LocalFile localFile(this); const std::string path = localFile.GetFileName(); MITK_INFO << "Writing image: " << path << std::endl; try { // Implementation of writer using itkImageIO directly. This skips the use // of templated itkImageFileWriter, which saves the multiplexing on MITK side. const unsigned int dimension = inputVector->GetDimension(); const unsigned int *const dimensions = inputVector->GetDimensions(); const mitk::PixelType pixelType = inputVector->GetPixelType(); const mitk::Vector3D mitkSpacing = geometry->GetSpacing(); const mitk::Point3D mitkOrigin = geometry->GetOrigin(); // Due to templating in itk, we are forced to save a 4D spacing and 4D Origin, // though they are not supported in MITK itk::Vector spacing4D; spacing4D[0] = mitkSpacing[0]; spacing4D[1] = mitkSpacing[1]; spacing4D[2] = mitkSpacing[2]; spacing4D[3] = 1; // There is no support for a 4D spacing. However, we should have a valid value here itk::Vector origin4D; origin4D[0] = mitkOrigin[0]; origin4D[1] = mitkOrigin[1]; origin4D[2] = mitkOrigin[2]; origin4D[3] = 0; // There is no support for a 4D origin. However, we should have a valid value here // Set the necessary information for imageIO nrrdImageIo->SetNumberOfDimensions(dimension); nrrdImageIo->SetPixelType(pixelType.GetPixelType()); nrrdImageIo->SetComponentType(pixelType.GetComponentType() < PixelComponentUserType ? static_cast(pixelType.GetComponentType()) : itk::ImageIOBase::UNKNOWNCOMPONENTTYPE); nrrdImageIo->SetNumberOfComponents(pixelType.GetNumberOfComponents()); itk::ImageIORegion ioRegion(dimension); for (unsigned int i = 0; i < dimension; i++) { nrrdImageIo->SetDimensions(i, dimensions[i]); nrrdImageIo->SetSpacing(i, spacing4D[i]); nrrdImageIo->SetOrigin(i, origin4D[i]); mitk::Vector3D mitkDirection; mitkDirection.SetVnlVector(geometry->GetIndexToWorldTransform()->GetMatrix().GetVnlMatrix().get_column(i)); itk::Vector direction4D; direction4D[0] = mitkDirection[0]; direction4D[1] = mitkDirection[1]; direction4D[2] = mitkDirection[2]; // MITK only supports a 3x3 direction matrix. Due to templating in itk, however, we must // save a 4x4 matrix for 4D images. in this case, add an homogneous component to the matrix. if (i == 3) { direction4D[3] = 1; // homogenous component } else { direction4D[3] = 0; } vnl_vector axisDirection(dimension); for (unsigned int j = 0; j < dimension; j++) { axisDirection[j] = direction4D[j] / spacing4D[i]; } nrrdImageIo->SetDirection(i, axisDirection); ioRegion.SetSize(i, inputVector->GetLargestPossibleRegion().GetSize(i)); ioRegion.SetIndex(i, inputVector->GetLargestPossibleRegion().GetIndex(i)); } // use compression if available nrrdImageIo->UseCompressionOn(); nrrdImageIo->SetIORegion(ioRegion); nrrdImageIo->SetFileName(path); // label set specific meta data char keybuffer[512]; char valbuffer[512]; sprintf(keybuffer, "modality"); sprintf(valbuffer, "org.mitk.image.multilabel"); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); sprintf(keybuffer, "layers"); sprintf(valbuffer, "%1d", input->GetNumberOfLayers()); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); for (unsigned int layerIdx = 0; layerIdx < input->GetNumberOfLayers(); layerIdx++) { sprintf(keybuffer, "layer_%03u", layerIdx); // layer idx sprintf(valbuffer, "%1u", input->GetNumberOfLabels(layerIdx)); // number of labels for the layer itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), std::string(valbuffer)); auto iter = input->GetLabelSet(layerIdx)->IteratorConstBegin(); unsigned int count(0); while (iter != input->GetLabelSet(layerIdx)->IteratorConstEnd()) { std::unique_ptr document; document.reset(new TiXmlDocument()); auto *decl = new TiXmlDeclaration("1.0", "", ""); // TODO what to write here? encoding? etc.... document->LinkEndChild(decl); TiXmlElement *labelElem = mitk::LabelSetIOHelper::GetLabelAsTiXmlElement(iter->second); document->LinkEndChild(labelElem); TiXmlPrinter printer; printer.SetIndent(""); printer.SetLineBreak(""); document->Accept(&printer); sprintf(keybuffer, "org.mitk.label_%03u_%05u", layerIdx, count); itk::EncapsulateMetaData( nrrdImageIo->GetMetaDataDictionary(), std::string(keybuffer), printer.Str()); ++iter; ++count; } } // end label set specific meta data // Handle time geometry const auto* arbitraryTG = dynamic_cast(input->GetTimeGeometry()); if (arbitraryTG) { itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), PROPERTY_KEY_TIMEGEOMETRY_TYPE, ArbitraryTimeGeometry::GetStaticNameOfClass()); auto metaTimePoints = ConvertTimePointListToMetaDataObject(arbitraryTG); nrrdImageIo->GetMetaDataDictionary().Set(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS, metaTimePoints); } // Handle properties mitk::PropertyList::Pointer imagePropertyList = input->GetPropertyList(); for (const auto& property : *imagePropertyList->GetMap()) { mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfo(property.first, GetMimeType()->GetName(), true); if (infoList.empty()) { continue; } std::string value = infoList.front()->GetSerializationFunction()(property.second); if (value == mitk::BaseProperty::VALUE_CANNOT_BE_CONVERTED_TO_STRING) { continue; } std::string key = infoList.front()->GetKey(); itk::EncapsulateMetaData(nrrdImageIo->GetMetaDataDictionary(), key, value); } ImageReadAccessor imageAccess(inputVector); nrrdImageIo->Write(imageAccess.GetData()); } catch (const std::exception &e) { mitkThrow() << e.what(); } // end image write } IFileIO::ConfidenceLevel LabelSetImageIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; const std::string fileName = this->GetLocalFileName(); itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(fileName); io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDataDictionary = io->GetMetaDataDictionary(); std::string value(""); itk::ExposeMetaData(imgMetaDataDictionary, "modality", value); if (value.compare("org.mitk.image.multilabel") == 0) { return Supported; } else return Unsupported; } - std::vector LabelSetImageIO::Read() + std::vector LabelSetImageIO::DoRead() { mitk::LocaleSwitch localeSwitch("C"); // begin regular image loading, adapted from mitkItkImageIO itk::NrrdImageIO::Pointer nrrdImageIO = itk::NrrdImageIO::New(); Image::Pointer image = Image::New(); const unsigned int MINDIM = 2; const unsigned int MAXDIM = 4; const std::string path = this->GetLocalFileName(); MITK_INFO << "loading " << path << " via itk::ImageIOFactory... " << 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 "; } // Got to allocate space for the image. Determine the characteristics of // the image. nrrdImageIO->SetFileName(path); nrrdImageIO->ReadImageInformation(); unsigned int ndim = nrrdImageIO->GetNumberOfDimensions(); if (ndim < MINDIM || ndim > MAXDIM) { MITK_WARN << "Sorry, only dimensions 2, 3 and 4 are supported. The given file has " << ndim << " dimensions! Reading as 4D."; ndim = MAXDIM; } itk::ImageIORegion ioRegion(ndim); itk::ImageIORegion::SizeType ioSize = ioRegion.GetSize(); itk::ImageIORegion::IndexType ioStart = ioRegion.GetIndex(); unsigned int dimensions[MAXDIM]; dimensions[0] = 0; dimensions[1] = 0; dimensions[2] = 0; dimensions[3] = 0; ScalarType spacing[MAXDIM]; spacing[0] = 1.0f; spacing[1] = 1.0f; spacing[2] = 1.0f; spacing[3] = 1.0f; Point3D origin; origin.Fill(0); unsigned int i; for (i = 0; i < ndim; ++i) { ioStart[i] = 0; ioSize[i] = nrrdImageIO->GetDimensions(i); if (i < MAXDIM) { dimensions[i] = nrrdImageIO->GetDimensions(i); spacing[i] = nrrdImageIO->GetSpacing(i); if (spacing[i] <= 0) spacing[i] = 1.0f; } if (i < 3) { origin[i] = nrrdImageIO->GetOrigin(i); } } ioRegion.SetSize(ioSize); ioRegion.SetIndex(ioStart); MITK_INFO << "ioRegion: " << ioRegion << std::endl; nrrdImageIO->SetIORegion(ioRegion); void *buffer = new unsigned char[nrrdImageIO->GetImageSizeInBytes()]; nrrdImageIO->Read(buffer); image->Initialize(MakePixelType(nrrdImageIO), ndim, dimensions); image->SetImportChannel(buffer, 0, Image::ManageMemory); // access direction of itk::Image and include spacing mitk::Matrix3D matrix; matrix.SetIdentity(); unsigned int j, itkDimMax3 = (ndim >= 3 ? 3 : ndim); for (i = 0; i < itkDimMax3; ++i) for (j = 0; j < itkDimMax3; ++j) matrix[i][j] = nrrdImageIO->GetDirection(j)[i]; // re-initialize PlaneGeometry with origin and direction PlaneGeometry *planeGeometry = image->GetSlicedGeometry(0)->GetPlaneGeometry(0); planeGeometry->SetOrigin(origin); planeGeometry->GetIndexToWorldTransform()->SetMatrix(matrix); // re-initialize SlicedGeometry3D SlicedGeometry3D *slicedGeometry = image->GetSlicedGeometry(0); slicedGeometry->InitializeEvenlySpaced(planeGeometry, image->GetDimension(2)); slicedGeometry->SetSpacing(spacing); MITK_INFO << slicedGeometry->GetCornerPoint(false, false, false); MITK_INFO << slicedGeometry->GetCornerPoint(true, true, true); // re-initialize TimeGeometry const itk::MetaDataDictionary& dictionary = nrrdImageIO->GetMetaDataDictionary(); TimeGeometry::Pointer timeGeometry; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE) || dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TYPE)) { // also check for the name because of backwards compatibility. Past code version stored with the name and not with // the key itk::MetaDataObject::ConstPointer timeGeometryTypeData; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TYPE)) { timeGeometryTypeData = dynamic_cast*>(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TYPE)); } else { timeGeometryTypeData = dynamic_cast*>(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TYPE)); } if (timeGeometryTypeData->GetMetaDataObjectValue() == ArbitraryTimeGeometry::GetStaticNameOfClass()) { MITK_INFO << "used time geometry: " << ArbitraryTimeGeometry::GetStaticNameOfClass(); typedef std::vector TimePointVector; TimePointVector timePoints; if (dictionary.HasKey(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS)); } else if (dictionary.HasKey(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)) { timePoints = ConvertMetaDataObjectToTimePointList(dictionary.Get(PROPERTY_KEY_TIMEGEOMETRY_TIMEPOINTS)); } if (timePoints.empty()) { MITK_ERROR << "Stored timepoints are empty. Meta information seems to bee invalid. Switch to ProportionalTimeGeometry fallback"; } else if (timePoints.size() - 1 != image->GetDimension(3)) { MITK_ERROR << "Stored timepoints (" << timePoints.size() - 1 << ") and size of image time dimension (" << image->GetDimension(3) << ") do not match. Switch to ProportionalTimeGeometry fallback"; } else { ArbitraryTimeGeometry::Pointer arbitraryTimeGeometry = ArbitraryTimeGeometry::New(); TimePointVector::const_iterator pos = timePoints.begin(); auto prePos = pos++; for (; pos != timePoints.end(); ++prePos, ++pos) { arbitraryTimeGeometry->AppendNewTimeStepClone(slicedGeometry, *prePos, *pos); } timeGeometry = arbitraryTimeGeometry; } } } if (timeGeometry.IsNull()) { // Fallback. If no other valid time geometry has been created, create a ProportionalTimeGeometry MITK_INFO << "used time geometry: " << ProportionalTimeGeometry::GetStaticNameOfClass(); ProportionalTimeGeometry::Pointer propTimeGeometry = ProportionalTimeGeometry::New(); propTimeGeometry->Initialize(slicedGeometry, image->GetDimension(3)); timeGeometry = propTimeGeometry; } image->SetTimeGeometry(timeGeometry); buffer = nullptr; MITK_INFO << "number of image components: " << image->GetPixelType().GetNumberOfComponents(); // end regular image loading LabelSetImage::Pointer output = ConvertImageToLabelSetImage(image); // get labels and add them as properties to the image char keybuffer[256]; unsigned int numberOfLayers = GetIntByKey(dictionary, "layers"); std::string _xmlStr; mitk::Label::Pointer label; for (unsigned int layerIdx = 0; layerIdx < numberOfLayers; layerIdx++) { sprintf(keybuffer, "layer_%03u", layerIdx); int numberOfLabels = GetIntByKey(dictionary, keybuffer); mitk::LabelSet::Pointer labelSet = mitk::LabelSet::New(); for (int labelIdx = 0; labelIdx < numberOfLabels; labelIdx++) { TiXmlDocument doc; sprintf(keybuffer, "label_%03u_%05d", layerIdx, labelIdx); _xmlStr = GetStringByKey(dictionary, keybuffer); doc.Parse(_xmlStr.c_str()); TiXmlElement *labelElem = doc.FirstChildElement("Label"); if (labelElem == nullptr) mitkThrow() << "Error parsing NRRD header for mitk::LabelSetImage IO"; label = mitk::LabelSetIOHelper::LoadLabelFromTiXmlDocument(labelElem); if (label->GetValue() == 0) // set exterior label is needed to hold exterior information output->SetExteriorLabel(label); labelSet->AddLabel(label); labelSet->SetLayer(layerIdx); } output->AddLabelSetToLayer(layerIdx, labelSet); } for (auto iter = dictionary.Begin(), iterEnd = dictionary.End(); iter != iterEnd; ++iter) { if (iter->second->GetMetaDataObjectTypeInfo() == typeid(std::string)) { const std::string& key = iter->first; std::string assumedPropertyName = key; std::replace(assumedPropertyName.begin(), assumedPropertyName.end(), '_', '.'); std::string mimeTypeName = GetMimeType()->GetName(); // Check if there is already a info for the key and our mime type. mitk::CoreServicePointer propPersistenceService(mitk::CoreServices::GetPropertyPersistence()); IPropertyPersistence::InfoResultType infoList = propPersistenceService->GetInfoByKey(key); auto predicate = [&mimeTypeName](const PropertyPersistenceInfo::ConstPointer& x) { return x.IsNotNull() && x->GetMimeTypeName() == mimeTypeName; }; auto finding = std::find_if(infoList.begin(), infoList.end(), predicate); if (finding == infoList.end()) { auto predicateWild = [](const PropertyPersistenceInfo::ConstPointer& x) { return x.IsNotNull() && x->GetMimeTypeName() == PropertyPersistenceInfo::ANY_MIMETYPE_NAME(); }; finding = std::find_if(infoList.begin(), infoList.end(), predicateWild); } PropertyPersistenceInfo::ConstPointer info; if (finding != infoList.end()) { assumedPropertyName = (*finding)->GetName(); info = *finding; } else { // we have not found anything suitable so we generate our own info auto newInfo = PropertyPersistenceInfo::New(); newInfo->SetNameAndKey(assumedPropertyName, key); newInfo->SetMimeTypeName(PropertyPersistenceInfo::ANY_MIMETYPE_NAME()); info = newInfo; } std::string value = dynamic_cast*>(iter->second.GetPointer())->GetMetaDataObjectValue(); mitk::BaseProperty::Pointer loadedProp = info->GetDeserializationFunction()(value); output->SetProperty(assumedPropertyName.c_str(), loadedProp); // Read properties should be persisted unless they are default properties // which are written anyway bool isDefaultKey = false; for (const auto& defaultKey : m_DefaultMetaDataKeys) { if (defaultKey.length() <= assumedPropertyName.length()) { // does the start match the default key if (assumedPropertyName.substr(0, defaultKey.length()).find(defaultKey) != std::string::npos) { isDefaultKey = true; break; } } } if (!isDefaultKey) { propPersistenceService->AddInfo(info); } } } MITK_INFO << "...finished!"; std::vector result; result.push_back(output.GetPointer()); return result; } int LabelSetImageIO::GetIntByKey(const itk::MetaDataDictionary &dic, const std::string &str) { std::vector imgMetaKeys = dic.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString(""); for (; itKey != imgMetaKeys.end(); itKey++) { itk::ExposeMetaData(dic, *itKey, metaString); if (itKey->find(str.c_str()) != std::string::npos) { return atoi(metaString.c_str()); } } return 0; } std::string LabelSetImageIO::GetStringByKey(const itk::MetaDataDictionary &dic, const std::string &str) { std::vector imgMetaKeys = dic.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString(""); for (; itKey != imgMetaKeys.end(); itKey++) { itk::ExposeMetaData(dic, *itKey, metaString); if (itKey->find(str.c_str()) != std::string::npos) { return metaString; } } return metaString; } LabelSetImageIO *LabelSetImageIO::IOClone() const { return new LabelSetImageIO(*this); } void LabelSetImageIO::InitializeDefaultMetaDataKeys() { this->m_DefaultMetaDataKeys.push_back("NRRD.space"); this->m_DefaultMetaDataKeys.push_back("NRRD.kinds"); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TYPE); this->m_DefaultMetaDataKeys.push_back(PROPERTY_NAME_TIMEGEOMETRY_TIMEPOINTS); this->m_DefaultMetaDataKeys.push_back("ITK.InputFilterName"); this->m_DefaultMetaDataKeys.push_back("label_"); this->m_DefaultMetaDataKeys.push_back("layer_"); } } // namespace #endif //__mitkLabelSetImageWriter__cpp diff --git a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h index 59277a97e5..4b079dc5e4 100644 --- a/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h +++ b/Modules/Multilabel/autoload/IO/mitkLabelSetImageIO.h @@ -1,66 +1,68 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef __mitkLabelSetImageIO_h #define __mitkLabelSetImageIO_h #include #include namespace mitk { /** * Writes a LabelSetImage to a file * @ingroup Process */ // The export macro should be removed. Currently, the unit // tests directly instantiate this class. class LabelSetImageIO : public mitk::AbstractFileIO { public: typedef mitk::LabelSetImage InputType; LabelSetImageIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - /** - * @brief Reads a number of mitk::LabelSetImages from the file system - * @return a vector of mitk::LabelSetImages - * @throws throws an mitk::Exception if an error ocurrs during parsing the nrrd header - */ - std::vector Read() override; + ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; // -------------- LabelSetImageIO specific functions ------------- int GetIntByKey(const itk::MetaDataDictionary &dic, const std::string &str); std::string GetStringByKey(const itk::MetaDataDictionary &dic, const std::string &str); protected: + /** + * @brief Reads a number of mitk::LabelSetImages from the file system + * @return a vector of mitk::LabelSetImages + * @throws throws an mitk::Exception if an error ocurrs during parsing the nrrd header + */ + std::vector> DoRead() override; + // Fills the m_DefaultMetaDataKeys vector with default values virtual void InitializeDefaultMetaDataKeys(); private: LabelSetImageIO *IOClone() const override; std::vector m_DefaultMetaDataKeys; }; } // end of namespace mitk #endif // __mitkLabelSetImageIO_h diff --git a/Modules/TubeGraph/include/mitkTubeGraphIO.h b/Modules/TubeGraph/include/mitkTubeGraphIO.h index 0124cbcd3b..b4a0b0afea 100644 --- a/Modules/TubeGraph/include/mitkTubeGraphIO.h +++ b/Modules/TubeGraph/include/mitkTubeGraphIO.h @@ -1,69 +1,71 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef _MITK_TUBE_GRAPH_IO_H_ #define _MITK_TUBE_GRAPH_IO_H_ #include #include #include #include "mitkTubeGraph.h" class TiXmlElement; namespace mitk { /** * @brief reader and writer for xml representations of mitk::TubeGraph * * @ingroup IO */ class TubeGraphIO : public mitk::AbstractFileIO { public: TubeGraphIO(); // -------------- AbstractFileReader ------------- using AbstractFileReader::Read; - std::vector Read() override; ConfidenceLevel GetReaderConfidenceLevel() const override; // -------------- AbstractFileWriter ------------- void Write() override; ConfidenceLevel GetWriterConfidenceLevel() const override; static CustomMimeType TUBEGRAPH_MIMETYPE() // tsf { CustomMimeType mimeType(TUBEGRAPH_MIMETYPE_NAME()); mimeType.AddExtension("tsf"); mimeType.SetCategory("Graphs"); mimeType.SetComment("MITK Tube Graph Structure File"); return mimeType; } static std::string TUBEGRAPH_MIMETYPE_NAME() { static std::string name = mitk::IOMimeTypes::DEFAULT_BASE_NAME() + ".graphs.tubular-sructure"; return name; } + protected: + std::vector> DoRead() override; + private: TubeGraphIO *IOClone() const override; TubeGraphIO(const TubeGraphIO &other); const BoundingBox::Pointer ComputeBoundingBox(TubeGraph::Pointer graph) const; }; } #endif //_MITK_SURFACE_VTK_IO_H_ diff --git a/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp b/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp index c313192ff3..9d764365d5 100644 --- a/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp +++ b/Modules/TubeGraph/src/IO/mitkTubeGraphIO.cpp @@ -1,593 +1,593 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "mitkTubeGraphIO.h" #include "mitkCircularProfileTubeElement.h" #include "mitkTubeGraphDefinitions.h" #include "mitkTubeGraphProperty.h" #include #include #include #include namespace mitk { TubeGraphIO::TubeGraphIO(const TubeGraphIO &other) : AbstractFileIO(other) {} TubeGraphIO::TubeGraphIO() : AbstractFileIO( mitk::TubeGraph::GetStaticNameOfClass(), mitk::TubeGraphIO::TUBEGRAPH_MIMETYPE(), "Tube Graph Structure File") { this->RegisterService(); } - std::vector TubeGraphIO::Read() + std::vector TubeGraphIO::DoRead() { std::locale::global(std::locale("C")); std::vector> result; InputStream stream(this); TiXmlDocument doc; stream >> doc; if (!doc.Error()) { TubeGraph::Pointer newTubeGraph = TubeGraph::New(); TiXmlHandle hDoc(&doc); TiXmlElement *pElem; TiXmlHandle hRoot(nullptr); pElem = hDoc.FirstChildElement().Element(); // save this for later hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_GEOMETRY).Element(); // read geometry mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->Initialize(); // read origin mitk::Point3D origin; double temp = 0; pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_X, &temp); origin[0] = temp; pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Y, &temp); origin[1] = temp; pElem->Attribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Z, &temp); origin[2] = temp; geometry->SetOrigin(origin); // read spacing Vector3D spacing; pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_X, &temp); spacing.SetElement(0, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_Y, &temp); spacing.SetElement(1, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_SPACING_Z, &temp); spacing.SetElement(2, temp); geometry->SetSpacing(spacing); // read transform vtkMatrix4x4 *m = vtkMatrix4x4::New(); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XX, &temp); m->SetElement(0, 0, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XY, &temp); m->SetElement(1, 0, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_XZ, &temp); m->SetElement(2, 0, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YX, &temp); m->SetElement(0, 1, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YY, &temp); m->SetElement(1, 1, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_YZ, &temp); m->SetElement(2, 1, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZX, &temp); m->SetElement(0, 2, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZY, &temp); m->SetElement(1, 2, temp); pElem->Attribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZZ, &temp); m->SetElement(2, 2, temp); m->SetElement(0, 3, origin[0]); m->SetElement(1, 3, origin[1]); m->SetElement(2, 3, origin[2]); m->SetElement(3, 3, 1); geometry->SetIndexToWorldTransformByVtkMatrix(m); geometry->SetImageGeometry(false); // read tube graph // read vertices pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_VERTICES).Element(); if (pElem != nullptr) { // walk through the vertices for (TiXmlElement *vertexElement = pElem->FirstChildElement(); vertexElement != nullptr; vertexElement = vertexElement->NextSiblingElement()) { int vertexID(0); mitk::Point3D coordinate; coordinate.Fill(0.0); double diameter(0); vertexElement->Attribute(mitk::TubeGraphDefinitions::XML_VERTEX_ID, &vertexID); TiXmlElement *tubeElement = vertexElement->FirstChildElement(); tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, &temp); coordinate[0] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, &temp); coordinate[1] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, &temp); coordinate[2] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, &diameter); mitk::TubeGraphVertex vertexData; auto *newElement = new mitk::CircularProfileTubeElement(coordinate, diameter); vertexData.SetTubeElement(newElement); mitk::TubeGraph::VertexDescriptorType newVertex = newTubeGraph->AddVertex(vertexData); if (static_cast(newVertex) != vertexID) { MITK_ERROR << "Aborting tube graph creation, different vertex ids."; return result; ; } } } // read edges pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_EDGES).Element(); if (pElem != nullptr) { // walk through the edges auto edgeElement = pElem->FirstChildElement(); for ( ; edgeElement != nullptr; edgeElement = edgeElement->NextSiblingElement()) { int edgeID(0), edgeSourceID(0), edgeTargetID(0); mitk::Point3D coordinate; double diameter(0); edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_ID, &edgeID); edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_SOURCE_ID, &edgeSourceID); edgeElement->Attribute(mitk::TubeGraphDefinitions::XML_EDGE_TARGET_ID, &edgeTargetID); mitk::TubeGraphEdge edgeData; for (TiXmlElement *tubeElement = edgeElement->FirstChildElement(mitk::TubeGraphDefinitions::XML_ELEMENT); tubeElement != nullptr; tubeElement = tubeElement->NextSiblingElement()) { tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, &temp); coordinate[0] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, &temp); coordinate[1] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, &temp); coordinate[2] = temp; tubeElement->Attribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, &diameter); auto *newElement = new mitk::CircularProfileTubeElement(coordinate, diameter); edgeData.AddTubeElement(newElement); } try { newTubeGraph->AddEdge(edgeSourceID, edgeTargetID, edgeData); } catch (const std::runtime_error &error) { MITK_ERROR << error.what(); return result; } } } // Compute bounding box BoundingBox::Pointer bb = this->ComputeBoundingBox(newTubeGraph); geometry->SetBounds(bb->GetBounds()); MITK_INFO << "Tube Graph read"; MITK_INFO << "Edge numb:" << newTubeGraph->GetNumberOfEdges() << " Vertices: " << newTubeGraph->GetNumberOfVertices(); MITK_INFO << "Reading tube graph property"; mitk::TubeGraphProperty::Pointer newProperty = mitk::TubeGraphProperty::New(); // read label groups pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_LABELGROUPS).Element(); if (pElem != nullptr) { // walk through the label groups for (TiXmlElement *labelGroupElement = pElem->FirstChildElement(); labelGroupElement != nullptr; labelGroupElement = labelGroupElement->NextSiblingElement()) { auto *newLabelGroup = new mitk::TubeGraphProperty::LabelGroup(); const char *labelGroupName; labelGroupName = labelGroupElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME.c_str()); if (labelGroupName) newLabelGroup->labelGroupName = labelGroupName; for (TiXmlElement *labelElement = labelGroupElement->FirstChildElement(mitk::TubeGraphDefinitions::XML_LABEL); labelElement != nullptr; labelElement = labelElement->NextSiblingElement()) { auto *newLabel = new mitk::TubeGraphProperty::LabelGroup::Label(); const char *labelName; bool isVisible = true; Color color; labelName = labelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABEL_NAME.c_str()); if (labelName) newLabel->labelName = labelName; labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_VISIBILITY, &temp); if (temp == 0) isVisible = false; else isVisible = true; labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_R, &temp); color[0] = temp; labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_G, &temp); color[1] = temp; labelElement->Attribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_B, &temp); color[2] = temp; newLabel->isVisible = isVisible; newLabel->labelColor = color; newLabelGroup->labels.push_back(newLabel); } newProperty->AddLabelGroup(newLabelGroup, newProperty->GetLabelGroups().size()); } } // read attributations pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTIONS).Element(); if (pElem != nullptr) { std::map tubeToLabelsMap; for (TiXmlElement *tubeToLabelElement = pElem->FirstChildElement(); tubeToLabelElement != nullptr; tubeToLabelElement = tubeToLabelElement->NextSiblingElement()) { TubeGraph::TubeDescriptorType tube; auto *labelGroup = new mitk::TubeGraphProperty::LabelGroup(); auto *label = new mitk::TubeGraphProperty::LabelGroup::Label(); tubeToLabelElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, &temp); tube.first = temp; tubeToLabelElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, &temp); tube.second = temp; const char *labelGroupName = tubeToLabelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME.c_str()); if (labelGroupName) labelGroup = newProperty->GetLabelGroupByName(labelGroupName); const char *labelName = tubeToLabelElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_LABEL_NAME.c_str()); if (labelName) label = newProperty->GetLabelByName(labelGroup, labelName); if (tube != TubeGraph::ErrorId && labelGroup != nullptr && label != nullptr) { TubeGraphProperty::TubeToLabelGroupType tubeToLabelGroup(tube, labelGroupName); tubeToLabelsMap.insert( std::pair(tubeToLabelGroup, labelName)); } } if (tubeToLabelsMap.size() > 0) newProperty->SetTubesToLabels(tubeToLabelsMap); } // read annotations pElem = hRoot.FirstChildElement(mitk::TubeGraphDefinitions::XML_ANNOTATIONS).Element(); if (pElem != nullptr) { for (TiXmlElement *annotationElement = pElem->FirstChildElement(); annotationElement != nullptr; annotationElement = annotationElement->NextSiblingElement()) { auto *annotation = new mitk::TubeGraphProperty::Annotation(); std::string annotationName; std::string annotationDescription; TubeGraph::TubeDescriptorType tube; annotationName = annotationElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_ANNOTATION_NAME.c_str()); annotation->name = annotationName; annotationDescription = annotationElement->Attribute((char *)mitk::TubeGraphDefinitions::XML_ANNOTATION_DESCRIPTION.c_str()); annotation->description = annotationDescription; annotationElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, &temp); tube.first = temp; annotationElement->Attribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, &temp); tube.second = temp; if (tube != TubeGraph::ErrorId) { annotation->tube = tube; newProperty->AddAnnotation(annotation); } } } MITK_INFO << "Tube Graph Property read"; newTubeGraph->SetGeometry(geometry); newTubeGraph->SetProperty("Tube Graph.Visualization Information", newProperty); result.push_back(newTubeGraph.GetPointer()); } else { mitkThrow() << "Parsing error at line " << doc.ErrorRow() << ", col " << doc.ErrorCol() << ": " << doc.ErrorDesc(); } return result; } AbstractFileIO::ConfidenceLevel TubeGraphIO::GetReaderConfidenceLevel() const { if (AbstractFileIO::GetReaderConfidenceLevel() == Unsupported) return Unsupported; return Supported; } void TubeGraphIO::Write() { OutputStream out(this); if (!out.good()) { mitkThrow() << "Stream not good."; } std::locale previousLocale(out.getloc()); std::locale I("C"); out.imbue(I); const auto *tubeGraph = dynamic_cast(this->GetInput()); // Get geometry of the tube graph mitk::Geometry3D::Pointer geometry = dynamic_cast(tubeGraph->GetGeometry()); // Get property of the tube graph mitk::TubeGraphProperty::Pointer tubeGraphProperty = dynamic_cast( tubeGraph->GetProperty("Tube Graph.Visualization Information").GetPointer()); // Create XML document TiXmlDocument documentXML; { // Begin document auto *declXML = new TiXmlDeclaration("1.0", "", ""); documentXML.LinkEndChild(declXML); auto *mainXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_TUBEGRAPH_FILE); mainXML->SetAttribute(mitk::TubeGraphDefinitions::XML_FILE_VERSION, mitk::TubeGraphDefinitions::VERSION_STRING); documentXML.LinkEndChild(mainXML); auto *geometryXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_GEOMETRY); { // begin geometry geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XX, geometry->GetMatrixColumn(0)[0]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XY, geometry->GetMatrixColumn(0)[1]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_XZ, geometry->GetMatrixColumn(0)[2]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YX, geometry->GetMatrixColumn(1)[0]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YY, geometry->GetMatrixColumn(1)[1]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_YZ, geometry->GetMatrixColumn(1)[2]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZX, geometry->GetMatrixColumn(2)[0]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZY, geometry->GetMatrixColumn(2)[1]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_MATRIX_ZZ, geometry->GetMatrixColumn(2)[2]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_X, geometry->GetOrigin()[0]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Y, geometry->GetOrigin()[1]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ORIGIN_Z, geometry->GetOrigin()[2]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_X, geometry->GetSpacing()[0]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_Y, geometry->GetSpacing()[1]); geometryXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_SPACING_Z, geometry->GetSpacing()[2]); } // end geometry mainXML->LinkEndChild(geometryXML); auto *verticesXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_VERTICES); { // begin vertices section std::vector vertexVector = tubeGraph->GetVectorOfAllVertices(); for (unsigned int index = 0; index < vertexVector.size(); index++) { auto *vertexXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_VERTEX); vertexXML->SetAttribute(mitk::TubeGraphDefinitions::XML_VERTEX_ID, tubeGraph->GetVertexDescriptor(vertexVector[index])); // element of each vertex const mitk::TubeElement *element = vertexVector[index].GetTubeElement(); auto *elementXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ELEMENT); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, element->GetCoordinates().GetElement(0)); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, element->GetCoordinates().GetElement(1)); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, element->GetCoordinates().GetElement(2)); if (dynamic_cast(element)) elementXML->SetDoubleAttribute( mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, (dynamic_cast(element))->GetDiameter()); else elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, 2); vertexXML->LinkEndChild(elementXML); verticesXML->LinkEndChild(vertexXML); } } // end vertices section mainXML->LinkEndChild(verticesXML); auto *edgesXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_EDGES); { // begin edges section std::vector edgeVector = tubeGraph->GetVectorOfAllEdges(); for (unsigned int index = 0; index < edgeVector.size(); index++) { auto *edgeXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_EDGE); edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_ID, index); std::pair soureTargetPair = tubeGraph->GetVerticesOfAnEdge(tubeGraph->GetEdgeDescriptor(edgeVector[index])); edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_SOURCE_ID, tubeGraph->GetVertexDescriptor(soureTargetPair.first)); edgeXML->SetAttribute(mitk::TubeGraphDefinitions::XML_EDGE_TARGET_ID, tubeGraph->GetVertexDescriptor(soureTargetPair.second)); // begin elements of the edge std::vector elementVector = edgeVector[index].GetElementVector(); for (unsigned int elementIndex = 0; elementIndex < elementVector.size(); elementIndex++) { auto *elementXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ELEMENT); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_X, elementVector[elementIndex]->GetCoordinates().GetElement(0)); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Y, elementVector[elementIndex]->GetCoordinates().GetElement(1)); elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_Z, elementVector[elementIndex]->GetCoordinates().GetElement(2)); if (dynamic_cast(elementVector[elementIndex])) elementXML->SetDoubleAttribute( mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, (dynamic_cast(elementVector[elementIndex]))->GetDiameter()); else elementXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_ELEMENT_DIAMETER, 2); edgeXML->LinkEndChild(elementXML); // elementsXML->LinkEndChild(elementXML); } edgesXML->LinkEndChild(edgeXML); } } // end edges section mainXML->LinkEndChild(edgesXML); auto *labelGroupsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABELGROUPS); { // begin label group section std::vector labelGroupVector = tubeGraphProperty->GetLabelGroups(); for (unsigned int index = 0; index < labelGroupVector.size(); index++) { auto *labelGroupXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABELGROUP); labelGroupXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME, labelGroupVector[index]->labelGroupName); // begin labels of the label group std::vector labelVector = labelGroupVector[index]->labels; for (unsigned int labelIndex = 0; labelIndex < labelVector.size(); labelIndex++) { auto *labelXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_LABEL); labelXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_NAME, labelVector[labelIndex]->labelName); labelXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_VISIBILITY, labelVector[labelIndex]->isVisible); labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_R, labelVector[labelIndex]->labelColor[0]); labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_G, labelVector[labelIndex]->labelColor[1]); labelXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_LABEL_COLOR_B, labelVector[labelIndex]->labelColor[2]); labelGroupXML->LinkEndChild(labelXML); } labelGroupsXML->LinkEndChild(labelGroupXML); } } // end labe group section mainXML->LinkEndChild(labelGroupsXML); auto *attributionsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTIONS); { // begin attributions section std::map tubeToLabelGroup = tubeGraphProperty->GetTubesToLabels(); for (auto it = tubeToLabelGroup.begin(); it != tubeToLabelGroup.end(); it++) { auto *attributXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ATTRIBUTION); attributXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, it->first.first.first); attributXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, it->first.first.second); attributXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABELGROUP_NAME, it->first.second); attributXML->SetAttribute(mitk::TubeGraphDefinitions::XML_LABEL_NAME, it->second); attributionsXML->LinkEndChild(attributXML); } } // end attributions section mainXML->LinkEndChild(attributionsXML); auto *annotationsXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ANNOTATIONS); { // begin annotations section std::vector annotations = tubeGraphProperty->GetAnnotations(); for (unsigned int index = 0; index < annotations.size(); index++) { auto *annotationXML = new TiXmlElement(mitk::TubeGraphDefinitions::XML_ANNOTATION); annotationXML->SetAttribute(mitk::TubeGraphDefinitions::XML_ANNOTATION_NAME, annotations[index]->name); annotationXML->SetAttribute(mitk::TubeGraphDefinitions::XML_ANNOTATION_DESCRIPTION, annotations[index]->description); annotationXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_1, annotations[index]->tube.first); annotationXML->SetDoubleAttribute(mitk::TubeGraphDefinitions::XML_TUBE_ID_2, annotations[index]->tube.second); annotationsXML->LinkEndChild(annotationXML); } } // end annotations section mainXML->LinkEndChild(annotationsXML); } // end document TiXmlPrinter printer; printer.SetStreamPrinting(); documentXML.Accept(&printer); out << printer.Str(); } AbstractFileIO::ConfidenceLevel TubeGraphIO::GetWriterConfidenceLevel() const { if (AbstractFileIO::GetWriterConfidenceLevel() == Unsupported) return Unsupported; return Supported; } TubeGraphIO *TubeGraphIO::IOClone() const { return new TubeGraphIO(*this); } } const mitk::BoundingBox::Pointer mitk::TubeGraphIO::ComputeBoundingBox(mitk::TubeGraph::Pointer graph) const { BoundingBox::Pointer boundingBox = BoundingBox::New(); BoundingBox::PointIdentifier pointid = 0; BoundingBox::PointsContainer::Pointer pointscontainer = BoundingBox::PointsContainer::New(); ScalarType nullpoint[] = {0, 0, 0}; BoundingBox::PointType p(nullpoint); // traverse the tree and add each point to the pointscontainer mitk::Point3D pos; std::vector vertexVector = graph->GetVectorOfAllVertices(); for (auto vertex = vertexVector.begin(); vertex != vertexVector.end(); ++vertex) { pos = vertex->GetTubeElement()->GetCoordinates(); p[0] = pos[0]; p[1] = pos[1]; p[2] = pos[2]; pointscontainer->InsertElement(pointid++, p); } std::vector edgeVector = graph->GetVectorOfAllEdges(); for (auto edge = edgeVector.begin(); edge != edgeVector.end(); ++edge) { std::vector allElements = edge->GetElementVector(); for (unsigned int index = 0; index < edge->GetNumberOfElements(); index++) { pos = allElements[index]->GetCoordinates(); p[0] = pos[0]; p[1] = pos[1]; p[2] = pos[2]; pointscontainer->InsertElement(pointid++, p); } } boundingBox->SetPoints(pointscontainer); boundingBox->ComputeBoundingBox(); return boundingBox; } diff --git a/Modules/US/USModel/mitkUSDeviceReaderXML.cpp b/Modules/US/USModel/mitkUSDeviceReaderXML.cpp index 4295678f0e..250b7af835 100644 --- a/Modules/US/USModel/mitkUSDeviceReaderXML.cpp +++ b/Modules/US/USModel/mitkUSDeviceReaderXML.cpp @@ -1,204 +1,204 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ // MITK #include "mitkUSDeviceReaderWriterConstants.h" #include "mitkUSDeviceReaderXML.h" #include #include #include // Third Party #include #include #include mitk::USDeviceReaderXML::USDeviceReaderXML() : AbstractFileReader( mitk::IGTMimeTypes::USDEVICEINFORMATIONXML_MIMETYPE(), "MITK USDevice Reader (XML)"), m_Filename("") { RegisterService(); } mitk::USDeviceReaderXML::~USDeviceReaderXML() { } mitk::USDeviceReaderXML::USDeviceConfigData &mitk::USDeviceReaderXML::GetUSDeviceConfigData() { return m_DeviceConfig; } mitk::USDeviceReaderXML::USDeviceReaderXML(const mitk::USDeviceReaderXML& other) : AbstractFileReader(other) { } mitk::USDeviceReaderXML* mitk::USDeviceReaderXML::Clone() const { return new USDeviceReaderXML(*this); } -std::vector> mitk::USDeviceReaderXML::Read() +std::vector> mitk::USDeviceReaderXML::DoRead() { MITK_WARN << "This method is not implemented. \ Please use the method ReadUltrasoundDeviceConfiguration() instead."; std::vector result; return result; } bool mitk::USDeviceReaderXML::ReadUltrasoundDeviceConfiguration() { MITK_INFO << "Try to start reading xml device configuration..."; if (m_Filename == "") { MITK_WARN << "Cannot read file - empty filename!"; return false; } TiXmlDocument document(m_Filename); if (!document.LoadFile()) { MITK_ERROR << "Error when opening and reading file :" << m_Filename; return false; } TiXmlHandle documentHandle(&document); TiXmlElement* ultrasoundDeviceTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).ToElement(); if (ultrasoundDeviceTag == nullptr) { MITK_ERROR << "Error parsing the file :" << m_Filename << std::endl << "Wrong xml format structure."; return false; } //Extract attribute information of the ULTRASOUNDDEVICE-Tag: this->ExtractAttributeInformationOfUltrasoundDeviceTag(ultrasoundDeviceTag); TiXmlElement* generalSettingsTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).FirstChildElement(TAG_GENERALSETTINGS).ToElement(); if (generalSettingsTag == nullptr) { MITK_ERROR << "Error parsing the GENERALSETTINGS-Tag in the file :" << m_Filename; return false; } //Extract attribute information of the GENERALSETTINGS-Tag: this->ExtractAttributeInformationOfGeneralSettingsTag(generalSettingsTag); TiXmlElement* probesTag = documentHandle.FirstChildElement(TAG_ULTRASOUNDDEVICE).FirstChildElement(TAG_PROBES).ToElement(); if (probesTag == nullptr) { MITK_ERROR << "Error: PROBES-Tag was not found in the file :" << m_Filename << "Therefore, creating default probe."; //Create default ultrasound probe: mitk::USProbe::Pointer ultrasoundProbeDefault = mitk::USProbe::New(); ultrasoundProbeDefault->SetName("default"); ultrasoundProbeDefault->SetDepth(0); m_DeviceConfig.probes.push_back(ultrasoundProbeDefault); return true; } //Extract all saved and configured probes of the USDevice: for (TiXmlElement* probeTag = probesTag->FirstChildElement(TAG_PROBE); probeTag != nullptr; probeTag = probeTag->NextSiblingElement()) { this->ExtractProbe(probeTag); } return true; } void mitk::USDeviceReaderXML::SetFilename(std::string filename) { m_Filename = filename; } void mitk::USDeviceReaderXML::ExtractAttributeInformationOfUltrasoundDeviceTag(TiXmlElement *ultrasoundTag) { ultrasoundTag->QueryDoubleAttribute(ATTR_FILEVERS, &m_DeviceConfig.fileversion); ultrasoundTag->QueryStringAttribute(ATTR_TYPE, &m_DeviceConfig.deviceType); ultrasoundTag->QueryStringAttribute(ATTR_NAME, &m_DeviceConfig.deviceName); ultrasoundTag->QueryStringAttribute(ATTR_MANUFACTURER, &m_DeviceConfig.manufacturer); ultrasoundTag->QueryStringAttribute(ATTR_MODEL, &m_DeviceConfig.model); ultrasoundTag->QueryStringAttribute(ATTR_COMMENT, &m_DeviceConfig.comment); ultrasoundTag->QueryIntAttribute(ATTR_IMAGESTREAMS, &m_DeviceConfig.numberOfImageStreams); ultrasoundTag->QueryStringAttribute(ATTR_HOST, &m_DeviceConfig.host); ultrasoundTag->QueryIntAttribute(ATTR_PORT, &m_DeviceConfig.port); ultrasoundTag->QueryBoolAttribute(ATTR_SERVER, &m_DeviceConfig.server); } void mitk::USDeviceReaderXML::ExtractAttributeInformationOfGeneralSettingsTag(TiXmlElement *generalSettingsTag) { generalSettingsTag->QueryBoolAttribute(ATTR_GREYSCALE, &m_DeviceConfig.useGreyscale); generalSettingsTag->QueryBoolAttribute(ATTR_RESOLUTIONOVERRIDE, &m_DeviceConfig.useResolutionOverride); generalSettingsTag->QueryIntAttribute(ATTR_RESOLUTIONHEIGHT, &m_DeviceConfig.resolutionHeight); generalSettingsTag->QueryIntAttribute(ATTR_RESOLUTIONWIDTH, &m_DeviceConfig.resolutionWidth); generalSettingsTag->QueryIntAttribute(ATTR_SOURCEID, &m_DeviceConfig.sourceID); generalSettingsTag->QueryStringAttribute(ATTR_FILEPATH, &m_DeviceConfig.filepathVideoSource); generalSettingsTag->QueryIntAttribute(ATTR_OPENCVPORT, &m_DeviceConfig.opencvPort); } void mitk::USDeviceReaderXML::ExtractProbe(TiXmlElement *probeTag) { mitk::USProbe::Pointer ultrasoundProbe = mitk::USProbe::New(); std::string probeName; probeTag->QueryStringAttribute(ATTR_NAME, &probeName); ultrasoundProbe->SetName(probeName); TiXmlElement* depthsTag = probeTag->FirstChildElement(TAG_DEPTHS); if (depthsTag != nullptr) { for (TiXmlElement* depthTag = depthsTag->FirstChildElement(TAG_DEPTH); depthTag != nullptr; depthTag = depthTag->NextSiblingElement()) { int depth = 0; mitk::Vector3D spacing; spacing[0] = 1; spacing[1] = 1; spacing[2] = 1; depthTag->QueryIntAttribute(ATTR_DEPTH, &depth); TiXmlElement* spacingTag = depthTag->FirstChildElement(TAG_SPACING); if (spacingTag != nullptr) { spacingTag->QueryDoubleAttribute(ATTR_X, &spacing[0]); spacingTag->QueryDoubleAttribute(ATTR_Y, &spacing[1]); } ultrasoundProbe->SetDepthAndSpacing(depth, spacing); } } else { MITK_ERROR << "Error: DEPTHS-Tag was not found in the file :" << m_Filename << "Therefore, creating default depth [0] and spacing [1,1,1] for the probe."; ultrasoundProbe->SetDepth(0); } unsigned int croppingTop = 0; unsigned int croppingBottom = 0; unsigned int croppingLeft = 0; unsigned int croppingRight = 0; TiXmlElement* croppingTag = probeTag->FirstChildElement(TAG_CROPPING); if (croppingTag != nullptr) { croppingTag->QueryUnsignedAttribute(ATTR_TOP, &croppingTop); croppingTag->QueryUnsignedAttribute(ATTR_BOTTOM, &croppingBottom); croppingTag->QueryUnsignedAttribute(ATTR_LEFT, &croppingLeft); croppingTag->QueryUnsignedAttribute(ATTR_RIGHT, &croppingRight); } ultrasoundProbe->SetProbeCropping(croppingTop, croppingBottom, croppingLeft, croppingRight); m_DeviceConfig.probes.push_back(ultrasoundProbe); } diff --git a/Modules/US/USModel/mitkUSDeviceReaderXML.h b/Modules/US/USModel/mitkUSDeviceReaderXML.h index 74d3d76b9f..a81663d7c2 100644 --- a/Modules/US/USModel/mitkUSDeviceReaderXML.h +++ b/Modules/US/USModel/mitkUSDeviceReaderXML.h @@ -1,101 +1,103 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef mitkUSDeviceReaderXML_H_HEADER_INCLUDED_ #define mitkUSDeviceReaderXML_H_HEADER_INCLUDED_ #include #include #include class TiXmlElement; class TiXmlNode; namespace mitk { class MITKUS_EXPORT USDeviceReaderXML : public AbstractFileReader { public: USDeviceReaderXML(); ~USDeviceReaderXML() override; using AbstractFileReader::Read; - std::vector> Read() override; + bool ReadUltrasoundDeviceConfiguration(); void SetFilename(std::string filename); typedef struct USDeviceConfigData_ { double fileversion; std::string deviceType; std::string deviceName; std::string manufacturer; std::string model; std::string comment; std::string host; int port; bool server; int numberOfImageStreams; bool useGreyscale; bool useResolutionOverride; int resolutionWidth; int resolutionHeight; int sourceID; std::string filepathVideoSource; int opencvPort; std::vector probes; USDeviceConfigData_() : fileversion(0), deviceType("Unknown"), deviceName("Unknown"), manufacturer("Unknown"), comment(""), host("localhost"), port(18944), server(false), numberOfImageStreams(1), useGreyscale(true), useResolutionOverride(true), resolutionWidth(640), resolutionHeight(480), sourceID(0), filepathVideoSource(""), opencvPort(0) { }; }USDeviceConfigData; USDeviceConfigData &GetUSDeviceConfigData(); protected: + std::vector> DoRead() override; + USDeviceReaderXML(const USDeviceReaderXML& other); mitk::USDeviceReaderXML* Clone() const override; /** * \brief Extracts all stored attribute information of the ULTRASOUNDDEVICE-Tag. */ void ExtractAttributeInformationOfUltrasoundDeviceTag(TiXmlElement *element); /** * \brief Extracts all stored attribute information of the GENERALSETTINGS-Tag. */ void ExtractAttributeInformationOfGeneralSettingsTag(TiXmlElement *element); /** * \brief Extracts all stored information of a single ultrasound probe. */ void ExtractProbe(TiXmlElement *element); private: std::string m_Filename; USDeviceConfigData m_DeviceConfig; }; } // namespace mitk #endif // mitkUSDeviceReaderXML_H_HEADER_INCLUDED_