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..849b4f181e 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..9ddfe1f048 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/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/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/src/IO/mitkAbstractFileReader.cpp b/Modules/Core/src/IO/mitkAbstractFileReader.cpp index 05d7b1b837..1dcf0a3d45 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(IOMetaInformationPropertyConsants::READER_DESCRIPTION()), StringProperty::New(d->GetDescription())); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConsants::READER_VERSION()), StringProperty::New(MITK_VERSION_STRING)); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConsants::READER_MIME_NAME()), StringProperty::New(d->GetMimeType()->GetName())); + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConsants::READER_MIME_CATEGORY()), StringProperty::New(d->GetMimeType()->GetCategory())); + if (this->GetInputStream() == nullptr) + { + data->SetProperty(PropertyKeyPathToPropertyName(IOMetaInformationPropertyConsants::READER_INPUTLOCATION()), StringProperty::New(this->GetInputLocation())); + } + + for (const auto& option : options) + { + auto optionpath = IOMetaInformationPropertyConsants::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/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..b268ec5f59 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..103e3cb3f1 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..571cb18e09 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..e7ef8bc040 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..6d02b70802 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..4d1a6f0667 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..a236da6d4f 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/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/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/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..81245c97b3 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 maps from the file system + * @return a mitk::Image + * @throws 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/include/mitkBaseDICOMReaderService.h b/Modules/DICOMReader/include/mitkBaseDICOMReaderService.h index 1acff14ce9..e626b7da5a 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/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..78ffd50c10 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..593e55bb49 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..05fc2870b3 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..944fefde13 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..9dba6a5e6e 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..517cf1004d 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..8a64d4b476 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..3ad622320d 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..eec3bfec06 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..d299472e92 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/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..71ef45b36e 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..4e2ac697fe 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..5406974c3e 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; }