From c494cff67f2765a1547af6f6683ee6ab20cd9e3a Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Tue, 28 Apr 2026 07:24:31 -0500 Subject: [PATCH] ENH: Migrate MGHIO content to ITK main; archive this repo The MGHIO module was ingested into the main ITK source tree on 2026-04-28 via InsightSoftwareConsortium/ITK#6137 (merge commit 2e61183c46). Per the ITK ingestion strategy (Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md), the one-definition rule requires that any file now living at Modules/IO/MGHIO/ in ITK no longer live at this upstream repo's tree tip. This commit: - Removes the whitelisted files that transferred during ingest: include/, src/, test/, wrapping/, CMakeLists.txt, itk-module.cmake, CTestConfig.cmake. - Adds MIGRATION_README.md at the repo root pointing users at the authoritative in-tree ITK location and linking the ingest PR. - Leaves the pre-ingest history intact so blame, paper material, and historical references remain reachable. After this PR merges, this repository will be marked ARCHIVED via GitHub's repository settings (Danger Zone -> Archive this repository), making it read-only. Cloning ITK main gets the authoritative MGHIO module under Modules/IO/MGHIO/. Cloning this repo after archival gets only the MIGRATION_README pointer plus everything that was deliberately not migrated. --- CMakeLists.txt | 15 - CTestConfig.cmake | 7 - MIGRATION_README.md | 18 + include/itkMGHImageIO.h | 160 ------- include/itkMGHImageIOFactory.h | 74 --- itk-module.cmake | 17 - src/CMakeLists.txt | 6 - src/itkMGHImageIO.cxx | 809 -------------------------------- src/itkMGHImageIOFactory.cxx | 64 --- test/CMakeLists.txt | 40 -- test/MD5/T1.mgz.cid | 1 - test/MD5/T1_longname.mgh.gz.cid | 1 - test/MD5/T1_uncompresed.mgh.cid | 1 - test/itkMGHImageIOTest.cxx | 154 ------ test/itkMGHImageIOTest.h | 314 ------------- wrapping/CMakeLists.txt | 3 - wrapping/itkMGHImageIO.wrap | 2 - 17 files changed, 18 insertions(+), 1668 deletions(-) delete mode 100644 CMakeLists.txt delete mode 100644 CTestConfig.cmake create mode 100644 MIGRATION_README.md delete mode 100644 include/itkMGHImageIO.h delete mode 100644 include/itkMGHImageIOFactory.h delete mode 100644 itk-module.cmake delete mode 100644 src/CMakeLists.txt delete mode 100644 src/itkMGHImageIO.cxx delete mode 100644 src/itkMGHImageIOFactory.cxx delete mode 100644 test/CMakeLists.txt delete mode 100644 test/MD5/T1.mgz.cid delete mode 100644 test/MD5/T1_longname.mgh.gz.cid delete mode 100644 test/MD5/T1_uncompresed.mgh.cid delete mode 100644 test/itkMGHImageIOTest.cxx delete mode 100644 test/itkMGHImageIOTest.h delete mode 100644 wrapping/CMakeLists.txt delete mode 100644 wrapping/itkMGHImageIO.wrap diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index f9cda3e..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.10.2) - -project(MGHIO - VERSION 5.1.0 #Version should track with ITK - LANGUAGES CXX C) - -set(MGHIO_LIBRARIES MGHIO) - -if(NOT ITK_SOURCE_DIR) - find_package(ITK REQUIRED) - list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR}) - include(ITKModuleExternal) -else() - itk_module_impl() -endif() diff --git a/CTestConfig.cmake b/CTestConfig.cmake deleted file mode 100644 index efccad4..0000000 --- a/CTestConfig.cmake +++ /dev/null @@ -1,7 +0,0 @@ -set(CTEST_PROJECT_NAME "ITK") -set(CTEST_NIGHTLY_START_TIME "1:00:00 UTC") - -set(CTEST_DROP_METHOD "https") -set(CTEST_DROP_SITE "open.cdash.org") -set(CTEST_DROP_LOCATION "/submit.php?project=Insight") -set(CTEST_DROP_SITE_CDASH TRUE) diff --git a/MIGRATION_README.md b/MIGRATION_README.md new file mode 100644 index 0000000..a09c4ce --- /dev/null +++ b/MIGRATION_README.md @@ -0,0 +1,18 @@ +# Migrated to ITK main + +As of 2026-04-28, the `MGHIO` module has been ingested into the main +ITK source tree. The authoritative location is: + + https://github.com/InsightSoftwareConsortium/ITK/tree/main/Modules/IO/MGHIO + +See `Modules/IO/MGHIO/README.md` in the ITK tree for details on what +moved and what remains in this archived repo. + +This repository is retained read-only for historical reference (deep +git history, paper material, example assets not migrated to ITK). It +will be marked ARCHIVED after this PR merges. + +Related: +- ITK ingest PR: InsightSoftwareConsortium/ITK#6137 +- ITK ingest merge commit: InsightSoftwareConsortium/ITK@2e61183c46 +- Consolidation issue: InsightSoftwareConsortium/ITK#6060 diff --git a/include/itkMGHImageIO.h b/include/itkMGHImageIO.h deleted file mode 100644 index a3b3497..0000000 --- a/include/itkMGHImageIO.h +++ /dev/null @@ -1,160 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#ifndef itkMGHImageIO_h -#define itkMGHImageIO_h - -#include "itkMatrix.h" -#include "itkImageIOBase.h" -#include -#include "itk_zlib.h" - -#include "MGHIOExport.h" - -namespace itk -{ -/** \class MGHImageIO - * - * \author Hans J. Johnson - * \brief Class that defines how to read MGH file format. - * Originally developed as part of the Slicer software - * package under grants XXXX - * - * \ingroup IOFilters - * \ingroup MGHIO - */ -class MGHIO_EXPORT MGHImageIO : public ImageIOBase -{ -public: - /** Standard class type alias. */ - using Self = MGHImageIO; - using Superclass = ImageIOBase; - using Pointer = SmartPointer; - - /** Method for creation through the object factory. */ - itkNewMacro(Self); - - /** Run-time type information (and related methods). */ - itkOverrideGetNameOfClassMacro(MGHImageIO); - - /*-------- This part of the interfaces deals with reading data. ----- */ - - /** Determine if the file can be read with this ImageIO implementation. - * \param FileNameToRead The name of the file to test for reading. - * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite - * \return Returns true if this ImageIO can read the file specified. - */ - bool - CanReadFile(const char * FileNameToRead) override; - - /** Set the spacing and dimension information for the set filename. */ - void - ReadImageInformation() override; - - /** Reads the data from disk into the memory buffer provided. */ - void - Read(void * pData) override; - - /*-------- This part of the interfaces deals with writing data. ----- */ - - /** Determine if the file can be written with this ImageIO implementation. - * \param FileNameToWrite The name of the file to test for writing. - * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite - * \return Returns true if this ImageIO can write the file specified. - */ - bool - CanWriteFile(const char * name) override; - - /** Set the spacing and dimension information for the set filename. */ - void - WriteImageInformation() override; - - /** Writes the data to disk from the memory buffer provided. Make sure - * that the IORegions has been set properly. */ - void - Write(const void * buffer) override; - -protected: - MGHImageIO(); - ~MGHImageIO() override; - void - PrintSelf(std::ostream & os, Indent indent) const override; - - void - ReadVolumeHeader(); - -private: - static const int MRI_UCHAR = 0; - static const int MRI_INT = 1; - static const int MRI_FLOAT = 3; - static const int MRI_SHORT = 4; - static const int MRI_TENSOR = 6; - static const unsigned int FS_DIMENSION_HEADER_SIZE = sizeof(int) * 7; - static const unsigned int FS_RAS_HEADER_SIZE = (sizeof(float) * 15) + sizeof(short); - static const unsigned int FS_UNUSED_HEADER_SIZE = 256 - FS_RAS_HEADER_SIZE; - static const unsigned int FS_WHOLE_HEADER_SIZE = - FS_RAS_HEADER_SIZE + FS_DIMENSION_HEADER_SIZE + FS_UNUSED_HEADER_SIZE; - - /** check if a filename is for a compressed file */ - bool - IsCompressedFilename(const std::string fname); - /// processes the actual data buffer - void - SwapBytesIfNecessary(void * const buffer, const unsigned long numberOfPixels); - - /// examines the direction cosines and creates encapsulation data - // void MriDirCos(); - - void - WriteHeader(); - - void - WriteData(const void * buffer); - - void - PermuteFrameValues(const void * buffer, char * tempmemory); - - unsigned int - GetComponentSize() const override; - - std::string - GetOrientation(itk::Matrix directions); - - bool m_IsCompressed; - gzFile m_GZFile; - std::ofstream m_Output; - - // Utility function to assist with writing to disk in the - // proper format. TInType is static_cast type. - template - int - TWrite(const TInType inValue); - template - int - TRead(TOutType & outValue); - - int - TWrite(const char * buf, const unsigned long count); - void - OpenFile(); - void - CloseFile(); -}; -} // end namespace itk - -#endif // itkMGHImageIO_h diff --git a/include/itkMGHImageIOFactory.h b/include/itkMGHImageIOFactory.h deleted file mode 100644 index b9b3e28..0000000 --- a/include/itkMGHImageIOFactory.h +++ /dev/null @@ -1,74 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#ifndef itkMGHImageIOFactory_h -#define itkMGHImageIOFactory_h - -#include "itkObjectFactoryBase.h" -#include "itkImageIOBase.h" - -#include "MGHIOExport.h" - -namespace itk -{ -/** \class MGHImageIOFactory - * \brief Create instances of MGHImageIO objects using an object factory. - * \ingroup MGHIO - */ -class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase -{ -public: - ITK_DISALLOW_COPY_AND_MOVE(MGHImageIOFactory); - - /** Standard class type alias */ - using Self = MGHImageIOFactory; - using Superclass = ObjectFactoryBase; - using Pointer = SmartPointer; - using ConstPointer = SmartPointer; - - /** Class methods used to interface with the registered factories **/ - const char * - GetITKSourceVersion() const override; - - const char * - GetDescription() const override; - - /** Method for class instantiation **/ - itkFactorylessNewMacro(Self); - - /** Run-time type information (and related methods). */ - itkOverrideGetNameOfClassMacro(MGHImageIOFactory); - - /** Register one factory of this type */ - static void - RegisterOneFactory() - { - MGHImageIOFactory::Pointer MGHFactory = MGHImageIOFactory::New(); - - ObjectFactoryBase::RegisterFactoryInternal(MGHFactory); - } - -protected: - MGHImageIOFactory(); - ~MGHImageIOFactory() override; - void - PrintSelf(std::ostream & os, Indent indent) const override; -}; -} // end namespace itk - -#endif /// itkMGHImageIOFactory_h diff --git a/itk-module.cmake b/itk-module.cmake deleted file mode 100644 index 91be1e6..0000000 --- a/itk-module.cmake +++ /dev/null @@ -1,17 +0,0 @@ -set(DOCUMENTATION "This modules contains an ImageIO class to read or write the - MGH file format that is an integral part of FreeSurfer based tools.") - -itk_module(MGHIO - ENABLE_SHARED - DEPENDS - ITKIOImageBase - ITKZLIB - TEST_DEPENDS - ITKTestKernel - ITKTransform - EXCLUDE_FROM_DEFAULT - FACTORY_NAMES - ImageIO::MGH - DESCRIPTION - "${DOCUMENTATION}" -) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt deleted file mode 100644 index 772c626..0000000 --- a/src/CMakeLists.txt +++ /dev/null @@ -1,6 +0,0 @@ -set(MGHIO_SRC -itkMGHImageIOFactory.cxx -itkMGHImageIO.cxx -) - -itk_module_add_library(MGHIO ${MGHIO_SRC}) diff --git a/src/itkMGHImageIO.cxx b/src/itkMGHImageIO.cxx deleted file mode 100644 index 0180f47..0000000 --- a/src/itkMGHImageIO.cxx +++ /dev/null @@ -1,809 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#include "itkMGHImageIO.h" -#include "itkByteSwapper.h" -#include "itkMetaDataObject.h" -#include "itksys/SystemTools.hxx" - -namespace itk -{ - -// VALID file extensions -static const std::string __MGH_EXT(".mgh"); -static const std::string __MGZ_EXT(".mgz"); -static const std::string __GZ_EXT(".gz"); - -using MatrixType = itk::Matrix; -using VectorType = itk::Vector; - -static MatrixType -GetRAS2LPS() -{ - MatrixType RAS2LAS; - RAS2LAS.SetIdentity(); - RAS2LAS[0][0] = -1.0; - RAS2LAS[1][1] = -1.0; - RAS2LAS[2][2] = 1.0; - return RAS2LAS; -} - -// ------------------------------- -// -// Convert to BE -// -// ------------------------------- - -template -int -MGHImageIO ::TRead(TOutType & outValue) -{ - TDiskType onDiskValue; - const int result = ::gzread(this->m_GZFile, &onDiskValue, sizeof(TDiskType)); - itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); - outValue = static_cast(onDiskValue); - return result; -} - -template -int -MGHImageIO ::TWrite(const TInType inValue) -{ - auto onDiskValue = static_cast(inValue); - itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); - if (this->m_IsCompressed) - { - return ::gzwrite(this->m_GZFile, &onDiskValue, sizeof(TDiskType)); - } - else - { - this->m_Output.write(reinterpret_cast(&onDiskValue), sizeof(TDiskType)); - return this->m_Output.good() ? sizeof(TDiskType) : 0; - } -} - -int -MGHImageIO ::TWrite(const char * buf, const unsigned long count) -{ - if (this->m_IsCompressed) - { - const unsigned long int result = ::gzwrite(this->m_GZFile, buf, count); - if (result != count) - { - itkExceptionMacro(<< " Failed to write " << count << ", only wrote " << result); - } - return result; - } - else - { - this->m_Output.write(buf, count); - return this->m_Output.good() ? count : 0; - } -} -// -------------------------------------- -// -// MGHImageIO -// - - -MGHImageIO ::MGHImageIO() -{ - this->SetNumberOfDimensions(3); - std::fill(m_Dimensions.begin(), m_Dimensions.end(), 0U); - m_ByteOrder = (ByteSwapper::SystemIsBigEndian()) ? IOByteOrderEnum::BigEndian : IOByteOrderEnum::LittleEndian; -} - -MGHImageIO ::~MGHImageIO() -{ - // Nothing to do in destructor -} - -bool -MGHImageIO ::IsCompressedFilename(const std::string fname) -{ - // - // Originally MGHImageIO allowed ".mgh", ".mgz", - // "mgh.gz" and ".gz" - // - // The '.gz' extension is too ambiguous. It collides with NIfTI - // (.nii.gz) and given that there's no consistent 'magic number' in - // the header, the MGH library will blindly try and read any '.gz' - // file until it crashes or detects invalid data. - // - // So the bare '.gz' extension is no longer recognized. - const std::string lastExtension = itksys::SystemTools::GetFilenameLastExtension(fname.c_str()); - if (lastExtension == __MGZ_EXT) - { - return true; - } - if (lastExtension == __GZ_EXT) - { - const std::string fnameWithoutLastExtension = itksys::SystemTools::GetFilenameWithoutLastExtension(fname); - const std::string penultimateExtension = itksys::SystemTools::GetFilenameLastExtension(fnameWithoutLastExtension); - if (penultimateExtension == __MGH_EXT) - { - return true; - } - } - return false; -} - -bool -MGHImageIO ::CanReadFile(const char * FileNameToRead) -{ - const std::string filename(FileNameToRead); - - if (filename.empty()) - { - itkExceptionMacro(<< "A FileName must be specified."); - return false; - } - - // check if the correct extension is given by the user - const std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename.c_str()); - if (extension == __MGH_EXT || this->IsCompressedFilename(filename)) - { - return true; - } - return false; -} - -void -MGHImageIO ::PrintSelf(std::ostream & os, Indent indent) const -{ - Superclass::PrintSelf(os, indent); - const std::string strSep = ", "; - - os << indent << "Data Dimensions: (" << m_Dimensions[0] << strSep << m_Dimensions[1] << strSep << m_Dimensions[2] - << ")\n" - << indent << "Data Spacing: (" << m_Spacing[0] << strSep << m_Spacing[1] << strSep << m_Spacing[2] << ")\n" - << indent << "Scalar Type: " << m_ComponentType << std::endl - << indent << "Number of Frames: " << m_NumberOfComponents << std::endl; - - os << indent << "RAS to IJK matrix: " << std::endl; -} - -void -MGHImageIO ::ReadImageInformation() -{ - this->m_GZFile = gzopen(m_FileName.c_str(), "rb"); - if (!this->m_GZFile) - { - itkExceptionMacro(<< "Can't find/open file: " << m_FileName); - return; - } - - ReadVolumeHeader(); - gzclose(this->m_GZFile); -} - -void -MGHImageIO ::ReadVolumeHeader() -{ - // check file reading - if (!this->m_GZFile) - { - itkExceptionMacro(<< "Can't find/open file: " << this->m_FileName); - return; - } - int version; - this->TRead(version); - this->TRead(m_Dimensions[0]); - this->TRead(m_Dimensions[1]); - this->TRead(m_Dimensions[2]); - // next is nframes - this->TRead(m_NumberOfComponents); - int type; - this->TRead(type); - int dof; - this->TRead(dof); // what does this do? - - // Convert type to an ITK type - switch (type) - { - case MRI_UCHAR: - { - m_ComponentType = IOComponentEnum::UCHAR; - } - break; - case MRI_INT: - { - m_ComponentType = IOComponentEnum::INT; - } - break; - case MRI_FLOAT: - { - m_ComponentType = IOComponentEnum::FLOAT; - } - break; - case MRI_SHORT: - { - m_ComponentType = IOComponentEnum::SHORT; - } - break; - case MRI_TENSOR: - { - m_ComponentType = IOComponentEnum::FLOAT; - m_NumberOfComponents = 9; - } - break; - default: - itkExceptionMacro(<< " Unknown data type " << type << " using float by default."); - m_ComponentType = IOComponentEnum::FLOAT; - } - - // Next short says whether RAS registration information is good. - // If so, read the voxel size and then the matrix - short RASgood; - this->TRead(RASgood); - if (RASgood) - { - for (size_t nSpacing = 0; nSpacing < 3; ++nSpacing) - { - this->TRead(m_Spacing[nSpacing]); - } - /* - From https://www.nmr.mgh.harvard.edu/~tosa/#coords: - To go from freesurfer voxel coordinates to RAS coordinates, they use: - translation: t_r, t_a, t_s is defined using c_r, c_a, c_s centre voxel position in RAS - rotation: direction cosines x_(r,a,s), y_(r,a,s), z_(r,a,s) - voxel size for scale: s_x, s_y, s_z - - [ x_r y_r z_r t_r][s_x 0 0 0] - [ x_a y_a z_a t_a][0 s_y 0 0] - [ x_s y_s z_s t_s][0 0 s_z 0] - [ 0 0 0 1 ][0 0 0 1] - Voxel center is a column matrix, multipled from the right - [v_x] - [v_y] - [v_z] - [ 1 ] - - In the MGH header, they hold: - x_r x_a x_s - y_r y_a y_s - z_r z_a z_s - c_r c_a c_s - */ - MatrixType MGHdirMatrix; - // reading in x_r x_a x_s y_r y_a y_s z_r z_a z_s and putting it into the - // matrix as: - // x_r y_r z_r - // x_a y_a z_a - // x_s y_s z_s - for (unsigned int c = 0; c < 3; ++c) - { - for (unsigned int r = 0; r < 3; ++r) // NOTE: Data stored row-major form, so traverse rows first - { - this->TRead(MGHdirMatrix[r][c]); - } - } - // getting orientation must be done before RAS->LAS conversion - // but not used const std::string orientation = GetOrientation( MGHdirMatrix ); - // convert the coordinates from RAS to LPS, as the ITK archetype assumes - // LPS volumes. volume orientation not related to scan order, always convert - MatrixType ITKdirMatrix = GetRAS2LPS() * MGHdirMatrix; // Pre-multipy by conversion - for (size_t c = 0; c < 3; ++c) - { - // now take x_r, x_a, x_s out of the matrix and set it to the direction - // vector 0, same for y_* and direction vector 1, z_* and vector 2 - std::vector vDir; - for (size_t r = 0; r < 3; ++r) - { - vDir.push_back(ITKdirMatrix[r][c]); - } - SetDirection(c, vDir); - } - - VectorType MGHcenterVoxel; // c_r c_a c_s - for (size_t ui = 0; ui < 3; ++ui) - { - this->TRead(MGHcenterVoxel[ui]); - } - // convert C to from RAS to LPS - VectorType ITKcenterVoxel = GetRAS2LPS() * MGHcenterVoxel; - - - // MriDirCos(); // convert direction cosines - // finally, store the origin of the image -> only works - // if the image is properly oriented in the sequel - // - // computed in CORONAL orientation = ITK_COORDINATE_ORIENTATION_LIA - VectorType fc; - fc[0] = m_Dimensions[0] * 0.5; - fc[1] = m_Dimensions[1] * 0.5; - fc[2] = m_Dimensions[2] * 0.5; - MatrixType spcing; - spcing[0][0] = m_Spacing[0]; - spcing[1][1] = m_Spacing[1]; - spcing[2][2] = m_Spacing[2]; - - VectorType ITKorigin = ITKcenterVoxel - (ITKdirMatrix * spcing * fc); - m_Origin[0] = ITKorigin[0]; - m_Origin[1] = ITKorigin[1]; - m_Origin[2] = ITKorigin[2]; - } - - // ================== - // read tags at the end of file - const size_t numValues = m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2]; - gzseek( - this->m_GZFile, FS_WHOLE_HEADER_SIZE + (m_NumberOfComponents * numValues * this->GetComponentSize()), SEEK_SET); - - float fBufTR; - // read TR, Flip, TE, FI, FOV - if (this->TRead(fBufTR)) - { - itk::MetaDataDictionary & thisDic = this->GetMetaDataDictionary(); - itk::EncapsulateMetaData(thisDic, std::string("TR"), fBufTR); - - // try to read flipAngle - float fBufFA; - if (this->TRead(fBufFA)) - { - itk::EncapsulateMetaData(thisDic, std::string("FlipAngle"), fBufFA); - // TE - float fBufTE; - if (this->TRead(fBufTE)) - { - itk::EncapsulateMetaData(thisDic, std::string("TE"), fBufTE); - // TI - float fBufTI; - if (this->TRead(fBufTI)) - { - itk::EncapsulateMetaData(thisDic, std::string("TI"), fBufTI); - // FOV - float fBufFOV; - if (this->TRead(fBufFOV)) - { - itk::EncapsulateMetaData(thisDic, std::string("FoV"), fBufFOV); - } - } - } - } - } -} - -void -MGHImageIO ::Read(void * pData) -{ - this->m_GZFile = gzopen(m_FileName.c_str(), "rb"); - if (!this->m_GZFile) - { - itkExceptionMacro(<< "Can't find/open file: " << m_FileName); - return; - } - - const unsigned long numPixels = m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2]; - - const unsigned int componentSize(this->GetComponentSize()); - - // check that the offset is actually computed wrt. the beginning - gzseek(this->m_GZFile, FS_WHOLE_HEADER_SIZE, SEEK_SET); - - const unsigned int frameSize = numPixels * componentSize; - - if (m_NumberOfComponents > 1) - { - auto * pBuffer = new char[frameSize]; - - const unsigned int pixelSize = componentSize * m_NumberOfComponents; - for (unsigned int frameIndex = 0; frameIndex < m_NumberOfComponents; ++frameIndex) - { - // read current frame - gzread(this->m_GZFile, pBuffer, frameSize); - // copy memory location in the final buffer - - auto * pSrc = (char *)pBuffer; - auto * pDst = (char *)pData; - - pDst += frameIndex * componentSize; - for (unsigned int ui = 0; ui < numPixels; ++ui, pSrc += componentSize, pDst += pixelSize) - { - for (unsigned int byteCount = 0; byteCount < componentSize; ++byteCount) - { - *(pDst + byteCount) = *(pSrc + byteCount); - } - } // next ui - } // next frameIndex - - // clear resources - delete[] pBuffer; - } - else - { - gzread(this->m_GZFile, pData, frameSize); - } - - gzclose(this->m_GZFile); - - SwapBytesIfNecessary(pData, numPixels * m_NumberOfComponents); - -} // end Read function - -void -MGHImageIO ::SwapBytesIfNecessary(void * const buffer, const unsigned long numberOfPixels) -{ - // NOTE: If machine order is little endian, and the data needs to be - // swapped, the SwapFromBigEndianToSystem is equivalent to - // SwapFromSystemToBigEndian. - - switch (m_ComponentType) - { - case IOComponentEnum::UCHAR: - { - ByteSwapper::SwapRangeFromSystemToBigEndian((unsigned char *)buffer, numberOfPixels); - } - break; - case IOComponentEnum::SHORT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian((short *)buffer, numberOfPixels); - } - break; - case IOComponentEnum::INT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian((int *)buffer, numberOfPixels); - } - break; - case IOComponentEnum::FLOAT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian((float *)buffer, numberOfPixels); - } - break; - default: - ExceptionObject exception(__FILE__, __LINE__); - exception.SetDescription("Pixel Type Unknown"); - throw exception; - } // end switch -} - -bool -MGHImageIO ::CanWriteFile(const char * name) -{ - const std::string filename(name); - - if (filename.empty()) - { - itkExceptionMacro(<< "A FileName must be specified."); - return false; - } - - // TODO: Use ITK Extension extractor - const std::string extension = itksys::SystemTools::GetFilenameExtension(filename.c_str()); - if (extension != __MGH_EXT && !this->IsCompressedFilename(filename)) - { - return false; - } - return true; -} - -void -MGHImageIO ::OpenFile() -{ - if (this->m_IsCompressed) - { - this->m_GZFile = gzopen(m_FileName.c_str(), "wb"); - if (this->m_GZFile == nullptr) - { - itkExceptionMacro(<< " Failed to open gzFile for writing"); - itkExceptionMacro(<< " File cannot be written"); - } - } - else - { - this->m_Output.open(m_FileName.c_str(), std::ios::out | std::ios::binary); - if (this->m_Output.fail()) - { - itkExceptionMacro(<< " File cannot be written"); - } - } -} -void -MGHImageIO ::CloseFile() -{ - if (this->m_IsCompressed) - { - gzclose(this->m_GZFile); - } - else - { - this->m_Output.close(); - } -} -void -MGHImageIO ::WriteImageInformation() -{ - this->m_IsCompressed = this->IsCompressedFilename(this->m_FileName); - this->OpenFile(); - this->WriteHeader(); - this->CloseFile(); -} - -void -MGHImageIO ::Write(const void * buffer) -{ - this->m_IsCompressed = this->IsCompressedFilename(this->m_FileName); - this->OpenFile(); - this->WriteHeader(); - this->WriteData(buffer); - this->CloseFile(); -} - -void -MGHImageIO ::WriteHeader() -{ - // version - constexpr int mghVersion = 1; - this->TWrite(mghVersion); - // dimensions - for (size_t ui = 0; ui < 3; ++ui) - { - this->TWrite(m_Dimensions[ui]); - } - - // nframes - this->TWrite(m_NumberOfComponents); - - // type - switch (m_ComponentType) - { - case IOComponentEnum::UCHAR: - { - this->TWrite(MRI_UCHAR); - } - break; - case IOComponentEnum::INT: - { - this->TWrite(MRI_INT); - } - break; - case IOComponentEnum::FLOAT: - { - this->TWrite(MRI_FLOAT); - } - break; - case IOComponentEnum::SHORT: - { - this->TWrite(MRI_SHORT); - } - break; - default: - itkExceptionMacro(<< "MGHImageIO supports unsigned char, int, float and short"); - } - - // dof !?! -> default value = 1 - this->TWrite(1); - - // write RAS and voxel size info - // for now, RAS flag will be good - // in the future, check if the m_Directions matrix is a permutation matrix - this->TWrite(1); - // spacing - for (unsigned int ui = 0; ui < 3; ++ui) - { - this->TWrite(m_Spacing[ui]); - } - - // get directions matrix - MatrixType ITKdirMatrix; - for (unsigned int c = 0; c < 3; ++c) - { - const std::vector & dir_line = GetDirection(c); - for (unsigned int r = 0; r < 3; ++r) - { - ITKdirMatrix[r][c] = dir_line[r]; - } - } - MatrixType MGHdirMatrix = GetRAS2LPS() * ITKdirMatrix; // Pre-multipy by RAS2LPS - // writing in x_r x_a x_s y_r y_a y_s z_r z_a z_s and putting it into the - // matrix as: - // x_r y_r z_r - // x_a y_a z_a - // x_s y_s z_s - for (unsigned int c = 0; c < 3; ++c) - { - for (unsigned int r = 0; r < 3; ++r) // Write in row-major order - { - this->TWrite(MGHdirMatrix[r][c]); - } - } - - VectorType fc; - fc[0] = m_Dimensions[0] * 0.5; - fc[1] = m_Dimensions[1] * 0.5; - fc[2] = m_Dimensions[2] * 0.5; - VectorType ITKorigin; - ITKorigin[0] = m_Origin[0]; - ITKorigin[1] = m_Origin[1]; - ITKorigin[2] = m_Origin[2]; - MatrixType spcing; - spcing.SetIdentity(); - spcing[0][0] = m_Spacing[0]; - spcing[1][1] = m_Spacing[1]; - spcing[2][2] = m_Spacing[2]; - const VectorType ITKcenterVoxel = ITKorigin + (ITKdirMatrix * spcing * fc); - const VectorType MGHcenterVoxel = GetRAS2LPS() * ITKcenterVoxel; - for (size_t ui = 0; ui < 3; ++ui) - { - this->TWrite(MGHcenterVoxel[ui]); - } - // fill the rest of the buffer with zeros - const char zerobyte(0); - for (size_t i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) - { - this->TWrite(zerobyte); - } -} - -void -MGHImageIO ::WriteData(const void * buffer) -{ - // swap bytes if necessary - const unsigned int numPixels = m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2]; - const unsigned long int numvalues = numPixels * m_NumberOfComponents; - const unsigned long int numbytes = this->GetComponentSize() * numvalues; - - auto * tempmemory = new char[numbytes]; - - // re-arrange data in frames - if (m_NumberOfComponents > 1) - { - PermuteFrameValues(buffer, tempmemory); - } - else - { - memcpy(tempmemory, buffer, numbytes); - } - - this->SwapBytesIfNecessary(tempmemory, numvalues); - - this->TWrite(tempmemory, this->GetImageSizeInBytes()); - delete[] tempmemory; - - // if present, the scan parameters are present at the end of the file, so now's the time to write them - itk::MetaDataDictionary & thisDic = this->GetMetaDataDictionary(); - - float fScanBuffer = 0.0F; - if (ExposeMetaData(thisDic, "TR", fScanBuffer)) - { - this->TWrite(fScanBuffer); - } // end TR - if (ExposeMetaData(thisDic, "FlipAngle", fScanBuffer)) - { - this->TWrite(fScanBuffer); - } // end FlipAngle - - if (ExposeMetaData(thisDic, "TE", fScanBuffer)) - { - this->TWrite(fScanBuffer); - } // end TE - - if (ExposeMetaData(thisDic, "TI", fScanBuffer)) - { - this->TWrite(fScanBuffer); - } // end TI - - if (ExposeMetaData(thisDic, "FoV", fScanBuffer)) - { - this->TWrite(fScanBuffer); - } // end FoV - - // no need to close the stream -} - -void -MGHImageIO ::PermuteFrameValues(const void * buffer, char * tempmemory) -{ - const unsigned int numPixels = m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2]; - const unsigned int valueSize(this->GetComponentSize()); - const unsigned int frameSize = numPixels * valueSize; - - const auto * pSrc = (const char *)buffer; - auto * pDst = (char *)tempmemory; - - for (unsigned int pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex, pDst += valueSize) - { - for (unsigned int componentIndex = 0; componentIndex < m_NumberOfComponents; ++componentIndex, pSrc += valueSize) - { - std::copy(pSrc, pSrc + valueSize, pDst + frameSize * componentIndex); - } // next component index - } // next pixelIndex -} - -unsigned int -MGHImageIO ::GetComponentSize() const -{ - unsigned int returnValue; - switch (m_ComponentType) - { - case IOComponentEnum::UCHAR: - { - returnValue = sizeof(unsigned char); - } - break; - case IOComponentEnum::SHORT: - { - returnValue = sizeof(short); - } - break; - case IOComponentEnum::INT: - { - returnValue = sizeof(int); - } - break; - case IOComponentEnum::FLOAT: - { - returnValue = sizeof(float); - } - break; - default: - itkExceptionMacro(<< "MGHImageIO supports unsigned char, int, float and short"); - } - return returnValue; -} - -/** - * Examines the direction cosines and creates an Orientation String. - * The Orientation String is a three character string indicating the primary - * direction of each axis in the 3d matrix. The characters can be L,R,A,P,I,S. - **/ -std::string -MGHImageIO ::GetOrientation(itk::Matrix directions) -{ - std::string orientation(""); - for (int cAxes = 0; cAxes < 3; cAxes++) - { - const double sag = directions(0, cAxes); // LR axis - const double cor = directions(1, cAxes); // PA axis - const double ax = directions(2, cAxes); // IS axis - if (itk::Math::abs(sag) > itk::Math::abs(cor) && itk::Math::abs(sag) > itk::Math::abs(ax)) - { - if (sag > 0) - { - orientation += "R"; - } - else - { - orientation += "L"; - } - continue; - } - if (itk::Math::abs(cor) > itk::Math::abs(ax)) - { - if (cor > 0) - { - orientation += "A"; - } - else - { - orientation += "P"; - } - continue; - } - if (ax > 0) - { - orientation += "S"; - } - else - { - orientation += "I"; - } - } - return orientation; -} -} // end namespace itk diff --git a/src/itkMGHImageIOFactory.cxx b/src/itkMGHImageIOFactory.cxx deleted file mode 100644 index 5d9aa32..0000000 --- a/src/itkMGHImageIOFactory.cxx +++ /dev/null @@ -1,64 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#include "itkMGHImageIOFactory.h" -#include "itkMGHImageIO.h" -#include "itkVersion.h" - - -namespace itk -{ -void -MGHImageIOFactory::PrintSelf(std::ostream &, Indent) const -{} - -MGHImageIOFactory::MGHImageIOFactory() -{ - this->RegisterOverride( - "itkImageIOBase", "itkMGHImageIO", "MGH Image IO", true, CreateObjectFunction::New()); -} - -MGHImageIOFactory::~MGHImageIOFactory() = default; - -const char * -MGHImageIOFactory::GetITKSourceVersion() const -{ - return ITK_SOURCE_VERSION; -} - -const char * -MGHImageIOFactory::GetDescription() const -{ - return "MGH ImageIO Factory, allows the loading of MGH/MGZ images into Insight"; -} -// Undocumented API used to register during static initialization. -// DO NOT CALL DIRECTLY. - -static bool MGHImageIOFactoryHasBeenRegistered = false; - -void MGHIO_EXPORT -MGHImageIOFactoryRegister__Private() -{ - if (!MGHImageIOFactoryHasBeenRegistered) - { - MGHImageIOFactoryHasBeenRegistered = true; - MGHImageIOFactory::RegisterOneFactory(); - } -} - -} // end namespace itk diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt deleted file mode 100644 index a8794a1..0000000 --- a/test/CMakeLists.txt +++ /dev/null @@ -1,40 +0,0 @@ -itk_module_test() -set(MGHIOTests - itkMGHImageIOTest.cxx -) - -set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) - -CreateTestDriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") - -itk_add_test(NAME MGHFactoryCreationTest - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} FactoryCreationTest ) - -itk_add_test(NAME MGHReadImagesTest_mgz - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} ReadImagesTest - DATA{${MGH_DATA_ROOT}/T1.mgz} TEST.mgz - ) - -itk_add_test(NAME MGHReadImagesTest_mgh - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} ReadImagesTest - DATA{${MGH_DATA_ROOT}/T1_uncompresed.mgh} TEST.mgh - ) - -itk_add_test(NAME MGHReadImagesTest_mgh.gz - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} ReadImagesTest - DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} TEST.mgh.gz - ) - -itk_add_test(NAME itkMGHIOInternalTests - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} TestReadWriteOfSmallImageOfAllTypes ) -itk_add_test(NAME itkMGHIOOriginTest - COMMAND MGHIOTestDriver itkMGHImageIOTest - ${ITK_TEST_OUTPUT_DIR} TestOriginWriteTest - DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} OriginTEST.mgh.gz - ) - diff --git a/test/MD5/T1.mgz.cid b/test/MD5/T1.mgz.cid deleted file mode 100644 index a416ac4..0000000 --- a/test/MD5/T1.mgz.cid +++ /dev/null @@ -1 +0,0 @@ -bafkreihdhvkddcmmtfgd5wugnrssr5cvzm4ab76lqj53e6f6tybyqrs3xy diff --git a/test/MD5/T1_longname.mgh.gz.cid b/test/MD5/T1_longname.mgh.gz.cid deleted file mode 100644 index a416ac4..0000000 --- a/test/MD5/T1_longname.mgh.gz.cid +++ /dev/null @@ -1 +0,0 @@ -bafkreihdhvkddcmmtfgd5wugnrssr5cvzm4ab76lqj53e6f6tybyqrs3xy diff --git a/test/MD5/T1_uncompresed.mgh.cid b/test/MD5/T1_uncompresed.mgh.cid deleted file mode 100644 index f517f32..0000000 --- a/test/MD5/T1_uncompresed.mgh.cid +++ /dev/null @@ -1 +0,0 @@ -bafkreib3qleljdy2t7czavhmkyzst5hlpobk7rt5pyix2n74hiaspyhfzi diff --git a/test/itkMGHImageIOTest.cxx b/test/itkMGHImageIOTest.cxx deleted file mode 100644 index 3e71192..0000000 --- a/test/itkMGHImageIOTest.cxx +++ /dev/null @@ -1,154 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ - -#include "itkMGHImageIOFactory.h" -#include "itkRandomImageSource.h" -#include "itkImageFileReader.h" -#include "itksys/SystemTools.hxx" -#include "itkMetaDataObject.h" -#include "itkIOCommon.h" - -#include "itkIOTestHelper.h" -#include "itkMGHImageIOTest.h" -#include - -int -itkMGHImageIOTest(int argc, char * argv[]) -{ - itk::ObjectFactoryBase::UnRegisterAllFactories(); - itk::MGHImageIOFactory::RegisterOneFactory(); - if (argc < 3) - { - std::cerr - << "ERROR: Incorrect number of arguments [ImageFileNameRead ImageFileNameWrite]" - << std::endl; - std::cerr << "Only " << argc << " arguments given." << std::endl; - return EXIT_FAILURE; - } - for (int i = 0; i < argc; ++i) - { - std::cout << i << " argv= " << argv[i] << std::endl; - } - // - // first argument is passing in the writable directory to do all testing - itksys::SystemTools::ChangeDirectory(argv[1]); - - static bool firstTime = true; - if (firstTime) - { - itk::ObjectFactoryBase::RegisterFactory(itk::MGHImageIOFactory::New()); - firstTime = false; - } - const std::string TestMode(argv[2]); - - bool returnSucceeded = true; - if (TestMode == std::string("FactoryCreationTest")) - // Tests added to increase code coverage. - { - itk::MGHImageIOFactory::Pointer MyFactoryTest = itk::MGHImageIOFactory::New(); - if (MyFactoryTest.IsNull()) - { - returnSucceeded &= false; - } - // This was made a protected function. MyFactoryTest->PrintSelf(std::cout,0); - } - else if (TestMode == std::string("TestReadWriteOfSmallImageOfAllTypes")) - { - std::string fn("test.mgz"); - // TODO: Need to test with images of non-identity direction cosigns, spacing, origin - returnSucceeded &= itkMGHImageIOTestReadWriteTest(fn, 3, "null", true); - returnSucceeded &= itkMGHImageIOTestReadWriteTest(fn, 3, "null", true); - returnSucceeded &= itkMGHImageIOTestReadWriteTest(fn, 3, "null", true); - returnSucceeded &= itkMGHImageIOTestReadWriteTest(fn, 3, "null", true); - returnSucceeded &= itkMGHImageIOTestReadWriteTest, 3>(fn, 3, "null", true); - } - else if (TestMode == std::string("ReadImagesTest")) // This is a mechanism for reading unsigned int images for - // testing. - { - using ImageType = itk::Image; - const std::string imageToBeRead(argv[3]); - const std::string imageToBeWritten(argv[4]); - try - { - std::cout << "Reading Image: " << imageToBeRead << std::endl; - ImageType::Pointer input = itk::IOTestHelper::ReadImage(imageToBeRead); - std::cout << input << std::endl; - itk::ImageFileWriter::Pointer testFactoryWriter = itk::ImageFileWriter::New(); - testFactoryWriter->SetFileName(imageToBeWritten); - testFactoryWriter->SetInput(input); - testFactoryWriter->Update(); - itk::ImageFileReader::Pointer testFactoryReader = itk::ImageFileReader::New(); - testFactoryReader->SetFileName(imageToBeWritten); - testFactoryReader->Update(); - ImageType::Pointer new_image = testFactoryReader->GetOutput(); - } - catch (itk::ExceptionObject & e) - { - e.Print(std::cerr); - returnSucceeded &= false; - } - } - else if (TestMode == "TestOriginWriteTest") - { - using ImageType = itk::Image; - ImageType::Pointer input; - const std::string imageToBeRead(argv[3]); - const std::string imageToBeWritten(argv[4]); - try - { - std::cout << "Reading Image: " << imageToBeRead << std::endl; - input = itk::IOTestHelper::ReadImage(imageToBeRead); - std::cout << input << std::endl; - - ImageType::PointType reference_origin; - reference_origin[0] = -123.4; - reference_origin[1] = 456.7; - reference_origin[2] = -890.0; - input->SetOrigin(reference_origin); - - itk::ImageFileWriter::Pointer testFactoryWriter = itk::ImageFileWriter::New(); - - testFactoryWriter->SetFileName(imageToBeWritten); - testFactoryWriter->SetInput(input); - testFactoryWriter->Update(); - itk::ImageFileReader::Pointer testFactoryReader = itk::ImageFileReader::New(); - testFactoryReader->SetFileName(imageToBeWritten); - testFactoryReader->Update(); - ImageType::Pointer new_image = testFactoryReader->GetOutput(); - const ImageType::PointType test_origin = new_image->GetOrigin(); - const double dist = reference_origin.EuclideanDistanceTo(test_origin); - if (dist > 1.0E-4) - { - std::cerr << std::setprecision(10) << "Origin written and origin read do not match: " - << "written: " << reference_origin << " read: " << test_origin << " distance: " << dist << std::endl; - returnSucceeded &= false; - } - } - catch (itk::ExceptionObject & e) - { - e.Print(std::cerr); - returnSucceeded &= false; - } - } - else - { - std::cerr << "Invalid TestMode : " << TestMode << std::endl; - returnSucceeded &= false; - } - return (returnSucceeded == true) ? EXIT_SUCCESS : EXIT_FAILURE; -} diff --git a/test/itkMGHImageIOTest.h b/test/itkMGHImageIOTest.h deleted file mode 100644 index 66c3c75..0000000 --- a/test/itkMGHImageIOTest.h +++ /dev/null @@ -1,314 +0,0 @@ -/*========================================================================= - * - * Copyright NumFOCUS - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0.txt - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - *=========================================================================*/ -#ifndef itkMGHImageIOTest_h -#define itkMGHImageIOTest_h - -#include -#include -#include -#include "itkImageRegionIterator.h" -#include "itkImageFileReader.h" -#include "itkImageFileWriter.h" -#include "itkMGHImageIO.h" -#include "itkImage.h" -#include "itkImageRegionIteratorWithIndex.h" -#include "itkRandomImageSource.h" -#include "itkDiffusionTensor3D.h" - -#include "itkEuler3DTransform.h" - - -template -typename itk::Image::Pointer -itkMGHImageIOTestGenerateRandomImage(const unsigned int size) -{ - using EulerTransformType = itk::Euler3DTransform; - EulerTransformType::Pointer eulerTransform = EulerTransformType::New(); - eulerTransform->SetIdentity(); - - // 15 degrees in radians - const double angleX = 15.0 * std::atan(1.0) / 45.0; - // 10 degrees in radians - const double angleY = 10.0 * std::atan(1.0) / 45.0; - // 5 degrees in radians - const double angleZ = 5.0 * std::atan(1.0) / 45.0; - eulerTransform->SetRotation(angleX, angleY, angleZ); - - using ImageType = itk::Image; - - typename ImageType::DirectionType permuteDirections; - const double dir1[3] = { -1., 0., 0. }; - const double dir2[3] = { 0., 0., 1. }; - const double dir3[3] = { 0., -1., 0. }; - permuteDirections.GetVnlMatrix().set_column(0, dir1); - permuteDirections.GetVnlMatrix().set_column(1, dir2); - permuteDirections.GetVnlMatrix().set_column(2, dir3); - - typename ImageType::DirectionType direction = eulerTransform->GetMatrix() * permuteDirections; - - for (unsigned int i = 0; i < VImageDimension; ++i) - { - for (unsigned int j = 0; j < VImageDimension; ++j) - { - direction[i][j] = static_cast(direction[i][j]); // Truncate for testing purposes - } - } - - typename ImageType::SizeType sz; - typename ImageType::SpacingType spacing; - typename ImageType::PointType origin; - - for (unsigned int i = 0; i < VImageDimension; ++i) - { - sz[i] = size; - spacing[i] = static_cast(i + 1.234567); - origin[i] = static_cast(1234.5); - } - - typename itk::RandomImageSource::Pointer source = itk::RandomImageSource::New(); - - source->SetDirection(direction); - source->SetSize(sz); - source->SetOrigin(origin); - source->SetSpacing(spacing); - - source->Update(); - typename ImageType::Pointer outImage = source->GetOutput(); - - { - itk::MetaDataDictionary & thisDic = outImage->GetMetaDataDictionary(); - // Add meta data to dictionary - // set TR, Flip, TE, FI, FOV //TODO: Add code that verifies these values - float fBufTR = 2.0F; - float fBufFA = 89.1F; - float fBufTE = 1.5F; - float fBufTI = 0.75F; - float fBufFOV = 321.0F; - itk::EncapsulateMetaData(thisDic, std::string("TR"), fBufTR); - // try to read flipAngle - itk::EncapsulateMetaData(thisDic, std::string("FlipAngle"), fBufFA); - // TE - itk::EncapsulateMetaData(thisDic, std::string("TE"), fBufTE); - // TI - itk::EncapsulateMetaData(thisDic, std::string("TI"), fBufTI); - // FOV - itk::EncapsulateMetaData(thisDic, std::string("FoV"), fBufFOV); - } - return outImage; -} - -// Template specialization for itkDiffusionTensor3D -template <> -itk::Image, 3>::Pointer -itkMGHImageIOTestGenerateRandomImage, 3>(unsigned int size) -{ - using TensorImageType = itk::Image, 3>; - using TensorImagePointer = TensorImageType::Pointer; - - const double dir1[3] = { 0, -1, 0 }; - const double dir2[3] = { 1, 0, 0 }; - const double dir3[3] = { 0, 0, -1 }; - - TensorImageType::DirectionType direction; - direction.GetVnlMatrix().set_column(0, dir1); - direction.GetVnlMatrix().set_column(1, dir2); - direction.GetVnlMatrix().set_column(2, dir3); - - TensorImageType::SizeType sz; - TensorImageType::SpacingType spacing; - TensorImageType::PointType origin; - for (unsigned int i = 0; i < 3; ++i) - { - sz[i] = size; - spacing[i] = static_cast(i * 3.21 + 1.0); - origin[i] = static_cast(1.23456); - } - - TensorImagePointer tensorImage = TensorImageType::New(); - tensorImage->SetRegions(sz); - tensorImage->SetSpacing(spacing); - tensorImage->SetOrigin(origin); - tensorImage->Allocate(); - tensorImage->SetDirection(direction); - - itk::DiffusionTensor3D pix; - using ScalarImageType = itk::Image; - using ScalarImagePointer = ScalarImageType::Pointer; - - std::vector scalarImageVec; - for (unsigned i = 0; i < pix.Size(); ++i) - { - ScalarImagePointer tempImage = itkMGHImageIOTestGenerateRandomImage(size); - scalarImageVec.push_back(tempImage); - } - itk::ImageRegionIteratorWithIndex tensorIt(tensorImage, tensorImage->GetLargestPossibleRegion()); - for (tensorIt.GoToBegin(); !tensorIt.IsAtEnd(); ++tensorIt) - { - for (unsigned int i = 0; i < pix.Size(); ++i) - { - const TensorImageType::IndexType & index = tensorIt.GetIndex(); - pix.SetNthComponent(i, scalarImageVec[i]->GetPixel(index)); - } - tensorIt.Set(pix); - } - return tensorImage; -} - - -template -bool -itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, std::string inputFile, bool compression = false) -{ - using ImageType = itk::Image; - - typename itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); - typename itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); - - itk::MGHImageIO::Pointer io = itk::MGHImageIO::New(); - reader->SetImageIO(io); - writer->SetImageIO(io); - - typename ImageType::Pointer reference_image; - - if (inputFile != "null") - { - typename itk::ImageFileReader::Pointer tmpReader = itk::ImageFileReader::New(); - tmpReader->SetImageIO(io); - tmpReader->SetFileName(inputFile.c_str()); - try - { - tmpReader->Update(); - std::cout << "DONE READING INPUT IMAGE" << std::endl; - } - catch (itk::ExceptionObject & e) - { - std::cerr << e << std::endl; - return EXIT_FAILURE; - } - reference_image = tmpReader->GetOutput(); - } - else - { - // Generate a random reference_image. - reference_image = itkMGHImageIOTestGenerateRandomImage(size); - } - - // Write, then read the reference_image. - try - { - writer->SetFileName(fn.c_str()); - if (compression == true) - { - writer->UseCompressionOn(); - } - else - { - writer->UseCompressionOff(); - } - reader->SetFileName(fn.c_str()); - // writer->SetFileName("testDebug.mhd"); - // reader->SetFileName("testDebug.mhd"); - } - catch (itk::ExceptionObject & e) - { - std::cerr << e << std::endl; - return EXIT_FAILURE; - } - - writer->SetInput(reference_image); - reference_image->Print(std::cout); - std::cout << "----------" << std::endl; - - try - { - writer->Update(); - std::cout << "DONE WRITING TEST IMAGE" << std::endl; - reader->Update(); - std::cout << "DONE READING TEST IMAGE" << std::endl; - } - catch (itk::ExceptionObject & e) - { - std::cerr << "Exception in file reader or writer " << std::endl; - std::cerr << e.GetDescription() << std::endl; - std::cerr << e.GetLocation() << std::endl; - return EXIT_FAILURE; - } - - // Print the reference_image information. - - typename ImageType::Pointer test_image = reader->GetOutput(); - test_image->Print(std::cout); - std::cout << std::endl; - - bool isFailingPixelValues = false; - bool isFailingOrigin = false; - bool isFailingSpacing = false; - bool isFailingDirection = false; - // Compare input and output images. - itk::ImageRegionIterator a(reference_image, reference_image->GetRequestedRegion()); - itk::ImageRegionIterator b(test_image, test_image->GetRequestedRegion()); - for (a.GoToBegin(), b.GoToBegin(); !a.IsAtEnd(); ++a, ++b) - { - if (b.Get() != a.Get()) - { - std::cerr << "At index " << b.GetIndex() << " value " << b.Get() << " should be " << a.Get() << std::endl; - isFailingPixelValues = true; - } - } - for (int idx = 0; idx < 3; ++idx) - { - // itk::Math::FloatAlmostEqual( floatRepresentationfx1.asFloat, floatRepresentationfx2.asFloat, 4, 0.1f) - if (!itk::Math::FloatAlmostEqual(test_image->GetSpacing()[idx], reference_image->GetSpacing()[idx], 4, 1e-7)) - { - isFailingSpacing = true; - } - if (!itk::Math::FloatAlmostEqual(test_image->GetOrigin()[idx], reference_image->GetOrigin()[idx], 100000, 1e-1)) - { - isFailingOrigin = true; - } - for (int idx2 = 0; idx2 < 3; ++idx2) - { - if (!itk::Math::FloatAlmostEqual( - test_image->GetDirection()[idx][idx2], reference_image->GetDirection()[idx][idx2], 4, 1e-7)) - { - isFailingDirection = true; - } - } - } - std::cerr << std::fixed << std::setprecision(10) << std::endl; - // Report failure dianostics - if (isFailingSpacing) - { - std::cerr << "ERROR: Invalid Spacing: " << test_image->GetSpacing() << " ! = " << reference_image->GetSpacing() - << std::endl; - } - if (isFailingOrigin) - { - std::cerr << "ERROR: Invalid Origin: " << test_image->GetOrigin() << " ! = " << reference_image->GetOrigin() - << std::endl; - } - if (isFailingDirection) - { - std::cerr << "ERROR: Invalid Direction: \n" - << test_image->GetDirection() << " ! = \n" - << reference_image->GetDirection() << std::endl; - } - return !(isFailingPixelValues || isFailingOrigin || isFailingSpacing || isFailingDirection); -} - -#endif // itkMGHImageIOTest_h_ diff --git a/wrapping/CMakeLists.txt b/wrapping/CMakeLists.txt deleted file mode 100644 index c2bacc1..0000000 --- a/wrapping/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -itk_wrap_module(MGHIO) -itk_auto_load_submodules() -itk_end_wrap_module() diff --git a/wrapping/itkMGHImageIO.wrap b/wrapping/itkMGHImageIO.wrap deleted file mode 100644 index e43d19a..0000000 --- a/wrapping/itkMGHImageIO.wrap +++ /dev/null @@ -1,2 +0,0 @@ -itk_wrap_simple_class("itk::MGHImageIO" POINTER) -itk_wrap_simple_class("itk::MGHImageIOFactory" POINTER)