From 81f9f39d9fe8d0651ea0a0df9c3421f167774697 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 May 2013 10:18:48 -0500 Subject: [PATCH 01/68] ENH: Adding Remote Module for ITKv4 A copy of the Slicer itkMGHImageIO mechanism for ITK. The intent of this repository is to extract the itkMGHImageIO from it's embedded Slicer only implementation and make it accessible to any ITK compliant program. This will be accomplished using the ITKv4 'Remote Module' mechanism as defined at: http://www.itk.org/Wiki/ITK/Policy_and_Procedures_for_Adding_Remote_Modules --- Modules/IO/MGHIO/CMakeLists.txt | 3 + Modules/IO/MGHIO/include/itkMGHImageIO.h | 133 +++ .../IO/MGHIO/include/itkMGHImageIOFactory.h | 69 ++ Modules/IO/MGHIO/itk-module.cmake | 13 + Modules/IO/MGHIO/src/CMakeLists.txt | 8 + Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 842 ++++++++++++++++++ Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 64 ++ Modules/IO/MGHIO/test/CMakeLists.txt | 37 + Modules/IO/MGHIO/test/MD5/T1.mgz.md5 | 1 + .../IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 | 1 + .../IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 | 1 + Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 119 +++ Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 229 +++++ Modules/IO/MGHIO/wrapping/CMakeLists.txt | 3 + Modules/IO/MGHIO/wrapping/itkMGHImageIO.wrap | 2 + 15 files changed, 1525 insertions(+) create mode 100644 Modules/IO/MGHIO/CMakeLists.txt create mode 100644 Modules/IO/MGHIO/include/itkMGHImageIO.h create mode 100644 Modules/IO/MGHIO/include/itkMGHImageIOFactory.h create mode 100644 Modules/IO/MGHIO/itk-module.cmake create mode 100644 Modules/IO/MGHIO/src/CMakeLists.txt create mode 100644 Modules/IO/MGHIO/src/itkMGHImageIO.cxx create mode 100644 Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx create mode 100644 Modules/IO/MGHIO/test/CMakeLists.txt create mode 100644 Modules/IO/MGHIO/test/MD5/T1.mgz.md5 create mode 100644 Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 create mode 100644 Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 create mode 100644 Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx create mode 100644 Modules/IO/MGHIO/test/itkMGHImageIOTest.h create mode 100644 Modules/IO/MGHIO/wrapping/CMakeLists.txt create mode 100644 Modules/IO/MGHIO/wrapping/itkMGHImageIO.wrap diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt new file mode 100644 index 000000000000..600f051a6e6d --- /dev/null +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -0,0 +1,3 @@ +project(ITKIOMGH) +set(ITKIOMGH_LIBRARIES ITKIOMGH) +itk_module_impl() diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h new file mode 100644 index 000000000000..99bdc99af1e6 --- /dev/null +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -0,0 +1,133 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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" + +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 ITKIOMGH + */ +class ITK_EXPORT MGHImageIO:public ImageIOBase +{ +public: + /** Standard class typedefs. */ + typedef MGHImageIO Self; + typedef ImageIOBase Superclass; + typedef SmartPointer Pointer; + + /** Method for creation through the object factory. */ + itkNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(MGHImageIO, Superclass); + + /*-------- 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. + */ + virtual bool CanReadFile(const char *FileNameToRead); + + /** Set the spacing and dimension information for the set filename. */ + virtual void ReadImageInformation(); + + /** Reads the data from disk into the memory buffer provided. */ + virtual void Read(void *buffer); + + /*-------- 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. + */ + virtual bool CanWriteFile(const char *FileNameToWrite); + + /** Set the spacing and dimension information for the set filename. */ + virtual void WriteImageInformation(); + + /** Writes the data to disk from the memory buffer provided. Make sure + * that the IORegions has been set properly. */ + virtual void Write(const void *buffer); + +protected: + MGHImageIO(); + ~MGHImageIO(); + void PrintSelf(std::ostream& os, Indent indent) const; + + 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; + + std::string GetOrientation( itk::Matrix directions ); + + bool m_IsCompressed; + gzFile m_GZFile; + std::ofstream *m_Output; + + template int TWrite(T out); + template int TRead(T &out); + + int TWrite(const char *buf,unsigned long count); + void OpenFile(); + void CloseFile(); +}; +} // end namespace itk + +#endif // __itkMGHImageIO_h diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h new file mode 100644 index 000000000000..c56478efcff9 --- /dev/null +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -0,0 +1,69 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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" + +namespace itk +{ +/** \class MGHImageIOFactory + * \brief Create instances of MGHImageIO objects using an object factory. + * \ingroup ITKIOMGH + */ +class ITK_EXPORT MGHImageIOFactory : public ObjectFactoryBase +{ +public: + /** Standard class typedefs */ + typedef MGHImageIOFactory Self; + typedef ObjectFactoryBase Superclass; + typedef SmartPointer Pointer; + typedef SmartPointer ConstPointer; + + /** Class methods used to interface with the registered factories **/ + virtual const char * GetITKSourceVersion(void) const; + + virtual const char * GetDescription(void) const; + + /** Method for class instantiation **/ + itkFactorylessNewMacro(Self); + + /** Run-time type information (and related methods). */ + itkTypeMacro(MGHImageIOFactory, ObjectFactoryBase); + + /** Register one factory of this type */ + static void RegisterOneFactory(void) + { + MGHImageIOFactory::Pointer MGHFactory = MGHImageIOFactory::New(); + + ObjectFactoryBase::RegisterFactoryInternal(MGHFactory); + } + +protected: + MGHImageIOFactory(); + ~MGHImageIOFactory(); + virtual void PrintSelf(std::ostream & os, Indent indent) const; + +private: + MGHImageIOFactory(const Self &); //purposely not implemented + void operator=(const Self &); //purposely not implemented +}; +} // end namespace itk + +#endif /// __itkMGHImageIOFactory_h diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake new file mode 100644 index 000000000000..e7c4ded97d1d --- /dev/null +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -0,0 +1,13 @@ +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(ITKIOMGH + DEPENDS + ITKIOImageBase + ITKZLIB + TEST_DEPENDS + ITKTestKernel + ITKTransform + DESCRIPTION + "${DOCUMENTATION}" +) diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt new file mode 100644 index 000000000000..9edf94c5aad6 --- /dev/null +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -0,0 +1,8 @@ +set(ITKIOMGH_SRC +itkMGHImageIOFactory.cxx +itkMGHImageIO.cxx +) + +add_library(ITKIOMGH ${ITKIOMGH_SRC}) +target_link_libraries(ITKIOMGH ${ITKMGH_LIBRARIES} ${ITKIOImageBase_LIBRARIES} ${ITKTransform_LIBRARIES}) +itk_module_target(ITKIOMGH) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx new file mode 100644 index 000000000000..b70afefd059a --- /dev/null +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -0,0 +1,842 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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"); +static const std::string __MGHGZ_EXT(".mgh.gz"); + + +// ------------------------------- +// +// Convert to BE +// +// ------------------------------- + +template +int +MGHImageIO +::TRead(T & out) +{ + const int result = ::gzread(this->m_GZFile, &out, sizeof(T) ); + itk::ByteSwapper::SwapFromSystemToBigEndian(&out); + return result; +} + +template +int +MGHImageIO +::TWrite(T out) +{ + itk::ByteSwapper::SwapFromSystemToBigEndian(&out); + if(this->m_IsCompressed) + { + return ::gzwrite(this->m_GZFile,&out,sizeof(T)); + } + else + { + this->m_Output->write(reinterpret_cast(&out),sizeof(T)); + return this->m_Output->good() ? sizeof(T) : 0; + } +} + +int +MGHImageIO +::TWrite(const char *buf,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() ) ? BigEndian : LittleEndian; +} + +MGHImageIO +::~MGHImageIO() +{ + //Nothing to do in destructor +} + +bool +MGHImageIO +::IsCompressedFilename(const std::string fname) +{ + const std::string extension = itksys::SystemTools::GetFilenameExtension(fname.c_str()); + return extension == __MGZ_EXT || extension == __GZ_EXT || extension == __MGHGZ_EXT; +} + +bool +MGHImageIO +::CanReadFile(const char* FileNameToRead) +{ + const std::string filename(FileNameToRead); + + if( filename == "" ) + { + itkExceptionMacro(<< "A FileName must be specified."); + return false; + } + + // check if the correct extension is given by the user + const std::string extension = itksys::SystemTools::GetFilenameExtension(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); + int bufInt; // buffer -> int type (most ITK types are unsigned) + this->TRead( bufInt); + m_Dimensions[0] = static_cast(bufInt); + this->TRead( bufInt); + m_Dimensions[1] = static_cast(bufInt); + this->TRead( bufInt); + m_Dimensions[2] = static_cast(bufInt); + // next is nframes + this->TRead( bufInt); + m_NumberOfComponents = static_cast(bufInt); + 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 = UCHAR; + } + break; + case MRI_INT: + { + m_ComponentType = INT; + } + break; + case MRI_FLOAT: + { + m_ComponentType = FLOAT; + } + break; + case MRI_SHORT: + { + m_ComponentType = SHORT; + } + break; + case MRI_TENSOR: + { + m_ComponentType = FLOAT; + m_NumberOfComponents = 9; + } + break; + default: + itkExceptionMacro(<< " Unknown data type " << type << " using float by default."); + m_ComponentType = 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( int nSpacing = 0; nSpacing < 3; ++nSpacing ) + { + float spacing; + this->TRead( spacing); // type is different + m_Spacing[nSpacing] = spacing; + } + /* + From http://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 + */ + typedef itk::Matrix MatrixType; + MatrixType matrix; + // 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 uj = 0; uj < 3; ++uj ) + { + for( unsigned int ui = 0; ui < 3; ++ui ) + { + float fBuffer; + this->TRead( fBuffer); + matrix[ui][uj] = fBuffer; +// std::cout << "itkMGHImageIO ReadVolumeHeader: matrix[" << ui << "][" << uj << "] = " << matrix[ui][uj] << "\n"; + } + } + float c[3]; + for( unsigned int ui = 0; ui < 3; ++ui ) + { + this->TRead( c[ui]); + } + + const std::string orientation = GetOrientation( matrix ); + // 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 + for( unsigned int ui = 0; ui < 3; ++ui ) + { + // convert the coordinates from RAS to LPS, as the ITK archetype assumes + // LPS volumes + // volume orientation not related to scan order, always convert + matrix[0][ui] *= -1.0; // R -> L + matrix[1][ui] *= -1.0; // A -> P + std::vector vDir; + for( unsigned int uj = 0; uj < 3; ++uj ) + { + vDir.push_back( matrix[uj][ui] ); + } + // std::cout << "itkMGHImageIO ReadVolumeHeader: setting " << ui << " direction in LPS: " << vDir[0] << "," << + // vDir[1] << "," << vDir[2] << "\n"; + SetDirection( ui, vDir ); + } + + // MriDirCos(); // convert direction cosines + + // finally, store the origin of the image -> only works + // if the image is properly orriented in the sequel + // + // computed in CORONAL orientation = ITK_COORDINATE_ORIENTATION_LIA + // convert C to from RAS to LPS + c[0] *= -1; + c[1] *= -1; + const float fcx = static_cast(m_Dimensions[0]) / 2.0f; + const float fcy = static_cast(m_Dimensions[1]) / 2.0f; + const float fcz = static_cast(m_Dimensions[2]) / 2.0f; + for( unsigned int ui = 0; ui < 3; ++ui ) + { + m_Origin[ui] = c[ui] + - ( matrix[ui][0] * m_Spacing[0] * fcx + + matrix[ui][1] * m_Spacing[1] * fcy + + matrix[ui][2] * m_Spacing[2] * fcz ); + } + + } + + // ================== + // read tags at the end of file + + const unsigned long 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 fBuf; + // read TR, Flip, TE, FI, FOV + if( this->TRead( fBuf) ) + { + itk::MetaDataDictionary & thisDic = this->GetMetaDataDictionary(); + itk::EncapsulateMetaData(thisDic, + std::string("TR"), + fBuf); + + // try to read flipAngle + if( this->TRead( fBuf ) ) + { + itk::EncapsulateMetaData(thisDic, + std::string("FlipAngle"), + fBuf); + // TE + if( this->TRead( fBuf ) ) + { + itk::EncapsulateMetaData(thisDic, + std::string("TE"), + fBuf); + // TI + if( this->TRead( fBuf) ) + { + itk::EncapsulateMetaData(thisDic, + std::string("TI"), + fBuf); + // FOV + if( this->TRead( fBuf) ) + { + itk::EncapsulateMetaData(thisDic, + std::string("FoV"), + fBuf); + } + } + } + } + } +} + +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 ) + { + char* 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 + + char * pSrc = (char *)pBuffer; + char * 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 UCHAR: + { + ByteSwapper::SwapRangeFromSystemToBigEndian( (unsigned char *)buffer, + numberOfPixels); + } + break; + case SHORT: + { + ByteSwapper::SwapRangeFromSystemToBigEndian( (short *)buffer, + numberOfPixels); + } + break; + case INT: + { + ByteSwapper::SwapRangeFromSystemToBigEndian( (int *)buffer, + numberOfPixels); + } + break; + case 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 == 0 ) + { + itkExceptionMacro(<< " Failed to open gzFile for writing"); + itkExceptionMacro(<< " File cannot be written"); + } + } + else + { + this->m_Output = new std::ofstream; + 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 + const int mghVersion = 1; + this->TWrite(mghVersion ); + // dimensions + for( unsigned int ui = 0; ui < 3; ++ui ) + { + this->TWrite((int)m_Dimensions[ui] ); + } + + // nframes + this->TWrite((int)m_NumberOfComponents ); + + // type + switch( m_ComponentType ) + { + case UCHAR: + { + this->TWrite(MRI_UCHAR); + } + break; + case INT: + { + this->TWrite(MRI_INT); + } + break; + case FLOAT: + { + this->TWrite(MRI_FLOAT); + } + break; + case 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((short)1); + // spacing + for( unsigned int ui = 0; ui < 3; ++ui ) + { + this->TWrite((float)m_Spacing[ui]); + } + + // get directions matrix + std::vector > vvRas; + for( unsigned int ui = 0; ui < 3; ++ui ) + { + vvRas.push_back( GetDirection(ui) ); + } + // transpose data before writing it + std::vector vBufRas; + // transpose the matrix + for( unsigned int ui(0); ui < 3; ++ui ) + { + for( unsigned int uj(0); uj < 3; ++uj ) + { + if( uj == 0 || uj == 1 ) + { + // convert the coordinates from LPS to RAS + vBufRas.push_back(-1.0 * (float)vvRas[uj][ui] ); + } + else + { + vBufRas.push_back( (float)vvRas[uj][ui] ); + } + } + } + for( std::vector::const_iterator cit = vBufRas.begin(); cit != vBufRas.end(); ++cit ) + { + this->TWrite(*cit); + } + + // write c_r, c_a, c_s + // defined as origin + DC x resolution x ( dim0/2 , dim1/2, dim2/2 ) + for( unsigned int ui = 0; ui < 3; ++ui ) + { + float crasBuf = m_Origin[ui]; + for( unsigned int uj = 0; uj < 3; ++uj ) + { + crasBuf += vvRas[ui][uj] * m_Spacing[uj] * (float)m_Dimensions[uj] / 2.0f; + } + this->TWrite(crasBuf ); + } // next ui + + // fill the rest of the buffer with zeros + const char zerobyte(0); + for(unsigned int 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; + + char* 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 char* pSrc = (const char *)buffer; + char* 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 UCHAR: + { + returnValue = sizeof(unsigned char); + } + break; + case SHORT: + { + returnValue = sizeof(short); + } + break; + case INT: + { + returnValue = sizeof(int); + } + break; + case 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( fabs(sag) > fabs(cor) && fabs(sag) > fabs(ax) ) + { + if( sag > 0 ) + { + orientation += "R"; + } + else + { + orientation += "L"; + } + continue; + } + if( fabs(cor) > fabs(ax) ) + { + if( cor > 0 ) + { + orientation += "A"; + } + else + { + orientation += "P"; + } + continue; + } + if( ax > 0 ) + { + orientation += "S"; + } + else + { + orientation += "I"; + } + } + // std::cout << "GetOrientation returning " << orientation.c_str() << std::endl; + return orientation; +} +} // end namespace itk diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx new file mode 100644 index 000000000000..844419de5474 --- /dev/null +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -0,0 +1,64 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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", + 1, + CreateObjectFunction::New() ); +} + +MGHImageIOFactory::~MGHImageIOFactory() +{} + +const char * +MGHImageIOFactory::GetITKSourceVersion(void) 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 MGHImageIOFactoryRegister__Private(void) +{ + if( ! MGHImageIOFactoryHasBeenRegistered ) + { + MGHImageIOFactoryHasBeenRegistered = true; + MGHImageIOFactory::RegisterOneFactory(); + } +} + +} // end namespace itk diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt new file mode 100644 index 000000000000..2a4aa5fcbb5a --- /dev/null +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -0,0 +1,37 @@ +itk_module_test() +set(ITKIOMGHTests + itkMGHImageIOTest.cxx +) + +set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) + +# For itkMGHImageIOTest.h. +include_directories( ${ITKIOMGH_SOURCE_DIR}/test ) + +CreateTestDriver(ITKIOMGH "${ITKIOMGH-Test_LIBRARIES}" "${ITKIOMGHTests}") + +itk_add_test(NAME MGHFactoryCreationTest + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} FactoryCreationTest ) + +itk_add_test(NAME MGHReadImagesTest_mgz + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} ReadImagesTest + DATA{${MGH_DATA_ROOT}/T1.mgz} TEST.mgz + ) + +itk_add_test(NAME MGHReadImagesTest_mgh + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} ReadImagesTest + DATA{${MGH_DATA_ROOT}/T1_uncompresed.mgh} TEST.mgh + ) + +itk_add_test(NAME MGHReadImagesTest_mgh.gz + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} ReadImagesTest + DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} TEST.mgh.gz + ) + +itk_add_test(NAME itkMGHIOInternalTests + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} TestReadWriteOfSmallImageOfAllTypes ) diff --git a/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 b/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 new file mode 100644 index 000000000000..322e898af15f --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 @@ -0,0 +1 @@ +0409fb9d011d00b8a0d8f18997634017 diff --git a/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 b/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 new file mode 100644 index 000000000000..322e898af15f --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 @@ -0,0 +1 @@ +0409fb9d011d00b8a0d8f18997634017 diff --git a/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 b/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 new file mode 100644 index 000000000000..dbade93fef41 --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 @@ -0,0 +1 @@ +c9957d62f0bda84055b4f41f4eef28ef diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx new file mode 100644 index 000000000000..120bb75657db --- /dev/null +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -0,0 +1,119 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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 "itkRandomImageSource.h" +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itksys/SystemTools.hxx" +#include "itkMetaDataObject.h" +#include "itkDiffusionTensor3D.h" +#include "itkIOCommon.h" + +#include "itkIOTestHelper.h" +#include "itkMGHImageIOTest.h" + +#define SPECIFIC_IMAGEIO_MODULE_TEST + + +int itkMGHImageIOTest(int ac, char* av[]) +{ + itk::ObjectFactoryBase::UnRegisterAllFactories(); + itk::MGHImageIOFactory::RegisterOneFactory(); + if(ac < 3 ) + { + std::cerr << "ERROR: Incorrect number of arguments [ImageFileNameRead ImageFileNameWrite]" << std::endl; + std::cerr << "Only " << ac << " arguments given." << std::endl; + return EXIT_FAILURE; + } + for(int i =0; i < ac; ++i) + { + std::cout << i << " av= " << av[i] << std::endl; + } + // + // first argument is passing in the writable directory to do all testing + itksys::SystemTools::ChangeDirectory(av[1]); + + static bool firstTime = true; + if(firstTime) + { + itk::ObjectFactoryBase::RegisterFactory(itk::MGHImageIOFactory::New() ); + firstTime = false; + } + const std::string TestMode(av[2]); + + int returnStatus = EXIT_SUCCESS; + if( TestMode == std::string("FactoryCreationTest")) + //Tests added to increase code coverage. + { + itk::MGHImageIOFactory::Pointer MyFactoryTest=itk::MGHImageIOFactory::New(); + if(MyFactoryTest.IsNull()) + { + returnStatus = EXIT_FAILURE; + } + //This was made a protected function. MyFactoryTest->PrintSelf(std::cout,0); + } + else if ( TestMode == std::string("TestReadWriteOfSmallImageOfAllTypes")) + { + std::string fn("test.mgz"); + if( ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && + ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && + ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && + ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && + ( returnStatus = itkMGHImageIOTestReadWriteTest, 3>(fn,3,"null", true) ) != EXIT_FAILURE ) + { + returnStatus = EXIT_SUCCESS; + } + //TODO: Need to test with images of non-identity direction cosigns, spacing, origin + } + else if( TestMode == std::string("ReadImagesTest") ) //This is a mechanism for reading unsigned int images for testing. + { + typedef itk::Image ImageType; + ImageType::Pointer input; + const std::string imageToBeRead(av[3]); + const std::string imageToBeWritten(av[4]); + try + { + std::cout << "Reading Image: " << imageToBeRead << std::endl; + 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); + returnStatus = EXIT_FAILURE; + } + } + else + { + std::cerr << "Invalid TestMode : " << TestMode << std::endl; + returnStatus = EXIT_FAILURE; + } + return returnStatus; +} diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h new file mode 100644 index 000000000000..b3e88c99a69a --- /dev/null +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -0,0 +1,229 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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 + * + * http://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 "itkImageRegionIterator.h" +#include "itkImageFileReader.h" +#include "itkImageFileWriter.h" +#include "itkMGHImageIO.h" +#include "itkImage.h" +#include "itkImageRegionIteratorWithIndex.h" +#include "itkRandomImageSource.h" +#include "itkDiffusionTensor3D.h" + +template +typename itk::Image::Pointer +itkMGHImageIOTestGenerateRandomImage(unsigned int size) +{ + typedef itk::Image ImageType; + + const double dir1[3] = { 0, -1, 0 }; + const double dir2[3] = { 1, 0, 0 }; + const double dir3[3] = { 0, 0, -1 }; + + typename ImageType::DirectionType direction; + direction.GetVnlMatrix().set_column(0,dir1); + direction.GetVnlMatrix().set_column(1,dir2); + direction.GetVnlMatrix().set_column(2,dir3); + + 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); + origin[i] = static_cast(i); + } + + typename itk::RandomImageSource::Pointer source + = itk::RandomImageSource::New(); + + source->SetDirection(direction); + source->SetSize(sz); + source->SetOrigin(origin); + source->SetSpacing(spacing); + + source->Update(); + return (source->GetOutput()); +} + +//Template specialization for itkDiffusionTensor3D +template<> +itk::Image,3>::Pointer +itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsigned int size) +{ + typedef itk::Image,3> TensorImageType; + typedef TensorImageType::Pointer TensorImagePointer; + + 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 + 1); + origin[i] = static_cast( (i & 1) ? -i : i ); + } + + TensorImagePointer tensorImage = TensorImageType::New(); + tensorImage->SetRegions(sz); + tensorImage->SetSpacing(spacing); + tensorImage->SetOrigin(origin); + tensorImage->Allocate(); + tensorImage->SetDirection(direction); + + itk::DiffusionTensor3D pix; + typedef itk::Image ScalarImageType; + typedef ScalarImageType::Pointer ScalarImagePointer; + + 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 +int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, + std::string inputFile, bool compression=false) +{ + typedef itk::Image ImageType; + + 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 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; + } + + image = tmpReader->GetOutput(); + } + else + { + // Generate a random image. + image = itkMGHImageIOTestGenerateRandomImage(size); + } + + // Write, then read the 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(image); + + 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 image information. + + reader->GetOutput()->Print(std::cout); + std::cout << std::endl; + + // Compare input and output images. + itk::ImageRegionIterator a(image, image->GetRequestedRegion()); + itk::ImageRegionIterator b(reader->GetOutput(), + reader->GetOutput()->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; + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; +} + +#endif // __itkMGHImageIOTest_h_ diff --git a/Modules/IO/MGHIO/wrapping/CMakeLists.txt b/Modules/IO/MGHIO/wrapping/CMakeLists.txt new file mode 100644 index 000000000000..7dcea8761d17 --- /dev/null +++ b/Modules/IO/MGHIO/wrapping/CMakeLists.txt @@ -0,0 +1,3 @@ +itk_wrap_module(ITKIOMGH) +itk_auto_load_submodules() +itk_end_wrap_module() diff --git a/Modules/IO/MGHIO/wrapping/itkMGHImageIO.wrap b/Modules/IO/MGHIO/wrapping/itkMGHImageIO.wrap new file mode 100644 index 000000000000..e43d19a9a403 --- /dev/null +++ b/Modules/IO/MGHIO/wrapping/itkMGHImageIO.wrap @@ -0,0 +1,2 @@ +itk_wrap_simple_class("itk::MGHImageIO" POINTER) +itk_wrap_simple_class("itk::MGHImageIOFactory" POINTER) From 4f8451abad234bd1bcf7de06f8e9009bd2e7783a Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 1 Jun 2013 13:18:36 -0500 Subject: [PATCH 02/68] STYLE: Useless ITK deprecated define removed. The ITK_EXPORT define was set to nothing and had no known remaining purpose. It was removed to make the over all code easier to understand. There was, understandably, a bit of confusion about the need for this being pervasive in the code. It is currently backwards compatible to have this in code, but at some future point it will be removed. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 99bdc99af1e6..c6ee707f56d3 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -35,7 +35,7 @@ namespace itk * \ingroup IOFilters * \ingroup ITKIOMGH */ -class ITK_EXPORT MGHImageIO:public ImageIOBase +class MGHImageIO:public ImageIOBase { public: /** Standard class typedefs. */ diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index c56478efcff9..827d8347300a 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -27,7 +27,7 @@ namespace itk * \brief Create instances of MGHImageIO objects using an object factory. * \ingroup ITKIOMGH */ -class ITK_EXPORT MGHImageIOFactory : public ObjectFactoryBase +class MGHImageIOFactory : public ObjectFactoryBase { public: /** Standard class typedefs */ From 2dd1b9f116a81f4b8b348da8b4010d6000d6cfba Mon Sep 17 00:00:00 2001 From: Xiaoxiao Liu Date: Mon, 26 Aug 2013 14:14:14 -0400 Subject: [PATCH 03/68] STYLE: Remove "ITK" from the module name. Following the new naming rules for ITK remote modules, the remote module name should not contain the "ITK" prefix. --- Modules/IO/MGHIO/CMakeLists.txt | 4 ++-- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- Modules/IO/MGHIO/itk-module.cmake | 2 +- Modules/IO/MGHIO/src/CMakeLists.txt | 8 ++++---- Modules/IO/MGHIO/test/CMakeLists.txt | 16 ++++++++-------- Modules/IO/MGHIO/wrapping/CMakeLists.txt | 2 +- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index 600f051a6e6d..e0254d3d4fb1 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,3 +1,3 @@ -project(ITKIOMGH) -set(ITKIOMGH_LIBRARIES ITKIOMGH) +project(MGHIO) +set(MGHIO_LIBRARIES MGHIO) itk_module_impl() diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index c6ee707f56d3..6cf5dda0670f 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -33,7 +33,7 @@ namespace itk * package under grants XXXX * * \ingroup IOFilters - * \ingroup ITKIOMGH + * \ingroup MGHIO */ class MGHImageIO:public ImageIOBase { diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 827d8347300a..6b9b6a834918 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -25,7 +25,7 @@ namespace itk { /** \class MGHImageIOFactory * \brief Create instances of MGHImageIO objects using an object factory. - * \ingroup ITKIOMGH + * \ingroup MGHIO */ class MGHImageIOFactory : public ObjectFactoryBase { diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index e7c4ded97d1d..9bcf5646a144 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -1,7 +1,7 @@ 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(ITKIOMGH +itk_module(MGHIO DEPENDS ITKIOImageBase ITKZLIB diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 9edf94c5aad6..f736c45c45f3 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -1,8 +1,8 @@ -set(ITKIOMGH_SRC +set(MGHIO_SRC itkMGHImageIOFactory.cxx itkMGHImageIO.cxx ) -add_library(ITKIOMGH ${ITKIOMGH_SRC}) -target_link_libraries(ITKIOMGH ${ITKMGH_LIBRARIES} ${ITKIOImageBase_LIBRARIES} ${ITKTransform_LIBRARIES}) -itk_module_target(ITKIOMGH) +add_library(MGHIO ${MGHIO_SRC}) +target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKTransform_LIBRARIES}) +itk_module_target(MGHIO) diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index 2a4aa5fcbb5a..a7a05d477b3e 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -1,37 +1,37 @@ itk_module_test() -set(ITKIOMGHTests +set(MGHIOTests itkMGHImageIOTest.cxx ) set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) # For itkMGHImageIOTest.h. -include_directories( ${ITKIOMGH_SOURCE_DIR}/test ) +include_directories( ${MGHIO_SOURCE_DIR}/test ) -CreateTestDriver(ITKIOMGH "${ITKIOMGH-Test_LIBRARIES}" "${ITKIOMGHTests}") +CreateTestDriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") itk_add_test(NAME MGHFactoryCreationTest - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} FactoryCreationTest ) itk_add_test(NAME MGHReadImagesTest_mgz - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} ReadImagesTest DATA{${MGH_DATA_ROOT}/T1.mgz} TEST.mgz ) itk_add_test(NAME MGHReadImagesTest_mgh - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + 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 ITKIOMGHTestDriver itkMGHImageIOTest + 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 ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} TestReadWriteOfSmallImageOfAllTypes ) diff --git a/Modules/IO/MGHIO/wrapping/CMakeLists.txt b/Modules/IO/MGHIO/wrapping/CMakeLists.txt index 7dcea8761d17..c2bacc18dc8e 100644 --- a/Modules/IO/MGHIO/wrapping/CMakeLists.txt +++ b/Modules/IO/MGHIO/wrapping/CMakeLists.txt @@ -1,3 +1,3 @@ -itk_wrap_module(ITKIOMGH) +itk_wrap_module(MGHIO) itk_auto_load_submodules() itk_end_wrap_module() From 11008b5bfc433bf338b6fc4575fe7561df94713b Mon Sep 17 00:00:00 2001 From: Xiaoxiao Liu Date: Mon, 26 Aug 2013 14:55:10 -0400 Subject: [PATCH 04/68] ENH: Remote module is OFF by default. Add "EXCLUDE_FROM_ALL" tag for this remote module. --- Modules/IO/MGHIO/itk-module.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 9bcf5646a144..22e09bf0a867 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -8,6 +8,7 @@ itk_module(MGHIO TEST_DEPENDS ITKTestKernel ITKTransform + EXCLUDE_FROM_ALL DESCRIPTION "${DOCUMENTATION}" ) From 2c9b62a270c054abfd327618d772cfc12ca93acb Mon Sep 17 00:00:00 2001 From: Xiaoxiao Liu Date: Mon, 26 Aug 2013 18:06:20 -0400 Subject: [PATCH 05/68] STYLE: Clean up unnecesssary cmake script. The headers in the test dir can be found without explicitly including the directory. --- Modules/IO/MGHIO/test/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index a7a05d477b3e..ba8ec0ad8743 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -5,9 +5,6 @@ set(MGHIOTests set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) -# For itkMGHImageIOTest.h. -include_directories( ${MGHIO_SOURCE_DIR}/test ) - CreateTestDriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") itk_add_test(NAME MGHFactoryCreationTest From 2331f0d3d76aefd91896e87a605cafdb27e6f285 Mon Sep 17 00:00:00 2001 From: Xiaoxiao Liu Date: Mon, 26 Aug 2013 18:10:49 -0400 Subject: [PATCH 06/68] BUG: Remove ITKTransform dependency. Clean up the module dependency. MGHIO does not depend on ITKTransform. --- Modules/IO/MGHIO/itk-module.cmake | 1 - Modules/IO/MGHIO/src/CMakeLists.txt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 22e09bf0a867..fbdbc6538a06 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -7,7 +7,6 @@ itk_module(MGHIO ITKZLIB TEST_DEPENDS ITKTestKernel - ITKTransform EXCLUDE_FROM_ALL DESCRIPTION "${DOCUMENTATION}" diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index f736c45c45f3..0288e2291154 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -4,5 +4,5 @@ itkMGHImageIO.cxx ) add_library(MGHIO ${MGHIO_SRC}) -target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKTransform_LIBRARIES}) +target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) itk_module_target(MGHIO) From e7d661feed443cfe0f4cf7c6288afffd7b008ac1 Mon Sep 17 00:00:00 2001 From: Xiaoxiao Liu Date: Thu, 12 Sep 2013 10:41:20 -0400 Subject: [PATCH 07/68] FIX: ITK warnings of deprecated EXCLUDE_FROM_ALL. EXCLUDE_FROM_ALL is replaced by EXCLUDE_FROM_DEFAULT in ITK commit:0a98a978509a9536e07c22cde254559cc3c7d417. --- Modules/IO/MGHIO/itk-module.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index fbdbc6538a06..5076141d1b37 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -7,7 +7,7 @@ itk_module(MGHIO ITKZLIB TEST_DEPENDS ITKTestKernel - EXCLUDE_FROM_ALL + EXCLUDE_FROM_DEFAULT DESCRIPTION "${DOCUMENTATION}" ) From 1c9f995bd6471b5091ae70dc8665e62da43732b3 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Fri, 20 Sep 2013 16:02:11 -0500 Subject: [PATCH 08/68] BUG: missing steps converting origin back to freesurfer space --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index b70afefd059a..d3a1b3bc3645 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -650,18 +650,23 @@ ::WriteHeader() this->TWrite(*cit); } - // write c_r, c_a, c_s - // defined as origin + DC x resolution x ( dim0/2 , dim1/2, dim2/2 ) + const float fcx = static_cast(m_Dimensions[0]) / 2.0f; + const float fcy = static_cast(m_Dimensions[1]) / 2.0f; + const float fcz = static_cast(m_Dimensions[2]) / 2.0f; + float c[3]; for( unsigned int ui = 0; ui < 3; ++ui ) { - float crasBuf = m_Origin[ui]; - for( unsigned int uj = 0; uj < 3; ++uj ) - { - crasBuf += vvRas[ui][uj] * m_Spacing[uj] * (float)m_Dimensions[uj] / 2.0f; - } - this->TWrite(crasBuf ); - } // next ui - + c[ui] = m_Origin[ui] + + ( vvRas[ui][0] * m_Spacing[0] * fcx + + vvRas[ui][1] * m_Spacing[1] * fcy + + vvRas[ui][2] * m_Spacing[2] * fcz ); + } + c[0] *= -1.0; + c[1] *= -1.0; + for( unsigned int ui = 0; ui < 3; ++ui ) + { + this->TWrite(c[ui]); + } // fill the rest of the buffer with zeros const char zerobyte(0); for(unsigned int i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) From 8e6f38b19d9f9df8cd90b0132a8500a740648ce7 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Tue, 24 Sep 2013 08:51:19 -0500 Subject: [PATCH 09/68] COMP: Add test for origin writing fix --- Modules/IO/MGHIO/test/CMakeLists.txt | 6 +++ Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 42 +++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index ba8ec0ad8743..a8794a1aca4f 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -32,3 +32,9 @@ itk_add_test(NAME MGHReadImagesTest_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/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 120bb75657db..08b849e18c92 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -110,6 +110,48 @@ int itkMGHImageIOTest(int ac, char* av[]) returnStatus = EXIT_FAILURE; } } + else if( TestMode == "TestOriginWriteTest" ) + { + typedef itk::Image ImageType; + ImageType::Pointer input; + const std::string imageToBeRead(av[3]); + const std::string imageToBeWritten(av[4]); + try + { + std::cout << "Reading Image: " << imageToBeRead << std::endl; + input = itk::IOTestHelper::ReadImage(imageToBeRead); + std::cout << input << std::endl; + + ImageType::PointType origin; + origin[0] = -123.4; + origin[1] = 456.7; + origin[2] = -890.0; + input->SetOrigin(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(); + ImageType::PointType origin2 = new_image->GetOrigin(); + if(origin != origin2) + { + std::cerr << "Origin written and origin read do not match: " + << "written: " << origin + << " read: " << origin2 << std::endl; + returnStatus = EXIT_FAILURE; + } + } + catch (itk::ExceptionObject &e) + { + e.Print(std::cerr); + returnStatus = EXIT_FAILURE; + } + } else { std::cerr << "Invalid TestMode : " << TestMode << std::endl; From 42a2c55ae87c0cf94a82b2c9139666bc6b74b0e3 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Tue, 24 Sep 2013 15:16:38 -0500 Subject: [PATCH 10/68] COMP: fix precision of distance between origins test --- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 08b849e18c92..f334ca98c805 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -29,6 +29,7 @@ #include "itkIOTestHelper.h" #include "itkMGHImageIOTest.h" +#include #define SPECIFIC_IMAGEIO_MODULE_TEST @@ -138,11 +139,14 @@ int itkMGHImageIOTest(int ac, char* av[]) testFactoryReader->Update(); ImageType::Pointer new_image = testFactoryReader->GetOutput(); ImageType::PointType origin2 = new_image->GetOrigin(); - if(origin != origin2) + double dist = origin.EuclideanDistanceTo(origin2); + if(dist > 1.0E-4) { - std::cerr << "Origin written and origin read do not match: " + std::cerr << std::setprecision(10) + << "Origin written and origin read do not match: " << "written: " << origin - << " read: " << origin2 << std::endl; + << " read: " << origin2 << " distance: " + << dist << std::endl; returnStatus = EXIT_FAILURE; } } From a3a39c5df9823e33a605a4886ad73bb6cbae6a54 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Wed, 25 Sep 2013 11:13:27 -0500 Subject: [PATCH 11/68] BUG: refine CanReadFile in MGHImageIO existing logic couldn't handle filenames with a dot before the filename extension. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 42 +++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index d3a1b3bc3645..0c153cbc2064 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -106,8 +106,37 @@ bool MGHImageIO ::IsCompressedFilename(const std::string fname) { - const std::string extension = itksys::SystemTools::GetFilenameExtension(fname.c_str()); - return extension == __MGZ_EXT || extension == __GZ_EXT || extension == __MGHGZ_EXT; + // this is actually working logic that searches for + // extensions ".mgz", ".gz", and ".mgh.gz" + // + // There's something wrong with this logic, since it in + // effect will say it can read ANY gzipped files, but since there's + // no unique file signature in a MGH file were're kind of stuck. + if(fname.size() >= 7) + { + std::string last7chars = fname.substr(fname.size() - 7,7); + if(last7chars == __MGHGZ_EXT) + { + return true; + } + else + { + std::string last4chars = fname.substr(fname.size() - 4, 4); + if(last4chars == __MGZ_EXT) + { + return true; + } + else + { + std::string last3chars = fname.substr(fname.size() - 3,3); + if(last3chars == __GZ_EXT) + { + return true ; + } + } + } + } + return false; } bool @@ -123,10 +152,13 @@ ::CanReadFile(const char* FileNameToRead) } // check if the correct extension is given by the user - const std::string extension = itksys::SystemTools::GetFilenameExtension(filename.c_str()); - if( extension == __MGH_EXT || this->IsCompressedFilename(filename) ) + if(filename.size() > 4) { - return true; + const std::string extension = filename.substr(filename.size() - 4,4); + if( extension == __MGH_EXT || this->IsCompressedFilename(filename) ) + { + return true; + } } return false; } From 536599b2aa4bb6430fe110ff26b88bb7480c42b4 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Wed, 25 Sep 2013 11:58:12 -0500 Subject: [PATCH 12/68] BUG: as;dlfkj --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 35 ++++++-------------------- 1 file changed, 7 insertions(+), 28 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 0c153cbc2064..a091a089bc89 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -112,29 +112,11 @@ ::IsCompressedFilename(const std::string fname) // There's something wrong with this logic, since it in // effect will say it can read ANY gzipped files, but since there's // no unique file signature in a MGH file were're kind of stuck. - if(fname.size() >= 7) +/// Since both ".gz" and ".mgh.gz" are valid extension, checking for ".gz" is sufficient. + const std::string lastExtension = itksys::SystemTools::GetFilenameLastExtension(fname.c_str()); + if(lastExtension == __MGZ_EXT || lastExtension == __GZ_EXT) { - std::string last7chars = fname.substr(fname.size() - 7,7); - if(last7chars == __MGHGZ_EXT) - { - return true; - } - else - { - std::string last4chars = fname.substr(fname.size() - 4, 4); - if(last4chars == __MGZ_EXT) - { - return true; - } - else - { - std::string last3chars = fname.substr(fname.size() - 3,3); - if(last3chars == __GZ_EXT) - { - return true ; - } - } - } + return true; } return false; } @@ -152,13 +134,10 @@ ::CanReadFile(const char* FileNameToRead) } // check if the correct extension is given by the user - if(filename.size() > 4) + const std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename.c_str()); + if( extension == __MGH_EXT || this->IsCompressedFilename(filename) ) { - const std::string extension = filename.substr(filename.size() - 4,4); - if( extension == __MGH_EXT || this->IsCompressedFilename(filename) ) - { - return true; - } + return true; } return false; } From d7e184c1451d2020bc52b933c6ae67ba94af39ce Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Wed, 25 Sep 2013 11:13:27 -0500 Subject: [PATCH 13/68] BUG: refine CanReadFile in MGHImageIO existing logic couldn't handle filenames with a dot before the filename extension. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index d3a1b3bc3645..a091a089bc89 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -106,8 +106,19 @@ bool MGHImageIO ::IsCompressedFilename(const std::string fname) { - const std::string extension = itksys::SystemTools::GetFilenameExtension(fname.c_str()); - return extension == __MGZ_EXT || extension == __GZ_EXT || extension == __MGHGZ_EXT; + // this is actually working logic that searches for + // extensions ".mgz", ".gz", and ".mgh.gz" + // + // There's something wrong with this logic, since it in + // effect will say it can read ANY gzipped files, but since there's + // no unique file signature in a MGH file were're kind of stuck. +/// Since both ".gz" and ".mgh.gz" are valid extension, checking for ".gz" is sufficient. + const std::string lastExtension = itksys::SystemTools::GetFilenameLastExtension(fname.c_str()); + if(lastExtension == __MGZ_EXT || lastExtension == __GZ_EXT) + { + return true; + } + return false; } bool @@ -123,7 +134,7 @@ ::CanReadFile(const char* FileNameToRead) } // check if the correct extension is given by the user - const std::string extension = itksys::SystemTools::GetFilenameExtension(filename.c_str()); + const std::string extension = itksys::SystemTools::GetFilenameLastExtension(filename.c_str()); if( extension == __MGH_EXT || this->IsCompressedFilename(filename) ) { return true; From aa33defa3cca29df9a0b961be3c4eac5295678f6 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Wed, 2 Oct 2013 09:30:10 -0500 Subject: [PATCH 14/68] COMP: Disallow '.gz' extension --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index a091a089bc89..a7edf5c41832 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -27,7 +27,6 @@ namespace itk static const std::string __MGH_EXT(".mgh"); static const std::string __MGZ_EXT(".mgz"); static const std::string __GZ_EXT(".gz"); -static const std::string __MGHGZ_EXT(".mgh.gz"); // ------------------------------- @@ -114,10 +113,21 @@ ::IsCompressedFilename(const std::string fname) // no unique file signature in a MGH file were're kind of stuck. /// Since both ".gz" and ".mgh.gz" are valid extension, checking for ".gz" is sufficient. const std::string lastExtension = itksys::SystemTools::GetFilenameLastExtension(fname.c_str()); - if(lastExtension == __MGZ_EXT || lastExtension == __GZ_EXT) + 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; } From de832fdf8696da35676433505837b632c32e21b7 Mon Sep 17 00:00:00 2001 From: chaircrusher Date: Wed, 2 Oct 2013 09:54:03 -0500 Subject: [PATCH 15/68] DOC: fix comment --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index a7edf5c41832..27de3b4f4edd 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -105,13 +105,16 @@ bool MGHImageIO ::IsCompressedFilename(const std::string fname) { - // this is actually working logic that searches for - // extensions ".mgz", ".gz", and ".mgh.gz" // - // There's something wrong with this logic, since it in - // effect will say it can read ANY gzipped files, but since there's - // no unique file signature in a MGH file were're kind of stuck. -/// Since both ".gz" and ".mgh.gz" are valid extension, checking for ".gz" is sufficient. + // 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) { From f30929e0ba034ab410b605cc97c8a9b433bed72c Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 31 Jan 2014 15:05:00 -0600 Subject: [PATCH 16/68] BUG: Valgrind memory leak. The dynamically allocated variable must be deleted in the destructor. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 6 +++--- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 15 +++++++-------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 6cf5dda0670f..936d8e4e09f9 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -117,9 +117,9 @@ class MGHImageIO:public ImageIOBase std::string GetOrientation( itk::Matrix directions ); - bool m_IsCompressed; - gzFile m_GZFile; - std::ofstream *m_Output; + bool m_IsCompressed; + gzFile m_GZFile; + std::ofstream m_Output; template int TWrite(T out); template int TRead(T &out); diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 27de3b4f4edd..9b453f104fae 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -57,8 +57,8 @@ ::TWrite(T out) } else { - this->m_Output->write(reinterpret_cast(&out),sizeof(T)); - return this->m_Output->good() ? sizeof(T) : 0; + this->m_Output.write(reinterpret_cast(&out),sizeof(T)); + return this->m_Output.good() ? sizeof(T) : 0; } } @@ -77,8 +77,8 @@ ::TWrite(const char *buf,unsigned long count) } else { - this->m_Output->write(buf,count); - return this->m_Output->good() ? count : 0; + this->m_Output.write(buf,count); + return this->m_Output.good() ? count : 0; } } // -------------------------------------- @@ -545,9 +545,8 @@ ::OpenFile() } else { - this->m_Output = new std::ofstream; - this->m_Output->open(m_FileName.c_str(), std::ios::out | std::ios::binary ); - if( this->m_Output->fail() ) + this->m_Output.open(m_FileName.c_str(), std::ios::out | std::ios::binary ); + if( this->m_Output.fail() ) { itkExceptionMacro(<< " File cannot be written"); } @@ -563,7 +562,7 @@ ::CloseFile() } else { - this->m_Output->close(); + this->m_Output.close(); } } void From 82997aef51cf962610823f6a85af272fe5f7ddf5 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Tue, 31 Mar 2015 15:55:03 -0400 Subject: [PATCH 17/68] BUG: Fix KWStyle error for header guarder Remove usage of reserved "__" prefix. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 6 +++--- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 936d8e4e09f9..c767dd300b26 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -15,8 +15,8 @@ * limitations under the License. * *=========================================================================*/ -#ifndef __itkMGHImageIO_h -#define __itkMGHImageIO_h +#ifndef itkMGHImageIO_h +#define itkMGHImageIO_h #include "itkMatrix.h" #include "itkImageIOBase.h" @@ -130,4 +130,4 @@ class MGHImageIO:public ImageIOBase }; } // end namespace itk -#endif // __itkMGHImageIO_h +#endif // itkMGHImageIO_h diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 6b9b6a834918..01e1e06a26ad 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -15,8 +15,8 @@ * limitations under the License. * *=========================================================================*/ -#ifndef __itkMGHImageIOFactory_h -#define __itkMGHImageIOFactory_h +#ifndef itkMGHImageIOFactory_h +#define itkMGHImageIOFactory_h #include "itkObjectFactoryBase.h" #include "itkImageIOBase.h" @@ -66,4 +66,4 @@ class MGHImageIOFactory : public ObjectFactoryBase }; } // end namespace itk -#endif /// __itkMGHImageIOFactory_h +#endif /// itkMGHImageIOFactory_h From 66abfdcaab4052873d022365ea0b6aad7dd678b2 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Tue, 9 Jun 2015 13:37:10 -0500 Subject: [PATCH 18/68] ENH: Add ITK_OVERRIDE and ITK_NULLPTR designations To be consistent with ITK, ITK_OVERRIDE and ITK_NULLPTR are added. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 16 ++++++++-------- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 6 +++--- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 2 +- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 4 ---- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 2 +- 5 files changed, 13 insertions(+), 17 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index c767dd300b26..2fe04bab8ef2 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -56,13 +56,13 @@ class MGHImageIO:public ImageIOBase * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite * \return Returns true if this ImageIO can read the file specified. */ - virtual bool CanReadFile(const char *FileNameToRead); + virtual bool CanReadFile(const char *FileNameToRead) ITK_OVERRIDE; /** Set the spacing and dimension information for the set filename. */ - virtual void ReadImageInformation(); + virtual void ReadImageInformation() ITK_OVERRIDE; /** Reads the data from disk into the memory buffer provided. */ - virtual void Read(void *buffer); + virtual void Read(void *buffer) ITK_OVERRIDE; /*-------- This part of the interfaces deals with writing data. ----- */ @@ -71,19 +71,19 @@ class MGHImageIO:public ImageIOBase * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite * \return Returns true if this ImageIO can write the file specified. */ - virtual bool CanWriteFile(const char *FileNameToWrite); + virtual bool CanWriteFile(const char *FileNameToWrite) ITK_OVERRIDE; /** Set the spacing and dimension information for the set filename. */ - virtual void WriteImageInformation(); + virtual void WriteImageInformation() ITK_OVERRIDE; /** Writes the data to disk from the memory buffer provided. Make sure * that the IORegions has been set properly. */ - virtual void Write(const void *buffer); + virtual void Write(const void *buffer) ITK_OVERRIDE; protected: MGHImageIO(); ~MGHImageIO(); - void PrintSelf(std::ostream& os, Indent indent) const; + void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; void ReadVolumeHeader(); @@ -113,7 +113,7 @@ class MGHImageIO:public ImageIOBase void PermuteFrameValues(const void* buffer, char* tempmemory); - unsigned int GetComponentSize() const; + unsigned int GetComponentSize() const ITK_OVERRIDE; std::string GetOrientation( itk::Matrix directions ); diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 01e1e06a26ad..6b27760b8b3b 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -37,9 +37,9 @@ class MGHImageIOFactory : public ObjectFactoryBase typedef SmartPointer ConstPointer; /** Class methods used to interface with the registered factories **/ - virtual const char * GetITKSourceVersion(void) const; + virtual const char * GetITKSourceVersion(void) const ITK_OVERRIDE; - virtual const char * GetDescription(void) const; + virtual const char * GetDescription(void) const ITK_OVERRIDE; /** Method for class instantiation **/ itkFactorylessNewMacro(Self); @@ -58,7 +58,7 @@ class MGHImageIOFactory : public ObjectFactoryBase protected: MGHImageIOFactory(); ~MGHImageIOFactory(); - virtual void PrintSelf(std::ostream & os, Indent indent) const; + virtual void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; private: MGHImageIOFactory(const Self &); //purposely not implemented diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 9b453f104fae..d662a695b858 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -537,7 +537,7 @@ ::OpenFile() if(this->m_IsCompressed) { this->m_GZFile = gzopen(m_FileName.c_str(), "wb"); - if( this->m_GZFile == 0 ) + if( this->m_GZFile == ITK_NULLPTR ) { itkExceptionMacro(<< " Failed to open gzFile for writing"); itkExceptionMacro(<< " File cannot be written"); diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index f334ca98c805..7b0df9370905 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -17,14 +17,10 @@ *=========================================================================*/ #include "itkMGHImageIOFactory.h" -#include "itkMGHImageIO.h" #include "itkRandomImageSource.h" -#include "itkImage.h" #include "itkImageFileReader.h" -#include "itkImageFileWriter.h" #include "itksys/SystemTools.hxx" #include "itkMetaDataObject.h" -#include "itkDiffusionTensor3D.h" #include "itkIOCommon.h" #include "itkIOTestHelper.h" diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index b3e88c99a69a..95f36b96680c 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -226,4 +226,4 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, return EXIT_SUCCESS; } -#endif // __itkMGHImageIOTest_h_ +#endif //itkMGHImageIOTest_h_ From c801047ee3e001c833cc5ab52a04bd1b1a42cd5f Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 9 Jul 2015 08:10:43 -0500 Subject: [PATCH 19/68] BUG: Fix KWStyle error for header guarderd in test Remove usage of reserved "__" prefix. The test header needed to have the __prefix removed. --- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 95f36b96680c..88e288900ff3 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -15,8 +15,8 @@ * limitations under the License. * *=========================================================================*/ -#ifndef __itkMGHImageIOTest_h -#define __itkMGHImageIOTest_h +#ifndef itkMGHImageIOTest_h +#define itkMGHImageIOTest_h #include #include From 76164153f00113de628eeb9e547d1cfd44990138 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 10 Jul 2015 05:45:40 -0500 Subject: [PATCH 20/68] STYLE: Use ITK naming conventions for MGHIO. Convert MGHIO to ITKIOMGH to conform to the ITK naming conventions for IO modules. This places the MGH IO for images with other IO modules in the cmake system, and automatically identifies it as needing to be registered. --- Modules/IO/MGHIO/CMakeLists.txt | 4 ++-- Modules/IO/MGHIO/include/itkMGHImageIO.h | 6 ++++-- .../IO/MGHIO/include/itkMGHImageIOFactory.h | 5 +++-- Modules/IO/MGHIO/itk-module.cmake | 3 ++- Modules/IO/MGHIO/src/CMakeLists.txt | 8 ++++---- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 2 +- Modules/IO/MGHIO/test/CMakeLists.txt | 20 +++++++++---------- Modules/IO/MGHIO/wrapping/CMakeLists.txt | 2 +- 8 files changed, 27 insertions(+), 23 deletions(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index e0254d3d4fb1..600f051a6e6d 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,3 +1,3 @@ -project(MGHIO) -set(MGHIO_LIBRARIES MGHIO) +project(ITKIOMGH) +set(ITKIOMGH_LIBRARIES ITKIOMGH) itk_module_impl() diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 2fe04bab8ef2..39991c8d5ba7 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -23,6 +23,8 @@ #include #include "itk_zlib.h" +#include "ITKIOMGHExport.h" + namespace itk { /** \class MGHImageIO @@ -33,9 +35,9 @@ namespace itk * package under grants XXXX * * \ingroup IOFilters - * \ingroup MGHIO + * \ingroup ITKIOMGH */ -class MGHImageIO:public ImageIOBase +class ITKIOMGH_EXPORT MGHImageIO:public ImageIOBase { public: /** Standard class typedefs. */ diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 6b27760b8b3b..3227700aaf5c 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -20,14 +20,15 @@ #include "itkObjectFactoryBase.h" #include "itkImageIOBase.h" +#include "ITKIOMGHExport.h" namespace itk { /** \class MGHImageIOFactory * \brief Create instances of MGHImageIO objects using an object factory. - * \ingroup MGHIO + * \ingroup ITKIOMGH */ -class MGHImageIOFactory : public ObjectFactoryBase +class ITKIOMGH_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: /** Standard class typedefs */ diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 5076141d1b37..162c774099ce 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -1,7 +1,8 @@ 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 +itk_module(ITKIOMGH + ENABLE_SHARED DEPENDS ITKIOImageBase ITKZLIB diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 0288e2291154..2d98ac9e2b29 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -1,8 +1,8 @@ -set(MGHIO_SRC +set(ITKIOMGH_SRC itkMGHImageIOFactory.cxx itkMGHImageIO.cxx ) -add_library(MGHIO ${MGHIO_SRC}) -target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) -itk_module_target(MGHIO) +add_library(ITKIOMGH ${ITKIOMGH_SRC}) +target_link_libraries(ITKIOMGH ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) +itk_module_target(ITKIOMGH) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 844419de5474..ba39d51c839a 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -52,7 +52,7 @@ MGHImageIOFactory::GetDescription() const static bool MGHImageIOFactoryHasBeenRegistered=false; -void MGHImageIOFactoryRegister__Private(void) +void ITKIOMGH_EXPORT MGHImageIOFactoryRegister__Private(void) { if( ! MGHImageIOFactoryHasBeenRegistered ) { diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index a8794a1aca4f..234b709bb576 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -1,39 +1,39 @@ itk_module_test() -set(MGHIOTests +set(ITKIOMGHTests itkMGHImageIOTest.cxx ) set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) -CreateTestDriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") +CreateTestDriver(ITKIOMGH "${ITKIOMGH-Test_LIBRARIES}" "${ITKIOMGHTests}") itk_add_test(NAME MGHFactoryCreationTest - COMMAND MGHIOTestDriver itkMGHImageIOTest + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} FactoryCreationTest ) itk_add_test(NAME MGHReadImagesTest_mgz - COMMAND MGHIOTestDriver itkMGHImageIOTest + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} ReadImagesTest DATA{${MGH_DATA_ROOT}/T1.mgz} TEST.mgz ) itk_add_test(NAME MGHReadImagesTest_mgh - COMMAND MGHIOTestDriver itkMGHImageIOTest + COMMAND ITKIOMGHTestDriver 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 + COMMAND ITKIOMGHTestDriver 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_add_test(NAME itkITKIOMGHInternalTests + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} TestReadWriteOfSmallImageOfAllTypes ) -itk_add_test(NAME itkMGHIOOriginTest - COMMAND MGHIOTestDriver itkMGHImageIOTest +itk_add_test(NAME itkITKIOMGHOriginTest + COMMAND ITKIOMGHTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} TestOriginWriteTest DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} OriginTEST.mgh.gz ) diff --git a/Modules/IO/MGHIO/wrapping/CMakeLists.txt b/Modules/IO/MGHIO/wrapping/CMakeLists.txt index c2bacc18dc8e..7dcea8761d17 100644 --- a/Modules/IO/MGHIO/wrapping/CMakeLists.txt +++ b/Modules/IO/MGHIO/wrapping/CMakeLists.txt @@ -1,3 +1,3 @@ -itk_wrap_module(MGHIO) +itk_wrap_module(ITKIOMGH) itk_auto_load_submodules() itk_end_wrap_module() From ce578aa4bb317a1c4c3247a7200524c48fd27fbd Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sun, 12 Jul 2015 09:39:24 -0500 Subject: [PATCH 21/68] STYLE: Revert Use ITK naming conventions for MGHIO After discussion with ITK team, it was determined that the convention was mis-interpreted in the previous patch. Internal and Remote IO modules have different naming conventions. Since MGHIO is still an external IO library, it should not use the internal IO naming conventions. This reverts commit 76164153f00113de628eeb9e547d1cfd44990138. --- Modules/IO/MGHIO/CMakeLists.txt | 4 ++-- Modules/IO/MGHIO/include/itkMGHImageIO.h | 6 ++---- .../IO/MGHIO/include/itkMGHImageIOFactory.h | 5 ++--- Modules/IO/MGHIO/itk-module.cmake | 3 +-- Modules/IO/MGHIO/src/CMakeLists.txt | 8 ++++---- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 2 +- Modules/IO/MGHIO/test/CMakeLists.txt | 20 +++++++++---------- Modules/IO/MGHIO/wrapping/CMakeLists.txt | 2 +- 8 files changed, 23 insertions(+), 27 deletions(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index 600f051a6e6d..e0254d3d4fb1 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,3 +1,3 @@ -project(ITKIOMGH) -set(ITKIOMGH_LIBRARIES ITKIOMGH) +project(MGHIO) +set(MGHIO_LIBRARIES MGHIO) itk_module_impl() diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 39991c8d5ba7..2fe04bab8ef2 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -23,8 +23,6 @@ #include #include "itk_zlib.h" -#include "ITKIOMGHExport.h" - namespace itk { /** \class MGHImageIO @@ -35,9 +33,9 @@ namespace itk * package under grants XXXX * * \ingroup IOFilters - * \ingroup ITKIOMGH + * \ingroup MGHIO */ -class ITKIOMGH_EXPORT MGHImageIO:public ImageIOBase +class MGHImageIO:public ImageIOBase { public: /** Standard class typedefs. */ diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 3227700aaf5c..6b27760b8b3b 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -20,15 +20,14 @@ #include "itkObjectFactoryBase.h" #include "itkImageIOBase.h" -#include "ITKIOMGHExport.h" namespace itk { /** \class MGHImageIOFactory * \brief Create instances of MGHImageIO objects using an object factory. - * \ingroup ITKIOMGH + * \ingroup MGHIO */ -class ITKIOMGH_EXPORT MGHImageIOFactory : public ObjectFactoryBase +class MGHImageIOFactory : public ObjectFactoryBase { public: /** Standard class typedefs */ diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 162c774099ce..5076141d1b37 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -1,8 +1,7 @@ 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(ITKIOMGH - ENABLE_SHARED +itk_module(MGHIO DEPENDS ITKIOImageBase ITKZLIB diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 2d98ac9e2b29..0288e2291154 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -1,8 +1,8 @@ -set(ITKIOMGH_SRC +set(MGHIO_SRC itkMGHImageIOFactory.cxx itkMGHImageIO.cxx ) -add_library(ITKIOMGH ${ITKIOMGH_SRC}) -target_link_libraries(ITKIOMGH ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) -itk_module_target(ITKIOMGH) +add_library(MGHIO ${MGHIO_SRC}) +target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) +itk_module_target(MGHIO) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index ba39d51c839a..844419de5474 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -52,7 +52,7 @@ MGHImageIOFactory::GetDescription() const static bool MGHImageIOFactoryHasBeenRegistered=false; -void ITKIOMGH_EXPORT MGHImageIOFactoryRegister__Private(void) +void MGHImageIOFactoryRegister__Private(void) { if( ! MGHImageIOFactoryHasBeenRegistered ) { diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index 234b709bb576..a8794a1aca4f 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -1,39 +1,39 @@ itk_module_test() -set(ITKIOMGHTests +set(MGHIOTests itkMGHImageIOTest.cxx ) set(MGH_DATA_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/MD5) -CreateTestDriver(ITKIOMGH "${ITKIOMGH-Test_LIBRARIES}" "${ITKIOMGHTests}") +CreateTestDriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") itk_add_test(NAME MGHFactoryCreationTest - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} FactoryCreationTest ) itk_add_test(NAME MGHReadImagesTest_mgz - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} ReadImagesTest DATA{${MGH_DATA_ROOT}/T1.mgz} TEST.mgz ) itk_add_test(NAME MGHReadImagesTest_mgh - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest + 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 ITKIOMGHTestDriver itkMGHImageIOTest + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} ReadImagesTest DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} TEST.mgh.gz ) -itk_add_test(NAME itkITKIOMGHInternalTests - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest +itk_add_test(NAME itkMGHIOInternalTests + COMMAND MGHIOTestDriver itkMGHImageIOTest ${ITK_TEST_OUTPUT_DIR} TestReadWriteOfSmallImageOfAllTypes ) -itk_add_test(NAME itkITKIOMGHOriginTest - COMMAND ITKIOMGHTestDriver itkMGHImageIOTest +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/Modules/IO/MGHIO/wrapping/CMakeLists.txt b/Modules/IO/MGHIO/wrapping/CMakeLists.txt index 7dcea8761d17..c2bacc18dc8e 100644 --- a/Modules/IO/MGHIO/wrapping/CMakeLists.txt +++ b/Modules/IO/MGHIO/wrapping/CMakeLists.txt @@ -1,3 +1,3 @@ -itk_wrap_module(ITKIOMGH) +itk_wrap_module(MGHIO) itk_auto_load_submodules() itk_end_wrap_module() From f69071ea8694e55ee417ed5f054bd9dc024e2bfa Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sun, 12 Jul 2015 10:05:24 -0500 Subject: [PATCH 22/68] COMP: Make MGHIO a shared libary Make the MGHIO module a shared library like the other IO modules. ctest -R MGH 1/14 Test #810: ITKIOMGHInDoxygenGroup ........... Passed 0.05 sec 2/14 Test #811: MGHFactoryCreationTest ........... Passed 0.09 sec 3/14 Test #812: MGHReadImagesTest_mgz ............ Passed 4.23 sec 4/14 Test #813: MGHReadImagesTest_mgh ............ Passed 0.68 sec 5/14 Test #814: MGHReadImagesTest_mgh.gz ......... Passed 4.11 sec 6/14 Test #815: itkITKIOMGHInternalTests ......... Passed 0.08 sec 7/14 Test #816: itkITKIOMGHOriginTest ............ Passed 4.16 sec 8/14 Test #2356: MGHIOInDoxygenGroup .............. Passed 0.04 sec 9/14 Test #2357: MGHFactoryCreationTest ........... Passed 0.07 sec 10/14 Test #2358: MGHReadImagesTest_mgz ............ Passed 4.23 sec 11/14 Test #2359: MGHReadImagesTest_mgh ............ Passed 0.68 sec 12/14 Test #2360: MGHReadImagesTest_mgh.gz ......... Passed 4.13 sec 13/14 Test #2361: itkMGHIOInternalTests ............ Passed 0.07 sec 14/14 Test #2362: itkMGHIOOriginTest ............... Passed 4.13 sec 100% tests passed, 0 tests failed out of 14 --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 4 +++- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 4 +++- Modules/IO/MGHIO/itk-module.cmake | 1 + Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 3 ++- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 2fe04bab8ef2..dc80d24745e3 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -23,6 +23,8 @@ #include #include "itk_zlib.h" +#include "MGHIOExport.h" + namespace itk { /** \class MGHImageIO @@ -35,7 +37,7 @@ namespace itk * \ingroup IOFilters * \ingroup MGHIO */ -class MGHImageIO:public ImageIOBase +class MGHIO_EXPORT MGHImageIO:public ImageIOBase { public: /** Standard class typedefs. */ diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 6b27760b8b3b..2a86d7cd5cee 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -21,13 +21,15 @@ #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 MGHImageIOFactory : public ObjectFactoryBase +class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: /** Standard class typedefs */ diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 5076141d1b37..4315d78d5ed7 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -2,6 +2,7 @@ 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 diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 844419de5474..9088649f3f9a 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -19,6 +19,7 @@ #include "itkMGHImageIO.h" #include "itkVersion.h" + namespace itk { void MGHImageIOFactory::PrintSelf(std::ostream &, Indent) const @@ -52,7 +53,7 @@ MGHImageIOFactory::GetDescription() const static bool MGHImageIOFactoryHasBeenRegistered=false; -void MGHImageIOFactoryRegister__Private(void) +void MGHIO_EXPORT MGHImageIOFactoryRegister__Private(void) { if( ! MGHImageIOFactoryHasBeenRegistered ) { From 21100ef67464e98b75ec3032dbf3e0b0de5a3aa7 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 09:15:29 -0500 Subject: [PATCH 23/68] BUG: Test case was not verifying meta-data The test cases used determined that all pixel values were the same, but did not check that the image meta-data was preserved during writing! The tests have been improved to demonstrate that a bug has existed in the MGHIO writer for a very long time. If the DirectionCosine = Transpose(DirectionCosine) then there was not problem. A future patch will address the bug. --- Modules/IO/MGHIO/itk-module.cmake | 1 + Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 11 +- Modules/IO/MGHIO/test/CMakeLists.txt | 5 + Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 27 ++-- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 142 ++++++++++++++++---- 5 files changed, 136 insertions(+), 50 deletions(-) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 4315d78d5ed7..165569bfeed4 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -8,6 +8,7 @@ itk_module(MGHIO ITKZLIB TEST_DEPENDS ITKTestKernel + ITKTransform EXCLUDE_FROM_DEFAULT DESCRIPTION "${DOCUMENTATION}" diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index d662a695b858..605439e794e2 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -291,7 +291,7 @@ ::ReadVolumeHeader() z_r z_a z_s c_r c_a c_s */ - typedef itk::Matrix MatrixType; + typedef itk::Matrix MatrixType; MatrixType matrix; // 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: @@ -308,7 +308,7 @@ ::ReadVolumeHeader() // std::cout << "itkMGHImageIO ReadVolumeHeader: matrix[" << ui << "][" << uj << "] = " << matrix[ui][uj] << "\n"; } } - float c[3]; + float c[3]; //c_r c_a c_s for( unsigned int ui = 0; ui < 3; ++ui ) { this->TRead( c[ui]); @@ -337,12 +337,12 @@ ::ReadVolumeHeader() // MriDirCos(); // convert direction cosines // finally, store the origin of the image -> only works - // if the image is properly orriented in the sequel + // if the image is properly oriented in the sequel // // computed in CORONAL orientation = ITK_COORDINATE_ORIENTATION_LIA // convert C to from RAS to LPS - c[0] *= -1; - c[1] *= -1; + c[0] *= -1; //R->L + c[1] *= -1; //A->P const float fcx = static_cast(m_Dimensions[0]) / 2.0f; const float fcy = static_cast(m_Dimensions[1]) / 2.0f; const float fcz = static_cast(m_Dimensions[2]) / 2.0f; @@ -353,7 +353,6 @@ ::ReadVolumeHeader() + matrix[ui][1] * m_Spacing[1] * fcy + matrix[ui][2] * m_Spacing[2] * fcz ); } - } // ================== diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index a8794a1aca4f..679152bafb8a 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -38,3 +38,8 @@ itk_add_test(NAME itkMGHIOOriginTest DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} OriginTEST.mgh.gz ) + + +# "/Users/johnsonhj/Dropbox/DATA/wmparc_acpc_ref.mgz" +# "/Users/johnsonhj/Dropbox/DATA/wmparc_acpc_ref.nii.gz" + diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 7b0df9370905..28f06a8c4ff6 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -27,9 +27,6 @@ #include "itkMGHImageIOTest.h" #include -#define SPECIFIC_IMAGEIO_MODULE_TEST - - int itkMGHImageIOTest(int ac, char* av[]) { itk::ObjectFactoryBase::UnRegisterAllFactories(); @@ -70,6 +67,7 @@ int itkMGHImageIOTest(int ac, char* av[]) else if ( TestMode == std::string("TestReadWriteOfSmallImageOfAllTypes")) { std::string fn("test.mgz"); + //TODO: Need to test with images of non-identity direction cosigns, spacing, origin if( ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && @@ -78,21 +76,18 @@ int itkMGHImageIOTest(int ac, char* av[]) { returnStatus = EXIT_SUCCESS; } - //TODO: Need to test with images of non-identity direction cosigns, spacing, origin } else if( TestMode == std::string("ReadImagesTest") ) //This is a mechanism for reading unsigned int images for testing. { typedef itk::Image ImageType; - ImageType::Pointer input; const std::string imageToBeRead(av[3]); const std::string imageToBeWritten(av[4]); try { std::cout << "Reading Image: " << imageToBeRead << std::endl; - input = itk::IOTestHelper::ReadImage(imageToBeRead); + 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(); @@ -119,11 +114,11 @@ int itkMGHImageIOTest(int ac, char* av[]) input = itk::IOTestHelper::ReadImage(imageToBeRead); std::cout << input << std::endl; - ImageType::PointType origin; - origin[0] = -123.4; - origin[1] = 456.7; - origin[2] = -890.0; - input->SetOrigin(origin); + 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(); @@ -134,14 +129,14 @@ int itkMGHImageIOTest(int ac, char* av[]) testFactoryReader->SetFileName(imageToBeWritten); testFactoryReader->Update(); ImageType::Pointer new_image = testFactoryReader->GetOutput(); - ImageType::PointType origin2 = new_image->GetOrigin(); - double dist = origin.EuclideanDistanceTo(origin2); + 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: " << origin - << " read: " << origin2 << " distance: " + << "written: " << reference_origin + << " read: " << test_origin << " distance: " << dist << std::endl; returnStatus = EXIT_FAILURE; } diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 88e288900ff3..8d55b4d09741 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -20,6 +20,7 @@ #include #include +#include #include "itkImageRegionIterator.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" @@ -29,31 +30,70 @@ #include "itkRandomImageSource.h" #include "itkDiffusionTensor3D.h" +#include "itkEuler3DTransform.h" + template typename itk::Image::Pointer -itkMGHImageIOTestGenerateRandomImage(unsigned int size) +itkMGHImageIOTestGenerateRandomImage(const unsigned int size) { + + typedef itk::Euler3DTransform EulerTransformType; + 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); + typedef itk::Image ImageType; - const double dir1[3] = { 0, -1, 0 }; - const double dir2[3] = { 1, 0, 0 }; - const double dir3[3] = { 0, 0, -1 }; + 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; - direction.GetVnlMatrix().set_column(0,dir1); - direction.GetVnlMatrix().set_column(1,dir2); - direction.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++) + + for (unsigned int i = 0; i < VImageDimension; ++i) { sz[i] = size; - spacing[i] = static_cast(i+1); - origin[i] = static_cast(i); + spacing[i] = static_cast(i+1.234567); + origin[i] = static_cast(1234.5); } +#if 0 + //Make origin match numerical precision of MGH file + const double fcx = sz[0] * 0.5; + const double fcy = sz[1] * 0.5; + const double fcz = sz[2] * 0.5; + for( size_t ui = 0; ui < 3; ++ui ) + { + origin[ui] = origin[ui] + + ( direction[ui][0] * spacing[0] * fcx + + direction[ui][1] * spacing[1] * fcy + + direction[ui][2] * spacing[2] * fcz ); + } +#endif + typename itk::RandomImageSource::Pointer source = itk::RandomImageSource::New(); @@ -140,7 +180,7 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, reader->SetImageIO(io); writer->SetImageIO(io); - typename ImageType::Pointer image; + typename ImageType::Pointer reference_image; if (inputFile != "null") { @@ -158,16 +198,15 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, std::cerr << e << std::endl; return EXIT_FAILURE; } - - image = tmpReader->GetOutput(); + reference_image = tmpReader->GetOutput(); } else { - // Generate a random image. - image = itkMGHImageIOTestGenerateRandomImage(size); + // Generate a random reference_image. + reference_image = itkMGHImageIOTestGenerateRandomImage(size); } - // Write, then read the image. + // Write, then read the reference_image. try { writer->SetFileName(fn.c_str()); @@ -178,7 +217,6 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, reader->SetFileName(fn.c_str()); //writer->SetFileName("testDebug.mhd"); //reader->SetFileName("testDebug.mhd"); - } catch(itk::ExceptionObject &e) { @@ -186,9 +224,8 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, return EXIT_FAILURE; } - writer->SetInput(image); - - image->Print(std::cout); + writer->SetInput(reference_image); + reference_image->Print(std::cout); std::cout << "----------" << std::endl; try @@ -206,24 +243,73 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, return EXIT_FAILURE; } - // Print the image information. + // Print the reference_image information. - reader->GetOutput()->Print(std::cout); + 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(image, image->GetRequestedRegion()); - itk::ImageRegionIterator b(reader->GetOutput(), - reader->GetOutput()->GetRequestedRegion()); + 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; - return EXIT_FAILURE; + 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], 4, 1e-7 ) ) + { + 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 EXIT_SUCCESS; + return (isFailingPixelValues + || isFailingOrigin + || isFailingSpacing + || isFailingDirection)? EXIT_FAILURE:EXIT_SUCCESS; } #endif //itkMGHImageIOTest_h_ From c6517e15fab309a44ae679ea3c8b777ffd62c883 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 10:22:24 -0500 Subject: [PATCH 24/68] BUG: Correct DirectionCosine Interpretation When writing the image, the direction cosine was being written as the transpose of the correct answer. This has been fixed. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 605439e794e2..7a8253d972a7 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -659,11 +659,11 @@ ::WriteHeader() if( uj == 0 || uj == 1 ) { // convert the coordinates from LPS to RAS - vBufRas.push_back(-1.0 * (float)vvRas[uj][ui] ); + vBufRas.push_back(-1.0 * (float)vvRas[ui][uj] ); } else { - vBufRas.push_back( (float)vvRas[uj][ui] ); + vBufRas.push_back( (float)vvRas[ui][uj] ); } } } From 3524aabb0afcbc0e6f94881c5c33825f1cc21fb9 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 10:42:39 -0500 Subject: [PATCH 25/68] ENH: Improve TWrite for implicit type conversion MGH format is mostly stored as single precision floating point numbers instead of doubles. This can introduce slight numerical differences between format types. This simplifies type_casting to make writing the files easier, and will allow numerical processing to occur in double presision. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 6 ++- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 51 ++++++++++++------------ 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index dc80d24745e3..93e7a4de4030 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -123,10 +123,12 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase gzFile m_GZFile; std::ofstream m_Output; - template int TWrite(T out); + // 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(T &out); - int TWrite(const char *buf,unsigned long count); + int TWrite(const char *buf,const unsigned long count); void OpenFile(); void CloseFile(); }; diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 7a8253d972a7..3b707d0ab50e 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -45,26 +45,27 @@ ::TRead(T & out) return result; } -template +template int MGHImageIO -::TWrite(T out) +::TWrite(const TInType inValue) { - itk::ByteSwapper::SwapFromSystemToBigEndian(&out); + TDiskType onDiskValue = static_cast(inValue); + itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); if(this->m_IsCompressed) { - return ::gzwrite(this->m_GZFile,&out,sizeof(T)); + return ::gzwrite(this->m_GZFile,&onDiskValue,sizeof(TDiskType)); } else { - this->m_Output.write(reinterpret_cast(&out),sizeof(T)); - return this->m_Output.good() ? sizeof(T) : 0; + this->m_Output.write(reinterpret_cast(&onDiskValue),sizeof(TDiskType)); + return this->m_Output.good() ? sizeof(TDiskType) : 0; } } int MGHImageIO -::TWrite(const char *buf,unsigned long count) +::TWrite(const char *buf,const unsigned long count) { if(this->m_IsCompressed) { @@ -591,37 +592,37 @@ ::WriteHeader() { // version const int mghVersion = 1; - this->TWrite(mghVersion ); + this->TWrite( mghVersion ); // dimensions for( unsigned int ui = 0; ui < 3; ++ui ) { - this->TWrite((int)m_Dimensions[ui] ); + this->TWrite( m_Dimensions[ui] ); } // nframes - this->TWrite((int)m_NumberOfComponents ); + this->TWrite( m_NumberOfComponents ); // type switch( m_ComponentType ) { case UCHAR: { - this->TWrite(MRI_UCHAR); + this->TWrite(MRI_UCHAR); } break; case INT: { - this->TWrite(MRI_INT); + this->TWrite(MRI_INT); } break; case FLOAT: { - this->TWrite(MRI_FLOAT); + this->TWrite(MRI_FLOAT); } break; case SHORT: { - this->TWrite(MRI_SHORT); + this->TWrite(MRI_SHORT); } break; default: @@ -631,16 +632,16 @@ ::WriteHeader() } // dof !?! -> default value = 1 - this->TWrite(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((short)1); + this->TWrite(1); // spacing for( unsigned int ui = 0; ui < 3; ++ui ) { - this->TWrite((float)m_Spacing[ui]); + this->TWrite(m_Spacing[ui]); } // get directions matrix @@ -669,7 +670,7 @@ ::WriteHeader() } for( std::vector::const_iterator cit = vBufRas.begin(); cit != vBufRas.end(); ++cit ) { - this->TWrite(*cit); + this->TWrite(*cit); } const float fcx = static_cast(m_Dimensions[0]) / 2.0f; @@ -687,13 +688,13 @@ ::WriteHeader() c[1] *= -1.0; for( unsigned int ui = 0; ui < 3; ++ui ) { - this->TWrite(c[ui]); + this->TWrite(c[ui]); } // fill the rest of the buffer with zeros const char zerobyte(0); for(unsigned int i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) { - this->TWrite(zerobyte); + this->TWrite(zerobyte); } } @@ -730,26 +731,26 @@ ::WriteData(const void* buffer) float fScanBuffer = 0.0F; if( ExposeMetaData(thisDic, "TR", fScanBuffer) ) { - this->TWrite(fScanBuffer ); + this->TWrite(fScanBuffer ); } // end TR if( ExposeMetaData(thisDic, "FlipAngle", fScanBuffer) ) { - this->TWrite(fScanBuffer); + this->TWrite(fScanBuffer); } // end FlipAngle if( ExposeMetaData(thisDic, "TE", fScanBuffer) ) { - this->TWrite(fScanBuffer); + this->TWrite(fScanBuffer); } // end TE if( ExposeMetaData(thisDic, "TI", fScanBuffer) ) { - this->TWrite(fScanBuffer); + this->TWrite(fScanBuffer); } // end TI if( ExposeMetaData(thisDic, "FoV", fScanBuffer) ) { - this->TWrite(fScanBuffer); + this->TWrite(fScanBuffer); } // end FoV // no need to close the stream From 0abd64dd9b351f0d8ff62d9c3f26132946da1175 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 11:14:37 -0500 Subject: [PATCH 26/68] ENH: Improve numerical statibility MGH format uses floating point values on disk. Make the test program minimize the number of single/double precision floating point conversion. Since ITK is double presion, try to do all computation in double and minimize the truncation to single presion only when writing to disk. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 4 +- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 119 +++++++++++----------- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 30 +++++- 3 files changed, 89 insertions(+), 64 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 93e7a4de4030..37837a33e944 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -125,8 +125,8 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase // 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(T &out); + template int TWrite(const TInType inValue); + template int TRead(TOutType &outValue); int TWrite(const char *buf,const unsigned long count); void OpenFile(); diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 3b707d0ab50e..489b687ca32e 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -35,17 +35,19 @@ static const std::string __GZ_EXT(".gz"); // // ------------------------------- -template +template int MGHImageIO -::TRead(T & out) +::TRead(TOutType & outValue) { - const int result = ::gzread(this->m_GZFile, &out, sizeof(T) ); - itk::ByteSwapper::SwapFromSystemToBigEndian(&out); + TDiskType onDiskValue; + const int result = ::gzread(this->m_GZFile, &onDiskValue, sizeof(TDiskType) ); + itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); + outValue = static_cast(onDiskValue); return result; } -template +template int MGHImageIO ::TWrite(const TInType inValue) @@ -207,21 +209,16 @@ ::ReadVolumeHeader() return; } int version; - this->TRead( version); - int bufInt; // buffer -> int type (most ITK types are unsigned) - this->TRead( bufInt); - m_Dimensions[0] = static_cast(bufInt); - this->TRead( bufInt); - m_Dimensions[1] = static_cast(bufInt); - this->TRead( bufInt); - m_Dimensions[2] = static_cast(bufInt); + this->TRead( version); + this->TRead( m_Dimensions[0] ); + this->TRead( m_Dimensions[1] ); + this->TRead( m_Dimensions[2] ); // next is nframes - this->TRead( bufInt); - m_NumberOfComponents = static_cast(bufInt); + this->TRead( m_NumberOfComponents ); int type; - this->TRead( type); + this->TRead( type); int dof; - this->TRead( dof); // what does this do? + this->TRead( dof); // what does this do? // Convert type to an ITK type switch( type ) @@ -260,14 +257,12 @@ ::ReadVolumeHeader() // Next short says whether RAS registration information is good. // If so, read the voxel size and then the matrix short RASgood; - this->TRead( RASgood); + this->TRead( RASgood); if( RASgood ) { - for( int nSpacing = 0; nSpacing < 3; ++nSpacing ) + for( size_t nSpacing = 0; nSpacing < 3; ++nSpacing ) { - float spacing; - this->TRead( spacing); // type is different - m_Spacing[nSpacing] = spacing; + this->TRead( m_Spacing[nSpacing] ); } /* From http://www.nmr.mgh.harvard.edu/~tosa/#coords: @@ -303,22 +298,20 @@ ::ReadVolumeHeader() { for( unsigned int ui = 0; ui < 3; ++ui ) { - float fBuffer; - this->TRead( fBuffer); - matrix[ui][uj] = fBuffer; + this->TRead( matrix[ui][uj] ); // std::cout << "itkMGHImageIO ReadVolumeHeader: matrix[" << ui << "][" << uj << "] = " << matrix[ui][uj] << "\n"; } } - float c[3]; //c_r c_a c_s - for( unsigned int ui = 0; ui < 3; ++ui ) + double c[3]; //c_r c_a c_s + for( size_t ui = 0; ui < 3; ++ui ) { - this->TRead( c[ui]); + this->TRead( c[ui]); } const std::string orientation = GetOrientation( matrix ); // 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 - for( unsigned int ui = 0; ui < 3; ++ui ) + for( size_t ui = 0; ui < 3; ++ui ) { // convert the coordinates from RAS to LPS, as the ITK archetype assumes // LPS volumes @@ -326,7 +319,7 @@ ::ReadVolumeHeader() matrix[0][ui] *= -1.0; // R -> L matrix[1][ui] *= -1.0; // A -> P std::vector vDir; - for( unsigned int uj = 0; uj < 3; ++uj ) + for( size_t uj = 0; uj < 3; ++uj ) { vDir.push_back( matrix[uj][ui] ); } @@ -342,12 +335,12 @@ ::ReadVolumeHeader() // // computed in CORONAL orientation = ITK_COORDINATE_ORIENTATION_LIA // convert C to from RAS to LPS - c[0] *= -1; //R->L - c[1] *= -1; //A->P - const float fcx = static_cast(m_Dimensions[0]) / 2.0f; - const float fcy = static_cast(m_Dimensions[1]) / 2.0f; - const float fcz = static_cast(m_Dimensions[2]) / 2.0f; - for( unsigned int ui = 0; ui < 3; ++ui ) + c[0] *= -1.0; //R->L + c[1] *= -1.0; //A->P + const double fcx = m_Dimensions[0] * 0.5; + const double fcy = m_Dimensions[1] * 0.5; + const double fcz = m_Dimensions[2] * 0.5; + for( size_t ui = 0; ui < 3; ++ui ) { m_Origin[ui] = c[ui] - ( matrix[ui][0] * m_Spacing[0] * fcx @@ -359,44 +352,48 @@ ::ReadVolumeHeader() // ================== // read tags at the end of file - const unsigned long numValues = m_Dimensions[0] * m_Dimensions[1] * m_Dimensions[2]; + 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 fBuf; + float fBufTR; // read TR, Flip, TE, FI, FOV - if( this->TRead( fBuf) ) + if( this->TRead( fBufTR) ) { itk::MetaDataDictionary & thisDic = this->GetMetaDataDictionary(); itk::EncapsulateMetaData(thisDic, std::string("TR"), - fBuf); + fBufTR); // try to read flipAngle - if( this->TRead( fBuf ) ) + float fBufFA; + if( this->TRead( fBufFA ) ) { itk::EncapsulateMetaData(thisDic, std::string("FlipAngle"), - fBuf); + fBufFA); // TE - if( this->TRead( fBuf ) ) + float fBufTE; + if( this->TRead( fBufTE ) ) { itk::EncapsulateMetaData(thisDic, std::string("TE"), - fBuf); + fBufTE); // TI - if( this->TRead( fBuf) ) + float fBufTI; + if( this->TRead( fBufTI) ) { itk::EncapsulateMetaData(thisDic, std::string("TI"), - fBuf); + fBufTI); // FOV - if( this->TRead( fBuf) ) + float fBufFOV; + if( this->TRead( fBufFOV) ) { itk::EncapsulateMetaData(thisDic, std::string("FoV"), - fBuf); + fBufFOV); } } } @@ -594,9 +591,9 @@ ::WriteHeader() const int mghVersion = 1; this->TWrite( mghVersion ); // dimensions - for( unsigned int ui = 0; ui < 3; ++ui ) + for( size_t ui = 0; ui < 3; ++ui ) { - this->TWrite( m_Dimensions[ui] ); + this->TWrite( m_Dimensions[ui] ); } // nframes @@ -651,7 +648,7 @@ ::WriteHeader() vvRas.push_back( GetDirection(ui) ); } // transpose data before writing it - std::vector vBufRas; + std::vector vBufRas; // transpose the matrix for( unsigned int ui(0); ui < 3; ++ui ) { @@ -668,16 +665,16 @@ ::WriteHeader() } } } - for( std::vector::const_iterator cit = vBufRas.begin(); cit != vBufRas.end(); ++cit ) + for( std::vector::const_iterator cit = vBufRas.begin(); cit != vBufRas.end(); ++cit ) { - this->TWrite(*cit); + this->TWrite(*cit); } - const float fcx = static_cast(m_Dimensions[0]) / 2.0f; - const float fcy = static_cast(m_Dimensions[1]) / 2.0f; - const float fcz = static_cast(m_Dimensions[2]) / 2.0f; - float c[3]; - for( unsigned int ui = 0; ui < 3; ++ui ) + const double fcx = m_Dimensions[0] * 0.5; + const double fcy = m_Dimensions[1] * 0.5; + const double fcz = m_Dimensions[2] * 0.5; + double c[3]; + for( size_t ui = 0; ui < 3; ++ui ) { c[ui] = m_Origin[ui] + ( vvRas[ui][0] * m_Spacing[0] * fcx @@ -686,13 +683,13 @@ ::WriteHeader() } c[0] *= -1.0; c[1] *= -1.0; - for( unsigned int ui = 0; ui < 3; ++ui ) + for( size_t ui = 0; ui < 3; ++ui ) { - this->TWrite(c[ui]); + this->TWrite(c[ui]); } // fill the rest of the buffer with zeros const char zerobyte(0); - for(unsigned int i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) + for(size_t i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) { this->TWrite(zerobyte); } diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 8d55b4d09741..0abff6a14e96 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -32,6 +32,8 @@ #include "itkEuler3DTransform.h" + + template typename itk::Image::Pointer itkMGHImageIOTestGenerateRandomImage(const unsigned int size) @@ -103,7 +105,33 @@ itkMGHImageIOTestGenerateRandomImage(const unsigned int size) source->SetSpacing(spacing); source->Update(); - return (source->GetOutput()); + 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 From 6faa792b26fb44d5ca9a0d25d288083742141515 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 15:06:30 -0500 Subject: [PATCH 27/68] BUG: MGH File writing bug fixed In order to identify and more carefully ensure that conversions are done consistently for Reading/Writing, the code was converted from naked c-arrays to itk::Vector and itk::Matrix so that the manipulation of different spaces can look very much like the documentation describing the conversion between spaces. This conversion also assists with debugging and future maintenance by allowing out of code validation to be done in Matlab, Numpy, or similar matrix algebra tools. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 174 ++++++++++---------- Modules/IO/MGHIO/test/CMakeLists.txt | 5 - Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 27 ++- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 28 +--- 4 files changed, 106 insertions(+), 128 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 489b687ca32e..98b700c106d8 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -28,6 +28,18 @@ static const std::string __MGH_EXT(".mgh"); static const std::string __MGZ_EXT(".mgz"); static const std::string __GZ_EXT(".gz"); +typedef itk::Matrix MatrixType; +typedef itk::Vector VectorType; + +static MatrixType GetRAS2LPS() + { + MatrixType RAS2LAS; + RAS2LAS.SetIdentity(); + RAS2LAS[0][0]=-1.0; + RAS2LAS[1][1]=-1.0; + RAS2LAS[2][2]= 1.0; + return RAS2LAS; + } // ------------------------------- // @@ -287,71 +299,67 @@ ::ReadVolumeHeader() z_r z_a z_s c_r c_a c_s */ - typedef itk::Matrix MatrixType; - MatrixType matrix; + 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 uj = 0; uj < 3; ++uj ) + for( unsigned int c = 0; c < 3; ++c ) { - for( unsigned int ui = 0; ui < 3; ++ui ) + for( unsigned int r = 0; r < 3; ++r ) //NOTE: Data stored row-major form, so traverse rows first { - this->TRead( matrix[ui][uj] ); -// std::cout << "itkMGHImageIO ReadVolumeHeader: matrix[" << ui << "][" << uj << "] = " << matrix[ui][uj] << "\n"; + this->TRead( MGHdirMatrix[r][c] ); } - } - double c[3]; //c_r c_a c_s - for( size_t ui = 0; ui < 3; ++ui ) - { - this->TRead( c[ui]); + } + // 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 ); } - const std::string orientation = GetOrientation( matrix ); - // 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 + VectorType MGHcenterVoxel; //c_r c_a c_s for( size_t ui = 0; ui < 3; ++ui ) { - // convert the coordinates from RAS to LPS, as the ITK archetype assumes - // LPS volumes - // volume orientation not related to scan order, always convert - matrix[0][ui] *= -1.0; // R -> L - matrix[1][ui] *= -1.0; // A -> P - std::vector vDir; - for( size_t uj = 0; uj < 3; ++uj ) - { - vDir.push_back( matrix[uj][ui] ); - } - // std::cout << "itkMGHImageIO ReadVolumeHeader: setting " << ui << " direction in LPS: " << vDir[0] << "," << - // vDir[1] << "," << vDir[2] << "\n"; - SetDirection( ui, vDir ); + this->TRead( MGHcenterVoxel[ui]); } + // convert C to from RAS to LPS + VectorType ITKcenterVoxel=GetRAS2LPS()*MGHcenterVoxel; - // MriDirCos(); // convert direction cosines + // 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 - // convert C to from RAS to LPS - c[0] *= -1.0; //R->L - c[1] *= -1.0; //A->P - const double fcx = m_Dimensions[0] * 0.5; - const double fcy = m_Dimensions[1] * 0.5; - const double fcz = m_Dimensions[2] * 0.5; - for( size_t ui = 0; ui < 3; ++ui ) - { - m_Origin[ui] = c[ui] - - ( matrix[ui][0] * m_Spacing[0] * fcx - + matrix[ui][1] * m_Spacing[1] * fcy - + matrix[ui][2] * m_Spacing[2] * fcz ); - } + 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() ), @@ -642,50 +650,47 @@ ::WriteHeader() } // get directions matrix - std::vector > vvRas; - for( unsigned int ui = 0; ui < 3; ++ui ) - { - vvRas.push_back( GetDirection(ui) ); - } - // transpose data before writing it - std::vector vBufRas; - // transpose the matrix - for( unsigned int ui(0); ui < 3; ++ui ) - { - for( unsigned int uj(0); uj < 3; ++uj ) - { - if( uj == 0 || uj == 1 ) - { - // convert the coordinates from LPS to RAS - vBufRas.push_back(-1.0 * (float)vvRas[ui][uj] ); - } - else - { - vBufRas.push_back( (float)vvRas[ui][uj] ); - } - } - } - for( std::vector::const_iterator cit = vBufRas.begin(); cit != vBufRas.end(); ++cit ) - { - this->TWrite(*cit); - } - - const double fcx = m_Dimensions[0] * 0.5; - const double fcy = m_Dimensions[1] * 0.5; - const double fcz = m_Dimensions[2] * 0.5; - double c[3]; - for( size_t ui = 0; ui < 3; ++ui ) - { - c[ui] = m_Origin[ui] - + ( vvRas[ui][0] * m_Spacing[0] * fcx - + vvRas[ui][1] * m_Spacing[1] * fcy - + vvRas[ui][2] * m_Spacing[2] * fcz ); - } - c[0] *= -1.0; - c[1] *= -1.0; + 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(c[ui]); + this->TWrite(MGHcenterVoxel[ui]); } // fill the rest of the buffer with zeros const char zerobyte(0); @@ -861,7 +866,6 @@ ::GetOrientation( itk::Matrix directions ) orientation += "I"; } } - // std::cout << "GetOrientation returning " << orientation.c_str() << std::endl; return orientation; } } // end namespace itk diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index 679152bafb8a..a8794a1aca4f 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -38,8 +38,3 @@ itk_add_test(NAME itkMGHIOOriginTest DATA{${MGH_DATA_ROOT}/T1_longname.mgh.gz} OriginTEST.mgh.gz ) - - -# "/Users/johnsonhj/Dropbox/DATA/wmparc_acpc_ref.mgz" -# "/Users/johnsonhj/Dropbox/DATA/wmparc_acpc_ref.nii.gz" - diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 28f06a8c4ff6..b530d8aeb03c 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -53,14 +53,14 @@ int itkMGHImageIOTest(int ac, char* av[]) } const std::string TestMode(av[2]); - int returnStatus = EXIT_SUCCESS; + bool returnSucceeded = true; if( TestMode == std::string("FactoryCreationTest")) //Tests added to increase code coverage. { itk::MGHImageIOFactory::Pointer MyFactoryTest=itk::MGHImageIOFactory::New(); if(MyFactoryTest.IsNull()) { - returnStatus = EXIT_FAILURE; + returnSucceeded &= false; } //This was made a protected function. MyFactoryTest->PrintSelf(std::cout,0); } @@ -68,14 +68,11 @@ int itkMGHImageIOTest(int ac, char* av[]) { std::string fn("test.mgz"); //TODO: Need to test with images of non-identity direction cosigns, spacing, origin - if( ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && - ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && - ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && - ( returnStatus = itkMGHImageIOTestReadWriteTest(fn,3,"null", true) ) != EXIT_FAILURE && - ( returnStatus = itkMGHImageIOTestReadWriteTest, 3>(fn,3,"null", true) ) != EXIT_FAILURE ) - { - returnStatus = EXIT_SUCCESS; - } + 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. { @@ -99,7 +96,7 @@ int itkMGHImageIOTest(int ac, char* av[]) catch (itk::ExceptionObject &e) { e.Print(std::cerr); - returnStatus = EXIT_FAILURE; + returnSucceeded &= false; } } else if( TestMode == "TestOriginWriteTest" ) @@ -138,19 +135,19 @@ int itkMGHImageIOTest(int ac, char* av[]) << "written: " << reference_origin << " read: " << test_origin << " distance: " << dist << std::endl; - returnStatus = EXIT_FAILURE; + returnSucceeded &= false; } } catch (itk::ExceptionObject &e) { e.Print(std::cerr); - returnStatus = EXIT_FAILURE; + returnSucceeded &= false; } } else { std::cerr << "Invalid TestMode : " << TestMode << std::endl; - returnStatus = EXIT_FAILURE; + returnSucceeded &= false; } - return returnStatus; + return (returnSucceeded == true) ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 0abff6a14e96..a12df9f3dec0 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -38,7 +38,6 @@ template typename itk::Image::Pointer itkMGHImageIOTestGenerateRandomImage(const unsigned int size) { - typedef itk::Euler3DTransform EulerTransformType; EulerTransformType::Pointer eulerTransform = EulerTransformType::New(); eulerTransform->SetIdentity(); @@ -82,20 +81,6 @@ itkMGHImageIOTestGenerateRandomImage(const unsigned int size) origin[i] = static_cast(1234.5); } -#if 0 - //Make origin match numerical precision of MGH file - const double fcx = sz[0] * 0.5; - const double fcy = sz[1] * 0.5; - const double fcz = sz[2] * 0.5; - for( size_t ui = 0; ui < 3; ++ui ) - { - origin[ui] = origin[ui] - + ( direction[ui][0] * spacing[0] * fcx - + direction[ui][1] * spacing[1] * fcy - + direction[ui][2] * spacing[2] * fcz ); - } -#endif - typename itk::RandomImageSource::Pointer source = itk::RandomImageSource::New(); @@ -157,8 +142,8 @@ itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsign for(unsigned int i = 0; i < 3; ++i) { sz[i] = size; - spacing[i] = static_cast(i + 1); - origin[i] = static_cast( (i & 1) ? -i : i ); + spacing[i] = static_cast(i*3.21 + 1.0); + origin[i] = static_cast( 1.23456 ); } TensorImagePointer tensorImage = TensorImageType::New(); @@ -194,7 +179,7 @@ itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsign template -int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, +bool itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, std::string inputFile, bool compression=false) { typedef itk::Image ImageType; @@ -301,7 +286,7 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, isFailingSpacing = true; } if( ! itk::Math::FloatAlmostEqual( test_image->GetOrigin()[idx], - reference_image->GetOrigin()[idx], 4, 1e-7 ) ) + reference_image->GetOrigin()[idx], 100000, 1e-1 ) ) { isFailingOrigin = true; } @@ -334,10 +319,7 @@ int itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, << test_image->GetDirection() << " ! = \n" << reference_image->GetDirection() << std::endl; } - return (isFailingPixelValues - || isFailingOrigin - || isFailingSpacing - || isFailingDirection)? EXIT_FAILURE:EXIT_SUCCESS; + return ! (isFailingPixelValues || isFailingOrigin || isFailingSpacing || isFailingDirection); } #endif //itkMGHImageIOTest_h_ From d65651a36e419b8441d269e8bafce7833c48dfc7 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Thu, 16 Jul 2015 16:52:14 -0500 Subject: [PATCH 28/68] STYLE: Remove ITK style warning ITK-src/Modules/Remote/MGHIO/src/itkMGHImageIO.cxx:32: error: Type definition (VectorType) is not aligned with the previous one: 32 v.s. 33 --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 98b700c106d8..b5aa50f1668f 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -29,7 +29,7 @@ static const std::string __MGZ_EXT(".mgz"); static const std::string __GZ_EXT(".gz"); typedef itk::Matrix MatrixType; -typedef itk::Vector VectorType; +typedef itk::Vector VectorType; static MatrixType GetRAS2LPS() { @@ -311,7 +311,7 @@ ::ReadVolumeHeader() { 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 @@ -672,7 +672,7 @@ ::WriteHeader() this->TWrite(MGHdirMatrix[r][c]); } } - + VectorType fc; fc[0] = m_Dimensions[0] * 0.5; fc[1] = m_Dimensions[1] * 0.5; From c2002a85d7b87b60e3b9db530b238ce667f8c220 Mon Sep 17 00:00:00 2001 From: Jean-Christophe Fillion-Robin Date: Fri, 4 Dec 2015 10:21:39 -0500 Subject: [PATCH 29/68] BUG: Ensure factory is registered once. This commit updates CMakeLists.txt to ensure built library is shared. See ITK issue #3393 https://issues.itk.org/jira/browse/ITK-3393 --- Modules/IO/MGHIO/src/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 0288e2291154..134e6f90e0f3 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -3,6 +3,6 @@ itkMGHImageIOFactory.cxx itkMGHImageIO.cxx ) -add_library(MGHIO ${MGHIO_SRC}) +add_library(MGHIO ${ITK_LIBRARY_BUILD_TYPE} ${MGHIO_SRC}) target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) itk_module_target(MGHIO) From 7dd9b36a8a866c074a55adda176241e720b4d354 Mon Sep 17 00:00:00 2001 From: Zach Williamson Date: Thu, 30 Jun 2016 09:44:51 -0500 Subject: [PATCH 30/68] STYLE: Use Macro for Function Deletion --- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 2a86d7cd5cee..a1e0866ebf1d 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -63,8 +63,7 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase virtual void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; private: - MGHImageIOFactory(const Self &); //purposely not implemented - void operator=(const Self &); //purposely not implemented + ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); }; } // end namespace itk From 42138ee66bce15fc97eb9e75477dc0499e88dae2 Mon Sep 17 00:00:00 2001 From: Francois Budin Date: Thu, 26 Oct 2017 16:39:12 -0400 Subject: [PATCH 31/68] ENH: Add FACTORY_NAMES parameter to itk_module() declaration This new parameter allows ITK to be aware any object that needs to be registered to the ITK factory. Remote modules that offer IO capabilities can be more easily integrated in ITK. --- Modules/IO/MGHIO/itk-module.cmake | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 165569bfeed4..91be1e648826 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -10,6 +10,8 @@ itk_module(MGHIO ITKTestKernel ITKTransform EXCLUDE_FROM_DEFAULT + FACTORY_NAMES + ImageIO::MGH DESCRIPTION "${DOCUMENTATION}" ) From c863a12ebc7901b1d65607bf5abfc413837e059d Mon Sep 17 00:00:00 2001 From: Francois Budin Date: Mon, 13 Nov 2017 09:29:13 -0500 Subject: [PATCH 32/68] ENH: Module can now be build as an external remote module CMakeLists.txt was incomplete to build this module as an external (outside of ITK source tree) remote module. --- Modules/IO/MGHIO/CMakeLists.txt | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index e0254d3d4fb1..d945982a21cd 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,3 +1,11 @@ +cmake_minimum_required(VERSION 2.8.12) project(MGHIO) set(MGHIO_LIBRARIES MGHIO) -itk_module_impl() + +if(NOT ITK_SOURCE_DIR) + find_package(ITK REQUIRED) + list(APPEND CMAKE_MODULE_PATH ${ITK_CMAKE_DIR}) + include(ITKModuleExternal) +else() + itk_module_impl() +endif() From 3fae98f085866bcc1ae8ab3f08ef7949aa974903 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 16 Dec 2017 14:50:04 -0600 Subject: [PATCH 33/68] ENH: Initial ITKv5 conversions. Provide initial conversion of features to ITKv5. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 14 +++++++------- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 8 ++++---- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 37837a33e944..37f45f727764 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -58,13 +58,13 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite * \return Returns true if this ImageIO can read the file specified. */ - virtual bool CanReadFile(const char *FileNameToRead) ITK_OVERRIDE; + bool CanReadFile(const char *FileNameToRead) ITK_OVERRIDE; /** Set the spacing and dimension information for the set filename. */ - virtual void ReadImageInformation() ITK_OVERRIDE; + void ReadImageInformation() ITK_OVERRIDE; /** Reads the data from disk into the memory buffer provided. */ - virtual void Read(void *buffer) ITK_OVERRIDE; + void Read(void *buffer) ITK_OVERRIDE; /*-------- This part of the interfaces deals with writing data. ----- */ @@ -73,18 +73,18 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \post Sets classes ImageIOBase::m_FileName variable to be FileNameToWrite * \return Returns true if this ImageIO can write the file specified. */ - virtual bool CanWriteFile(const char *FileNameToWrite) ITK_OVERRIDE; + bool CanWriteFile(const char *FileNameToWrite) ITK_OVERRIDE; /** Set the spacing and dimension information for the set filename. */ - virtual void WriteImageInformation() ITK_OVERRIDE; + void WriteImageInformation() ITK_OVERRIDE; /** Writes the data to disk from the memory buffer provided. Make sure * that the IORegions has been set properly. */ - virtual void Write(const void *buffer) ITK_OVERRIDE; + void Write(const void *buffer) ITK_OVERRIDE; protected: MGHImageIO(); - ~MGHImageIO(); + ~MGHImageIO() override; void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; void ReadVolumeHeader(); diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index a1e0866ebf1d..412f60c6d56b 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -39,9 +39,9 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase typedef SmartPointer ConstPointer; /** Class methods used to interface with the registered factories **/ - virtual const char * GetITKSourceVersion(void) const ITK_OVERRIDE; + const char * GetITKSourceVersion(void) const ITK_OVERRIDE; - virtual const char * GetDescription(void) const ITK_OVERRIDE; + const char * GetDescription(void) const ITK_OVERRIDE; /** Method for class instantiation **/ itkFactorylessNewMacro(Self); @@ -59,8 +59,8 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase protected: MGHImageIOFactory(); - ~MGHImageIOFactory(); - virtual void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; + ~MGHImageIOFactory() override; + void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; private: ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); From 702a91e26625effefbd22b450304e698976ed7f6 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 16 Dec 2017 19:17:06 -0600 Subject: [PATCH 34/68] ENH: ITKv5 override consistency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Provide remove virtual and override Use clang-tidy to add ITK_OVERRIDE, and to remove redundant virtual on functions. cd ../ITK; clang-tidy -p ITK-clangtidy $find Modules/[A-J]* -name *.cxx |fgrep -v ThirdParty) -checks=-*,modernize-use-override -header-filter=.* -fix clang-tidy -p ITK-clangtidy $(find Modules/[K-Z]* -name *.cxx |fgrep -v ThirdParty) -checks=-*,modernize-use-override -header-filter=.* -fix https://stackoverflow.com/questions/39932391/virtual-override-or-both-c When you override a function you don't technically need to write either virtual or override. The original base class declaration needs the keyword virtual to mark it as virtual. In the derived class the function is virtual by way of having the ¹same type as the base class function. However, an override can help avoid bugs by producing a compilation error when the intended override isn't technically an override. E.g. that the function type isn't exactly like the base class function. Or that a maintenance of the base class changes that function's type, e.g. adding a defaulted argument. In the same way, a virtual keyword in the derived class can make such a bug more subtle, by ensuring that the function is still is virtual in further derived classes. So the general advice is, virtual for the base class function declaration. This is technically necessary. Use override (only) for a derived class' override. This helps with maintenance. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 37f45f727764..a257e0e73c7f 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -84,7 +84,7 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase protected: MGHImageIO(); - ~MGHImageIO() override; + ~MGHImageIO() ITK_OVERRIDE; void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; void ReadVolumeHeader(); diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 412f60c6d56b..eb50dee72240 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -59,7 +59,7 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase protected: MGHImageIOFactory(); - ~MGHImageIOFactory() override; + ~MGHImageIOFactory() ITK_OVERRIDE; void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; private: From 7ddb9ff2b8715135a54c6ede7f6310a0e6ea0871 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 16 Dec 2017 19:36:25 -0600 Subject: [PATCH 35/68] COMP: Use C++11 override directly git grep -l "ITK_OVERRIDE" | fgrep -v itk_compiler_detection.h | fgrep -v CMakeLists.txt |fgrep -v .cmake | xargs sed -i '' -e "s/ITK_OVERRIDE/override/g" --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 18 +++++++++--------- .../IO/MGHIO/include/itkMGHImageIOFactory.h | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index a257e0e73c7f..ad4ecad72b51 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -58,13 +58,13 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \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) ITK_OVERRIDE; + bool CanReadFile(const char *FileNameToRead) override; /** Set the spacing and dimension information for the set filename. */ - void ReadImageInformation() ITK_OVERRIDE; + void ReadImageInformation() override; /** Reads the data from disk into the memory buffer provided. */ - void Read(void *buffer) ITK_OVERRIDE; + void Read(void *buffer) override; /*-------- This part of the interfaces deals with writing data. ----- */ @@ -73,19 +73,19 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \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 *FileNameToWrite) ITK_OVERRIDE; + bool CanWriteFile(const char *FileNameToWrite) override; /** Set the spacing and dimension information for the set filename. */ - void WriteImageInformation() ITK_OVERRIDE; + 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) ITK_OVERRIDE; + void Write(const void *buffer) override; protected: MGHImageIO(); - ~MGHImageIO() ITK_OVERRIDE; - void PrintSelf(std::ostream& os, Indent indent) const ITK_OVERRIDE; + ~MGHImageIO() override; + void PrintSelf(std::ostream& os, Indent indent) const override; void ReadVolumeHeader(); @@ -115,7 +115,7 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase void PermuteFrameValues(const void* buffer, char* tempmemory); - unsigned int GetComponentSize() const ITK_OVERRIDE; + unsigned int GetComponentSize() const override; std::string GetOrientation( itk::Matrix directions ); diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index eb50dee72240..181f7ebf2293 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -39,9 +39,9 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase typedef SmartPointer ConstPointer; /** Class methods used to interface with the registered factories **/ - const char * GetITKSourceVersion(void) const ITK_OVERRIDE; + const char * GetITKSourceVersion(void) const override; - const char * GetDescription(void) const ITK_OVERRIDE; + const char * GetDescription(void) const override; /** Method for class instantiation **/ itkFactorylessNewMacro(Self); @@ -59,8 +59,8 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase protected: MGHImageIOFactory(); - ~MGHImageIOFactory() ITK_OVERRIDE; - void PrintSelf(std::ostream & os, Indent indent) const ITK_OVERRIDE; + ~MGHImageIOFactory() override; + void PrintSelf(std::ostream & os, Indent indent) const override; private: ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); From 0a176cee636bea25054b5e44e61a2907f7fd53fb Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 16 Dec 2017 20:10:45 -0600 Subject: [PATCH 36/68] COMP: Use C++11 nullptr directly git grep -l "ITK_NULLPTR" | fgrep -v itk_compiler_detection.h | fgrep -v CMakeLists.txt |fgrep -v .cmake | xargs sed -i '' -e "s/ITK_NULLPTR/nullptr/g" --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index b5aa50f1668f..efd1e92a94a2 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -542,7 +542,7 @@ ::OpenFile() if(this->m_IsCompressed) { this->m_GZFile = gzopen(m_FileName.c_str(), "wb"); - if( this->m_GZFile == ITK_NULLPTR ) + if( this->m_GZFile == nullptr ) { itkExceptionMacro(<< " Failed to open gzFile for writing"); itkExceptionMacro(<< " File cannot be written"); From f75ae0e2abb606fd75dcde27c6f8f4f14e276838 Mon Sep 17 00:00:00 2001 From: Jon Haitz Legarreta Date: Fri, 19 Jan 2018 08:10:32 +0100 Subject: [PATCH 37/68] ENH: Require cmake minimum version to be 3.9.5. Require CMake minimum version to be 3.9.5 following ITKv5 requiring C++11: https://discourse.itk.org/t/minimum-cmake-version-update/585 --- Modules/IO/MGHIO/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index d945982a21cd..f83579e5e346 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 2.8.12) +cmake_minimum_required(VERSION 3.9.5) project(MGHIO) set(MGHIO_LIBRARIES MGHIO) From aa480fcaa63d7b992ccaaf66d52386bc5c8a12d6 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Mon, 12 Feb 2018 15:23:14 -0600 Subject: [PATCH 38/68] STYLE: Modernize to C++11 conventions STYLE: Use auto for variable creation This check is responsible for using the auto type specifier for variable declarations to improve code readability and maintainability. The auto type specifier will only be introduced in situations where the variable type matches the type of the initializer expression. In other words auto should deduce the same type that was originally spelled in the source cd /Users/johnsonhj/Dashboard/src/ITK-clangtidy/ run-clang-tidy.py -checks=-*,modernize-use-auto -header-filter=.* -fix use auto when declaring iterators use auto when initializing with a cast to avoid duplicating the type name use auto when initializing with a template cast to avoid duplicating the type name use auto when initializing with new to avoid duplicating the type name SRCDIR=/Users/johnsonhj/Dashboard/src/ITK #My local SRC BLDDIR=/Users/johnsonhj/Dashboard/src/ITK-clangtidy/ #My local BLD PERF: Replace explicit return calls of constructor Replaces explicit calls to the constructor in a return with a braced initializer list. This way the return type is not needlessly duplicated in the function definition and the return statement. SRCDIR=/Users/johnsonhj/Dashboard/src/ITK #My local SRC BLDDIR=/Users/johnsonhj/Dashboard/src/ITK-clangtidy/ #My local BLD cd /Users/johnsonhj/Dashboard/src/ITK-clangtidy/ run-clang-tidy.py -checks=-*,modernize-return-braced-init-list -header-filter=.* -fix PERF: Allow compiler to choose best way to construct a copy With move semantics added to the language and the standard library updated with move constructors added for many types it is now interesting to take an argument directly by value, instead of by const-reference, and then copy. This check allows the compiler to take care of choosing the best way to construct the copy. The transformation is usually beneficial when the calling code passes an rvalue and assumes the move construction is a cheap operation. This short example illustrates how the construction of the value happens: class Foo { public: - Foo(const std::string &Copied, const std::string &ReadOnly) - : Copied(Copied), ReadOnly(ReadOnly) {} + Foo(std::string Moved, const std::string &ReadOnly) + : Copied(std::move(Moved)), ReadOnly(ReadOnly) {} private: private: std::string Copied; const std::string &ReadOnly; }; SRCDIR=/Users/johnsonhj/Dashboard/src/ITK #My local SRC BLDDIR=/Users/johnsonhj/Dashboard/src/ITK-clangtidy/ #My local BLD cd /Users/johnsonhj/Dashboard/src/ITK-clangtidy/ run-clang-tidy.py -checks=-*,modernize-pass-by-value -header-filter=.* -fix STYLE: Use range-based loops from C++11 Used as a more readable equivalent to the traditional for loop operating over a range of values, such as all elements in a container, in the forward direction. ==== Range based loopes are more explicit for only computing the end location once for containers. for ( ImageIORegion::IndexType::const_iterator i = this->GetIndex().begin(); i != this->GetIndex().end(); //<- NOTE: Compute end every loop iteration ++i ) for (long i : this->GetIndex()) //<- NOTE: Implicitly only compute end once ==== Explicitly reduce the amount of index computations: (The compiler probably does this too) for(int i = 0; i < 11; i++) { pos[0] = testPoints[i][0]; pos[1] = testPoints[i][1]; ^^^^ for(auto & testPoint : testPoints) { pos[0] = testPoint[0]; pos[1] = testPoint[1]; ==== SRCDIR=/Users/johnsonhj/Dashboard/src/ITK #My local SRC BLDDIR=/Users/johnsonhj/Dashboard/src/ITK-clangtidy/ #My local BLD cd /Users/johnsonhj/Dashboard/src/ITK-clangtidy/ run-clang-tidy.py -checks=-*,modernize-loop-convert -header-filter=.* -fix --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index efd1e92a94a2..30752e86e3d9 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -64,7 +64,7 @@ int MGHImageIO ::TWrite(const TInType inValue) { - TDiskType onDiskValue = static_cast(inValue); + auto onDiskValue = static_cast(inValue); itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); if(this->m_IsCompressed) { @@ -431,7 +431,7 @@ ::Read(void* pData) if( m_NumberOfComponents > 1 ) { - char* pBuffer = new char[frameSize]; + auto* pBuffer = new char[frameSize]; const unsigned int pixelSize = componentSize * m_NumberOfComponents; for( unsigned int frameIndex = 0; @@ -442,8 +442,8 @@ ::Read(void* pData) gzread( this->m_GZFile, pBuffer, frameSize ); // copy memory location in the final buffer - char * pSrc = (char *)pBuffer; - char * pDst = (char *)pData; + auto * pSrc = (char *)pBuffer; + auto * pDst = (char *)pData; pDst += frameIndex * componentSize; for( unsigned int ui = 0; @@ -710,7 +710,7 @@ ::WriteData(const void* buffer) const unsigned long int numvalues = numPixels * m_NumberOfComponents; const unsigned long int numbytes = this->GetComponentSize() * numvalues; - char* tempmemory = new char[numbytes]; + auto* tempmemory = new char[numbytes]; // re-arrange data in frames if( m_NumberOfComponents > 1 ) @@ -768,8 +768,8 @@ ::PermuteFrameValues(const void* buffer, const unsigned int valueSize( this->GetComponentSize() ); const unsigned int frameSize = numPixels * valueSize; - const char* pSrc = (const char *)buffer; - char* pDst = (char *)tempmemory; + const auto* pSrc = (const char *)buffer; + auto* pDst = (char *)tempmemory; for( unsigned int pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex, pDst += valueSize ) From 67e11ded271587c8f2095b23ad0af2f35b8d063f Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Mon, 12 Feb 2018 23:30:21 -0600 Subject: [PATCH 39/68] STYLE: Prefer C++11 type alias over typedef == http://en.cppreference.com/w/cpp/language/type_alias == Type alias is a name that refers to a previously defined type (similar to typedef). A type alias declaration introduces a name which can be used as a synonym for the type denoted by type-id. It does not introduce a new type and it cannot change the meaning of an existing type name. There is no difference between a type alias declaration and typedef declaration. This declaration may appear in block scope, class scope, or namespace scope. == https://www.quora.com/Is-using-typedef-in-C++-considered-a-bad-practice == While typedef is still available for backward compatibility, the new Type Alias syntax 'using Alias = ExistingLongName;' is more consistent with the flow of C++ than the old typedef syntax 'typedef ExistingLongName Alias;', and it also works for templates (Type alias, alias template (since C++11)), so leftover 'typedef' aliases will differ in style from any alias templates. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 8 ++++---- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 10 +++++----- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 4 ++-- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 4 ++-- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 16 ++++++++-------- 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index ad4ecad72b51..4f087b9eafce 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -40,10 +40,10 @@ namespace itk class MGHIO_EXPORT MGHImageIO:public ImageIOBase { public: - /** Standard class typedefs. */ - typedef MGHImageIO Self; - typedef ImageIOBase Superclass; - typedef SmartPointer Pointer; + /** Standard class type alias. */ + using Self = MGHImageIO; + using Superclass = ImageIOBase; + using Pointer = SmartPointer; /** Method for creation through the object factory. */ itkNewMacro(Self); diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 181f7ebf2293..9ae0bb925335 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -32,11 +32,11 @@ namespace itk class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: - /** Standard class typedefs */ - typedef MGHImageIOFactory Self; - typedef ObjectFactoryBase Superclass; - typedef SmartPointer Pointer; - typedef SmartPointer ConstPointer; + /** 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(void) const override; diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 30752e86e3d9..4bf284b9c30c 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -28,8 +28,8 @@ static const std::string __MGH_EXT(".mgh"); static const std::string __MGZ_EXT(".mgz"); static const std::string __GZ_EXT(".gz"); -typedef itk::Matrix MatrixType; -typedef itk::Vector VectorType; +using MatrixType = itk::Matrix; +using VectorType = itk::Vector; static MatrixType GetRAS2LPS() { diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index b530d8aeb03c..79940b0c1cb9 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -76,7 +76,7 @@ int itkMGHImageIOTest(int ac, char* av[]) } else if( TestMode == std::string("ReadImagesTest") ) //This is a mechanism for reading unsigned int images for testing. { - typedef itk::Image ImageType; + using ImageType = itk::Image; const std::string imageToBeRead(av[3]); const std::string imageToBeWritten(av[4]); try @@ -101,7 +101,7 @@ int itkMGHImageIOTest(int ac, char* av[]) } else if( TestMode == "TestOriginWriteTest" ) { - typedef itk::Image ImageType; + using ImageType = itk::Image; ImageType::Pointer input; const std::string imageToBeRead(av[3]); const std::string imageToBeWritten(av[4]); diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index a12df9f3dec0..f75381cbc020 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -38,7 +38,7 @@ template typename itk::Image::Pointer itkMGHImageIOTestGenerateRandomImage(const unsigned int size) { - typedef itk::Euler3DTransform EulerTransformType; + using EulerTransformType = itk::Euler3DTransform; EulerTransformType::Pointer eulerTransform = EulerTransformType::New(); eulerTransform->SetIdentity(); @@ -50,7 +50,7 @@ itkMGHImageIOTestGenerateRandomImage(const unsigned int size) const double angleZ = 5.0 * std::atan( 1.0 ) / 45.0; eulerTransform->SetRotation(angleX, angleY, angleZ); - typedef itk::Image ImageType; + using ImageType = itk::Image; typename ImageType::DirectionType permuteDirections; const double dir1[3] = { -1., 0., 0. }; @@ -124,8 +124,8 @@ template<> itk::Image,3>::Pointer itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsigned int size) { - typedef itk::Image,3> TensorImageType; - typedef TensorImageType::Pointer TensorImagePointer; + using TensorImageType = itk::Image,3>; + using TensorImagePointer = TensorImageType::Pointer; const double dir1[3] = { 0, -1, 0 }; const double dir2[3] = { 1, 0, 0 }; @@ -154,8 +154,8 @@ itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsign tensorImage->SetDirection(direction); itk::DiffusionTensor3D pix; - typedef itk::Image ScalarImageType; - typedef ScalarImageType::Pointer ScalarImagePointer; + using ScalarImageType = itk::Image; + using ScalarImagePointer = ScalarImageType::Pointer; std::vector scalarImageVec; for(unsigned i = 0; i < pix.Size(); ++i) @@ -182,7 +182,7 @@ template bool itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, std::string inputFile, bool compression=false) { - typedef itk::Image ImageType; + using ImageType = itk::Image; typename itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); @@ -277,7 +277,7 @@ bool itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, isFailingPixelValues = true; } } - for( int idx = 0 ; idx < 3; ++idx ) + 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], From 4a5d523a53f5c54d278b905d1005b9abfe9d5467 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Tue, 13 Feb 2018 08:24:42 -0600 Subject: [PATCH 40/68] STYLE: Prefer constexpr for const numeric literals Use constexpr for constant numeric literals. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 4bf284b9c30c..5e5102c20600 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -596,7 +596,7 @@ MGHImageIO ::WriteHeader() { // version - const int mghVersion = 1; + constexpr int mghVersion = 1; this->TWrite( mghVersion ); // dimensions for( size_t ui = 0; ui < 3; ++ui ) From 94f7003c3e6f13c7dfa65a2dd5f7ae812dc4748f Mon Sep 17 00:00:00 2001 From: Jon Haitz Legarreta Date: Sat, 14 Apr 2018 19:03:29 +0200 Subject: [PATCH 41/68] COMP: Move ITK_DISALLOW_COPY_AND_ASSIGN calls to public section. Move `ITK_DISALLOW_COPY_AND_ASSIGN` calls to public section following the discussion in https://discourse.itk.org/t/noncopyable If legacy (pre-macro) copy and assing methods existed, subsitute them for the `ITK_DISALLOW_COPY_AND_ASSIGN` macro. --- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 9ae0bb925335..514c2d237952 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -32,6 +32,8 @@ namespace itk class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: + ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); + /** Standard class type alias */ using Self = MGHImageIOFactory; using Superclass = ObjectFactoryBase; @@ -61,9 +63,6 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase MGHImageIOFactory(); ~MGHImageIOFactory() override; void PrintSelf(std::ostream & os, Indent indent) const override; - -private: - ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); }; } // end namespace itk From 6268b04c7fc58b8b9afe87ef36f4f715924afd2c Mon Sep 17 00:00:00 2001 From: Jon Haitz Legarreta Date: Sat, 5 May 2018 12:24:29 +0200 Subject: [PATCH 42/68] COMP: Set the minimum required CMake version to 3.10.2. As agreed in: https://discourse.itk.org/t/cmake-update/870/ Set the `cmake_minimum_required` to version **3.10.2**. --- Modules/IO/MGHIO/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index f83579e5e346..ae6ceb70ac4f 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.9.5) +cmake_minimum_required(VERSION 3.10.2) project(MGHIO) set(MGHIO_LIBRARIES MGHIO) From 3d6976817c1ee0a2a2bacce417206312abb26c37 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Wed, 19 Feb 2020 16:35:00 -0600 Subject: [PATCH 43/68] ENH: Add .gitattributes to allow running ITK clang-formatting scripts ``` git filter-branch -f \ --tree-filter "~/ITK/Utilities/Maintenance/clang-format.bash --clang-format ~/Dashboard/src/ITK-clang11/clang-format-Linux --tracked" \ master.. ``` --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 78 +- .../IO/MGHIO/include/itkMGHImageIOFactory.h | 18 +- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 759 ++++++++---------- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 23 +- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 119 +-- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 293 ++++--- 6 files changed, 620 insertions(+), 670 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 4f087b9eafce..c0926fb92407 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -37,7 +37,7 @@ namespace itk * \ingroup IOFilters * \ingroup MGHIO */ -class MGHIO_EXPORT MGHImageIO:public ImageIOBase +class MGHIO_EXPORT MGHImageIO : public ImageIOBase { public: /** Standard class type alias. */ @@ -58,13 +58,16 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \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; + bool + CanReadFile(const char * FileNameToRead) override; /** Set the spacing and dimension information for the set filename. */ - void ReadImageInformation() override; + void + ReadImageInformation() override; /** Reads the data from disk into the memory buffer provided. */ - void Read(void *buffer) override; + void + Read(void * buffer) override; /*-------- This part of the interfaces deals with writing data. ----- */ @@ -73,28 +76,33 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase * \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 *FileNameToWrite) override; + bool + CanWriteFile(const char * FileNameToWrite) override; /** Set the spacing and dimension information for the set filename. */ - void WriteImageInformation() override; + 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; + void + Write(const void * buffer) override; protected: MGHImageIO(); ~MGHImageIO() override; - void PrintSelf(std::ostream& os, Indent indent) const override; + void + PrintSelf(std::ostream & os, Indent indent) const override; - void ReadVolumeHeader(); + 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 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; @@ -102,35 +110,49 @@ class MGHIO_EXPORT MGHImageIO:public ImageIOBase 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); + bool + IsCompressedFilename(const std::string fname); /// processes the actual data buffer - void SwapBytesIfNecessary(void * const buffer, const unsigned long numberOfPixels); + void + SwapBytesIfNecessary(void * const buffer, const unsigned long numberOfPixels); /// examines the direction cosines and creates encapsulation data // void MriDirCos(); - void WriteHeader(); + void + WriteHeader(); - void WriteData(const void* buffer); + void + WriteData(const void * buffer); - void PermuteFrameValues(const void* buffer, char* tempmemory); + void + PermuteFrameValues(const void * buffer, char * tempmemory); - unsigned int GetComponentSize() const override; + unsigned int + GetComponentSize() const override; - std::string GetOrientation( itk::Matrix directions ); + 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 + // 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(); + 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 diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 514c2d237952..40f90168d135 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -26,9 +26,9 @@ namespace itk { /** \class MGHImageIOFactory - * \brief Create instances of MGHImageIO objects using an object factory. - * \ingroup MGHIO - */ + * \brief Create instances of MGHImageIO objects using an object factory. + * \ingroup MGHIO + */ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: @@ -41,9 +41,11 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase using ConstPointer = SmartPointer; /** Class methods used to interface with the registered factories **/ - const char * GetITKSourceVersion(void) const override; + const char * + GetITKSourceVersion(void) const override; - const char * GetDescription(void) const override; + const char * + GetDescription(void) const override; /** Method for class instantiation **/ itkFactorylessNewMacro(Self); @@ -52,7 +54,8 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase itkTypeMacro(MGHImageIOFactory, ObjectFactoryBase); /** Register one factory of this type */ - static void RegisterOneFactory(void) + static void + RegisterOneFactory(void) { MGHImageIOFactory::Pointer MGHFactory = MGHImageIOFactory::New(); @@ -62,7 +65,8 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase protected: MGHImageIOFactory(); ~MGHImageIOFactory() override; - void PrintSelf(std::ostream & os, Indent indent) const override; + void + PrintSelf(std::ostream & os, Indent indent) const override; }; } // end namespace itk diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 5e5102c20600..5ecad010f742 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -23,23 +23,24 @@ namespace itk { -//VALID file extensions +// 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 MatrixType = itk::Matrix; using VectorType = itk::Vector; -static MatrixType GetRAS2LPS() - { +static MatrixType +GetRAS2LPS() +{ MatrixType RAS2LAS; RAS2LAS.SetIdentity(); - RAS2LAS[0][0]=-1.0; - RAS2LAS[1][1]=-1.0; - RAS2LAS[2][2]= 1.0; + RAS2LAS[0][0] = -1.0; + RAS2LAS[1][1] = -1.0; + RAS2LAS[2][2] = 1.0; return RAS2LAS; - } +} // ------------------------------- // @@ -49,11 +50,10 @@ static MatrixType GetRAS2LPS() template int -MGHImageIO -::TRead(TOutType & outValue) +MGHImageIO ::TRead(TOutType & outValue) { TDiskType onDiskValue; - const int result = ::gzread(this->m_GZFile, &onDiskValue, sizeof(TDiskType) ); + const int result = ::gzread(this->m_GZFile, &onDiskValue, sizeof(TDiskType)); itk::ByteSwapper::SwapFromSystemToBigEndian(&onDiskValue); outValue = static_cast(onDiskValue); return result; @@ -61,40 +61,38 @@ ::TRead(TOutType & outValue) template int -MGHImageIO -::TWrite(const TInType inValue) +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)); - } + if (this->m_IsCompressed) + { + return ::gzwrite(this->m_GZFile, &onDiskValue, sizeof(TDiskType)); + } else - { - this->m_Output.write(reinterpret_cast(&onDiskValue),sizeof(TDiskType)); + { + 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) +MGHImageIO ::TWrite(const char * buf, const unsigned long count) { - if(this->m_IsCompressed) + if (this->m_IsCompressed) + { + const unsigned long int result = ::gzwrite(this->m_GZFile, buf, count); + if (result != count) { - const unsigned long int result = ::gzwrite( this->m_GZFile, buf, count ); - if( result != count ) - { - itkExceptionMacro( << " Failed to write " << count << ", only wrote " << result); - } - return result; + itkExceptionMacro(<< " Failed to write " << count << ", only wrote " << result); } + return result; + } else - { - this->m_Output.write(buf,count); + { + this->m_Output.write(buf, count); return this->m_Output.good() ? count : 0; - } + } } // -------------------------------------- // @@ -102,23 +100,20 @@ ::TWrite(const char *buf,const unsigned long count) // -MGHImageIO -::MGHImageIO() +MGHImageIO ::MGHImageIO() { this->SetNumberOfDimensions(3); std::fill(m_Dimensions.begin(), m_Dimensions.end(), 0U); - m_ByteOrder = ( ByteSwapper::SystemIsBigEndian() ) ? BigEndian : LittleEndian; + m_ByteOrder = (ByteSwapper::SystemIsBigEndian()) ? BigEndian : LittleEndian; } -MGHImageIO -::~MGHImageIO() +MGHImageIO ::~MGHImageIO() { - //Nothing to do in destructor + // Nothing to do in destructor } bool -MGHImageIO -::IsCompressedFilename(const std::string fname) +MGHImageIO ::IsCompressedFilename(const std::string fname) { // // Originally MGHImageIO allowed ".mgh", ".mgz", @@ -131,151 +126,136 @@ ::IsCompressedFilename(const std::string fname) // // So the bare '.gz' extension is no longer recognized. const std::string lastExtension = itksys::SystemTools::GetFilenameLastExtension(fname.c_str()); - if(lastExtension == __MGZ_EXT) - { + if (lastExtension == __MGZ_EXT) + { return true; - } - if(lastExtension == __GZ_EXT) + } + if (lastExtension == __GZ_EXT) + { + const std::string fnameWithoutLastExtension = itksys::SystemTools::GetFilenameWithoutLastExtension(fname); + const std::string penultimateExtension = itksys::SystemTools::GetFilenameLastExtension(fnameWithoutLastExtension); + if (penultimateExtension == __MGH_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) +MGHImageIO ::CanReadFile(const char * FileNameToRead) { const std::string filename(FileNameToRead); - if( filename == "" ) - { + if (filename == "") + { 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) ) - { + if (extension == __MGH_EXT || this->IsCompressedFilename(filename)) + { return true; - } + } return false; } void -MGHImageIO -::PrintSelf(std::ostream& os, Indent indent) const +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 << "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() +MGHImageIO ::ReadImageInformation() { - this->m_GZFile = gzopen( m_FileName.c_str(), "rb"); - if( !this->m_GZFile ) - { + 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() +MGHImageIO ::ReadVolumeHeader() { // check file reading - if( !this->m_GZFile ) - { + 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] ); + } + 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? + 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 ) - { + switch (type) + { case MRI_UCHAR: - { + { m_ComponentType = UCHAR; - } - break; + } + break; case MRI_INT: - { + { m_ComponentType = INT; - } - break; + } + break; case MRI_FLOAT: - { + { m_ComponentType = FLOAT; - } - break; + } + break; case MRI_SHORT: - { + { m_ComponentType = SHORT; - } - break; + } + break; case MRI_TENSOR: - { + { m_ComponentType = FLOAT; m_NumberOfComponents = 9; - } - break; + } + break; default: itkExceptionMacro(<< " Unknown data type " << type << " using float by default."); m_ComponentType = 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 ) + this->TRead(RASgood); + if (RASgood) + { + for (size_t nSpacing = 0; nSpacing < 3; ++nSpacing) { - for( size_t nSpacing = 0; nSpacing < 3; ++nSpacing ) - { - this->TRead( m_Spacing[nSpacing] ); - } + this->TRead(m_Spacing[nSpacing]); + } /* From http://www.nmr.mgh.harvard.edu/~tosa/#coords: To go from freesurfer voxel coordinates to RAS coordinates, they use: @@ -305,37 +285,37 @@ ::ReadVolumeHeader() // 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 c = 0; c < 3; ++c) + { + for (unsigned int r = 0; r < 3; ++r) // NOTE: Data stored row-major form, so traverse rows first { - for( unsigned int r = 0; r < 3; ++r ) //NOTE: Data stored row-major form, so traverse rows first - { - this->TRead( MGHdirMatrix[r][c] ); - } + 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 ) - { + 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 ) + for (size_t r = 0; r < 3; ++r) { - this->TRead( MGHcenterVoxel[ui]); + 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; + VectorType ITKcenterVoxel = GetRAS2LPS() * MGHcenterVoxel; // MriDirCos(); // convert direction cosines @@ -352,227 +332,200 @@ ::ReadVolumeHeader() spcing[1][1] = m_Spacing[1]; spcing[2][2] = m_Spacing[2]; - VectorType ITKorigin = ITKcenterVoxel - ( ITKdirMatrix * spcing * fc ); + 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); + 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) ) - { + if (this->TRead(fBufTR)) + { itk::MetaDataDictionary & thisDic = this->GetMetaDataDictionary(); - itk::EncapsulateMetaData(thisDic, - std::string("TR"), - fBufTR); + itk::EncapsulateMetaData(thisDic, std::string("TR"), fBufTR); // try to read flipAngle float fBufFA; - if( this->TRead( fBufFA ) ) - { - itk::EncapsulateMetaData(thisDic, - std::string("FlipAngle"), - 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); + 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); + 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); - } + if (this->TRead(fBufFOV)) + { + itk::EncapsulateMetaData(thisDic, std::string("FoV"), fBufFOV); } } } } + } } void -MGHImageIO -::Read(void* pData) +MGHImageIO ::Read(void * pData) { - this->m_GZFile = gzopen( m_FileName.c_str(), "rb"); - if( !this->m_GZFile ) - { + 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() ); + 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 ); + 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]; + 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 ) - { + for (unsigned int frameIndex = 0; frameIndex < m_NumberOfComponents; ++frameIndex) + { // read current frame - gzread( this->m_GZFile, pBuffer, frameSize ); + 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 ui = 0; ui < numPixels; ++ui, pSrc += componentSize, pDst += pixelSize) + { + for (unsigned int byteCount = 0; byteCount < componentSize; ++byteCount) { - for( unsigned int byteCount = 0; - byteCount < componentSize; ++byteCount ) - { *(pDst + byteCount) = *(pSrc + byteCount); - } - } // next ui - } // next frameIndex + } + } // next ui + } // next frameIndex // clear resources delete[] pBuffer; - } + } else - { - gzread( this->m_GZFile, pData, frameSize); - } + { + gzread(this->m_GZFile, pData, frameSize); + } gzclose(this->m_GZFile); - SwapBytesIfNecessary( pData, numPixels * m_NumberOfComponents ); + SwapBytesIfNecessary(pData, numPixels * m_NumberOfComponents); -} // end Read function +} // end Read function void -MGHImageIO -::SwapBytesIfNecessary(void * const buffer, - const unsigned long numberOfPixels) +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 ) - { + switch (m_ComponentType) + { case UCHAR: - { - ByteSwapper::SwapRangeFromSystemToBigEndian( (unsigned char *)buffer, - numberOfPixels); - } - break; + { + ByteSwapper::SwapRangeFromSystemToBigEndian((unsigned char *)buffer, numberOfPixels); + } + break; case SHORT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian( (short *)buffer, - numberOfPixels); - } - break; + { + ByteSwapper::SwapRangeFromSystemToBigEndian((short *)buffer, numberOfPixels); + } + break; case INT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian( (int *)buffer, - numberOfPixels); - } - break; + { + ByteSwapper::SwapRangeFromSystemToBigEndian((int *)buffer, numberOfPixels); + } + break; case FLOAT: - { - ByteSwapper::SwapRangeFromSystemToBigEndian( (float *)buffer, - numberOfPixels); - } - break; + { + ByteSwapper::SwapRangeFromSystemToBigEndian((float *)buffer, numberOfPixels); + } + break; default: ExceptionObject exception(__FILE__, __LINE__); exception.SetDescription("Pixel Type Unknown"); throw exception; - } // end switch + } // end switch } bool -MGHImageIO -::CanWriteFile(const char* name) +MGHImageIO ::CanWriteFile(const char * name) { const std::string filename(name); - if( filename.empty() ) - { + if (filename.empty()) + { itkExceptionMacro(<< "A FileName must be specified."); return false; - } + } - //TODO: Use ITK Extension extractor + // TODO: Use ITK Extension extractor const std::string extension = itksys::SystemTools::GetFilenameExtension(filename.c_str()); - if( extension != __MGH_EXT && !this->IsCompressedFilename(filename)) - { + if (extension != __MGH_EXT && !this->IsCompressedFilename(filename)) + { return false; - } + } return true; } void -MGHImageIO -::OpenFile() +MGHImageIO ::OpenFile() { - if(this->m_IsCompressed) - { + if (this->m_IsCompressed) + { this->m_GZFile = gzopen(m_FileName.c_str(), "wb"); - if( this->m_GZFile == nullptr ) - { + 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()) { - 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() +MGHImageIO ::CloseFile() { - if(this->m_IsCompressed) - { + if (this->m_IsCompressed) + { gzclose(this->m_GZFile); - } + } else - { + { this->m_Output.close(); - } + } } void -MGHImageIO -::WriteImageInformation() +MGHImageIO ::WriteImageInformation() { this->m_IsCompressed = this->IsCompressedFilename(this->m_FileName); this->OpenFile(); @@ -581,8 +534,7 @@ ::WriteImageInformation() } void -MGHImageIO -::Write(const void* buffer) +MGHImageIO ::Write(const void * buffer) { this->m_IsCompressed = this->IsCompressedFilename(this->m_FileName); this->OpenFile(); @@ -592,229 +544,215 @@ ::Write(const void* buffer) } void -MGHImageIO -::WriteHeader() +MGHImageIO ::WriteHeader() { // version constexpr int mghVersion = 1; - this->TWrite( mghVersion ); + this->TWrite(mghVersion); // dimensions - for( size_t ui = 0; ui < 3; ++ui ) - { - this->TWrite( m_Dimensions[ui] ); - } + for (size_t ui = 0; ui < 3; ++ui) + { + this->TWrite(m_Dimensions[ui]); + } // nframes - this->TWrite( m_NumberOfComponents ); + this->TWrite(m_NumberOfComponents); // type - switch( m_ComponentType ) - { + switch (m_ComponentType) + { case UCHAR: - { - this->TWrite(MRI_UCHAR); - } - break; + { + this->TWrite(MRI_UCHAR); + } + break; case INT: - { - this->TWrite(MRI_INT); - } - break; + { + this->TWrite(MRI_INT); + } + break; case FLOAT: - { - this->TWrite(MRI_FLOAT); - } - break; + { + this->TWrite(MRI_FLOAT); + } + break; case SHORT: - { - this->TWrite(MRI_SHORT); - } - break; - default: - itkExceptionMacro( - << "MGHImageIO supports unsigned char, int, float and short"); - + { + this->TWrite(MRI_SHORT); } + break; + default: + itkExceptionMacro(<< "MGHImageIO supports unsigned char, int, float and short"); + } // dof !?! -> default value = 1 - this->TWrite(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); + this->TWrite(1); // spacing - for( unsigned int ui = 0; ui < 3; ++ui ) - { - this->TWrite(m_Spacing[ui]); - } + 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 ) + for (unsigned int c = 0; c < 3; ++c) + { + const std::vector & dir_line = GetDirection(c); + for (unsigned int r = 0; r < 3; ++r) { - 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 + } + 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 c = 0; c < 3; ++c) + { + for (unsigned int r = 0; r < 3; ++r) // Write in row-major order { - for( unsigned int r = 0; r < 3; ++r ) //Write in row-major order - { - this->TWrite(MGHdirMatrix[r][c]); - } + 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]; + 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]); - } + 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); - } + for (size_t i = 0; i < FS_UNUSED_HEADER_SIZE; ++i) + { + this->TWrite(zerobyte); + } } void -MGHImageIO -::WriteData(const void* buffer) +MGHImageIO ::WriteData(const void * buffer) { // swap bytes if necessary - const unsigned int numPixels = m_Dimensions[0] - * m_Dimensions[1] * m_Dimensions[2]; + 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]; + auto * tempmemory = new char[numbytes]; // re-arrange data in frames - if( m_NumberOfComponents > 1 ) - { + if (m_NumberOfComponents > 1) + { PermuteFrameValues(buffer, tempmemory); - } + } else - { + { memcpy(tempmemory, buffer, numbytes); - } + } this->SwapBytesIfNecessary(tempmemory, numvalues); - this->TWrite(tempmemory,this->GetImageSizeInBytes()); + 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, "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, "TE", fScanBuffer)) + { + this->TWrite(fScanBuffer); + } // end TE - if( ExposeMetaData(thisDic, "TI", fScanBuffer) ) - { - this->TWrite(fScanBuffer); - } // end TI + if (ExposeMetaData(thisDic, "TI", fScanBuffer)) + { + this->TWrite(fScanBuffer); + } // end TI - if( ExposeMetaData(thisDic, "FoV", fScanBuffer) ) - { - this->TWrite(fScanBuffer); - } // end FoV + if (ExposeMetaData(thisDic, "FoV", fScanBuffer)) + { + this->TWrite(fScanBuffer); + } // end FoV // no need to close the stream } void -MGHImageIO -::PermuteFrameValues(const void* buffer, - char* tempmemory) +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 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; + const auto * pSrc = (const char *)buffer; + auto * pDst = (char *)tempmemory; - for( unsigned int pixelIndex = 0; - pixelIndex < numPixels; ++pixelIndex, pDst += valueSize ) + for (unsigned int pixelIndex = 0; pixelIndex < numPixels; ++pixelIndex, pDst += valueSize) + { + for (unsigned int componentIndex = 0; componentIndex < m_NumberOfComponents; ++componentIndex, pSrc += 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 + std::copy(pSrc, pSrc + valueSize, pDst + frameSize * componentIndex); + } // next component index + } // next pixelIndex } unsigned int -MGHImageIO -::GetComponentSize() const +MGHImageIO ::GetComponentSize() const { unsigned int returnValue; - switch( m_ComponentType ) + switch (m_ComponentType) + { + case UCHAR: { - case UCHAR: - { returnValue = sizeof(unsigned char); - } + } break; - case SHORT: - { + case SHORT: + { returnValue = sizeof(short); - } + } break; - case INT: - { + case INT: + { returnValue = sizeof(int); - } + } break; - case FLOAT: - { + case FLOAT: + { returnValue = sizeof(float); - } - break; - default: - itkExceptionMacro( - << "MGHImageIO supports unsigned char, int, float and short"); } + break; + default: + itkExceptionMacro(<< "MGHImageIO supports unsigned char, int, float and short"); + } return returnValue; } @@ -824,48 +762,47 @@ ::GetComponentSize() const * 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 ) +MGHImageIO ::GetOrientation(itk::Matrix directions) { std::string orientation(""); - for( int cAxes = 0; cAxes < 3; cAxes++ ) + 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 (fabs(sag) > fabs(cor) && fabs(sag) > fabs(ax)) { - 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( fabs(sag) > fabs(cor) && fabs(sag) > fabs(ax) ) + if (sag > 0) { - if( sag > 0 ) - { orientation += "R"; - } + } else - { + { orientation += "L"; - } - continue; } - if( fabs(cor) > fabs(ax) ) + continue; + } + if (fabs(cor) > fabs(ax)) + { + if (cor > 0) { - if( cor > 0 ) - { orientation += "A"; - } + } else - { + { orientation += "P"; - } - continue; } - if( ax > 0 ) - { + continue; + } + if (ax > 0) + { orientation += "S"; - } + } else - { + { orientation += "I"; - } } + } return orientation; } } // end namespace itk diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 9088649f3f9a..4522a78b48c9 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -22,20 +22,16 @@ namespace itk { -void MGHImageIOFactory::PrintSelf(std::ostream &, Indent) const +void +MGHImageIOFactory::PrintSelf(std::ostream &, Indent) const {} MGHImageIOFactory::MGHImageIOFactory() { - this->RegisterOverride("itkImageIOBase", - "itkMGHImageIO", - "MGH Image IO", - 1, - CreateObjectFunction::New() ); + this->RegisterOverride("itkImageIOBase", "itkMGHImageIO", "MGH Image IO", 1, CreateObjectFunction::New()); } -MGHImageIOFactory::~MGHImageIOFactory() -{} +MGHImageIOFactory::~MGHImageIOFactory() {} const char * MGHImageIOFactory::GetITKSourceVersion(void) const @@ -51,15 +47,16 @@ MGHImageIOFactory::GetDescription() const // Undocumented API used to register during static initialization. // DO NOT CALL DIRECTLY. -static bool MGHImageIOFactoryHasBeenRegistered=false; +static bool MGHImageIOFactoryHasBeenRegistered = false; -void MGHIO_EXPORT MGHImageIOFactoryRegister__Private(void) +void MGHIO_EXPORT + MGHImageIOFactoryRegister__Private(void) { - if( ! MGHImageIOFactoryHasBeenRegistered ) - { + if (!MGHImageIOFactoryHasBeenRegistered) + { MGHImageIOFactoryHasBeenRegistered = true; MGHImageIOFactory::RegisterOneFactory(); - } + } } } // end namespace itk diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 79940b0c1cb9..d6e505adabd4 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -27,86 +27,90 @@ #include "itkMGHImageIOTest.h" #include -int itkMGHImageIOTest(int ac, char* av[]) +int +itkMGHImageIOTest(int ac, char * av[]) { itk::ObjectFactoryBase::UnRegisterAllFactories(); itk::MGHImageIOFactory::RegisterOneFactory(); - if(ac < 3 ) - { - std::cerr << "ERROR: Incorrect number of arguments [ImageFileNameRead ImageFileNameWrite]" << std::endl; + if (ac < 3) + { + std::cerr + << "ERROR: Incorrect number of arguments [ImageFileNameRead ImageFileNameWrite]" + << std::endl; std::cerr << "Only " << ac << " arguments given." << std::endl; return EXIT_FAILURE; - } - for(int i =0; i < ac; ++i) - { + } + for (int i = 0; i < ac; ++i) + { std::cout << i << " av= " << av[i] << std::endl; - } + } // // first argument is passing in the writable directory to do all testing itksys::SystemTools::ChangeDirectory(av[1]); static bool firstTime = true; - if(firstTime) - { - itk::ObjectFactoryBase::RegisterFactory(itk::MGHImageIOFactory::New() ); + if (firstTime) + { + itk::ObjectFactoryBase::RegisterFactory(itk::MGHImageIOFactory::New()); firstTime = false; - } + } const std::string TestMode(av[2]); bool returnSucceeded = true; - if( TestMode == std::string("FactoryCreationTest")) - //Tests added to increase code coverage. + if (TestMode == std::string("FactoryCreationTest")) + // Tests added to increase code coverage. + { + itk::MGHImageIOFactory::Pointer MyFactoryTest = itk::MGHImageIOFactory::New(); + if (MyFactoryTest.IsNull()) { - 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")) - { + // 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. - { + // 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(av[3]); const std::string imageToBeWritten(av[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(); + itk::ImageFileWriter::Pointer testFactoryWriter = itk::ImageFileWriter::New(); testFactoryWriter->SetFileName(imageToBeWritten); testFactoryWriter->SetInput(input); testFactoryWriter->Update(); - itk::ImageFileReader::Pointer testFactoryReader=itk::ImageFileReader::New(); + itk::ImageFileReader::Pointer testFactoryReader = itk::ImageFileReader::New(); testFactoryReader->SetFileName(imageToBeWritten); testFactoryReader->Update(); ImageType::Pointer new_image = testFactoryReader->GetOutput(); - } - catch (itk::ExceptionObject &e) - { + } + catch (itk::ExceptionObject & e) + { e.Print(std::cerr); returnSucceeded &= false; - } } - else if( TestMode == "TestOriginWriteTest" ) - { + } + else if (TestMode == "TestOriginWriteTest") + { using ImageType = itk::Image; ImageType::Pointer input; - const std::string imageToBeRead(av[3]); - const std::string imageToBeWritten(av[4]); + const std::string imageToBeRead(av[3]); + const std::string imageToBeWritten(av[4]); try - { + { std::cout << "Reading Image: " << imageToBeRead << std::endl; input = itk::IOTestHelper::ReadImage(imageToBeRead); std::cout << input << std::endl; @@ -117,37 +121,34 @@ int itkMGHImageIOTest(int ac, char* av[]) reference_origin[2] = -890.0; input->SetOrigin(reference_origin); - itk::ImageFileWriter::Pointer testFactoryWriter=itk::ImageFileWriter::New(); + itk::ImageFileWriter::Pointer testFactoryWriter = itk::ImageFileWriter::New(); testFactoryWriter->SetFileName(imageToBeWritten); testFactoryWriter->SetInput(input); testFactoryWriter->Update(); - itk::ImageFileReader::Pointer testFactoryReader=itk::ImageFileReader::New(); + itk::ImageFileReader::Pointer testFactoryReader = itk::ImageFileReader::New(); testFactoryReader->SetFileName(imageToBeWritten); testFactoryReader->Update(); - ImageType::Pointer new_image = testFactoryReader->GetOutput(); + 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; + 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) - { + } + 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/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index f75381cbc020..9c90a9592493 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -33,7 +33,6 @@ #include "itkEuler3DTransform.h" - template typename itk::Image::Pointer itkMGHImageIOTestGenerateRandomImage(const unsigned int size) @@ -43,46 +42,45 @@ itkMGHImageIOTestGenerateRandomImage(const unsigned int size) eulerTransform->SetIdentity(); // 15 degrees in radians - const double angleX = 15.0 * std::atan( 1.0 ) / 45.0; + 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; + 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; + 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; - + 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 - } + { + direction[i][j] = static_cast(direction[i][j]); // Truncate for testing purposes } + } - typename ImageType::SizeType sz; + typename ImageType::SizeType sz; typename ImageType::SpacingType spacing; - typename ImageType::PointType origin; + 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); - } + { + sz[i] = size; + spacing[i] = static_cast(i + 1.234567); + origin[i] = static_cast(1234.5); + } - typename itk::RandomImageSource::Pointer source - = itk::RandomImageSource::New(); + typename itk::RandomImageSource::Pointer source = itk::RandomImageSource::New(); source->SetDirection(direction); source->SetSize(sz); @@ -90,41 +88,36 @@ itkMGHImageIOTestGenerateRandomImage(const unsigned int size) source->SetSpacing(spacing); source->Update(); - typename ImageType::Pointer outImage=source->GetOutput(); + typename ImageType::Pointer outImage = source->GetOutput(); - { + { itk::MetaDataDictionary & thisDic = outImage->GetMetaDataDictionary(); - //Add meta data to dictionary + // 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); + 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); + itk::EncapsulateMetaData(thisDic, std::string("FlipAngle"), fBufFA); // TE - itk::EncapsulateMetaData(thisDic, - std::string("TE"), fBufTE); + itk::EncapsulateMetaData(thisDic, std::string("TE"), fBufTE); // TI - itk::EncapsulateMetaData(thisDic, - std::string("TI"), fBufTI); + itk::EncapsulateMetaData(thisDic, std::string("TI"), fBufTI); // FOV - itk::EncapsulateMetaData(thisDic, - std::string("FoV"), fBufFOV); - } + itk::EncapsulateMetaData(thisDic, std::string("FoV"), fBufFOV); + } return outImage; } -//Template specialization for itkDiffusionTensor3D -template<> -itk::Image,3>::Pointer -itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsigned int size) +// Template specialization for itkDiffusionTensor3D +template <> +itk::Image, 3>::Pointer +itkMGHImageIOTestGenerateRandomImage, 3>(unsigned int size) { - using TensorImageType = itk::Image,3>; + using TensorImageType = itk::Image, 3>; using TensorImagePointer = TensorImageType::Pointer; const double dir1[3] = { 0, -1, 0 }; @@ -132,19 +125,19 @@ itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsign 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) - { + 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 ); - } + spacing[i] = static_cast(i * 3.21 + 1.0); + origin[i] = static_cast(1.23456); + } TensorImagePointer tensorImage = TensorImageType::New(); tensorImage->SetRegions(sz); @@ -153,41 +146,38 @@ itkMGHImageIOTestGenerateRandomImage< itk::DiffusionTensor3D , 3 >(unsign tensorImage->Allocate(); tensorImage->SetDirection(direction); - itk::DiffusionTensor3D pix; - using ScalarImageType = itk::Image; + 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); + 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) + } + itk::ImageRegionIteratorWithIndex tensorIt(tensorImage, tensorImage->GetLargestPossibleRegion()); + for (tensorIt.GoToBegin(); !tensorIt.IsAtEnd(); ++tensorIt) + { + for (unsigned int i = 0; i < pix.Size(); ++i) { - 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); + 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) +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(); + 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); @@ -196,69 +186,72 @@ bool itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, typename ImageType::Pointer reference_image; if (inputFile != "null") - { - typename itk::ImageFileReader::Pointer tmpReader - = itk::ImageFileReader::New(); + { + 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) - { + } + catch (itk::ExceptionObject & e) + { std::cerr << e << std::endl; return EXIT_FAILURE; - } - reference_image = tmpReader->GetOutput(); } + 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"); + if (compression == true) + { + writer->UseCompressionOn(); } - catch(itk::ExceptionObject &e) + 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; + 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(); + typename ImageType::Pointer test_image = reader->GetOutput(); test_image->Print(std::cout); std::cout << std::endl; @@ -269,57 +262,53 @@ bool itkMGHImageIOTestReadWriteTest(std::string fn, unsigned int size, // 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) + for (a.GoToBegin(), b.GoToBegin(); !a.IsAtEnd(); ++a, ++b) + { + if (b.Get() != a.Get()) { - 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 ) - { + } + 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 ) ) - { + 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 ) ) - { + } + if (!itk::Math::FloatAlmostEqual(test_image->GetOrigin()[idx], reference_image->GetOrigin()[idx], 100000, 1e-1)) + { isFailingOrigin = true; - } - for( int idx2 = 0; idx2 < 3; ++idx2 ) + } + for (int idx2 = 0; idx2 < 3; ++idx2) + { + if (!itk::Math::FloatAlmostEqual( + test_image->GetDirection()[idx][idx2], reference_image->GetDirection()[idx][idx2], 4, 1e-7)) { - 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); + // 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_ +#endif // itkMGHImageIOTest_h_ From c4ab54a8c0d151e81854499627a6443c172cacb8 Mon Sep 17 00:00:00 2001 From: Mathew Seng Date: Tue, 18 Feb 2020 07:50:01 -0600 Subject: [PATCH 44/68] ENH: Fix new enum changes from ITK and failed KWStyle test. --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 3 +- .../IO/MGHIO/include/itkMGHImageIOFactory.h | 3 +- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 41 ++++++++++--------- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 3 +- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 2 +- 5 files changed, 28 insertions(+), 24 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index c0926fb92407..b73725e70116 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ * limitations under the License. * *=========================================================================*/ + #ifndef itkMGHImageIO_h #define itkMGHImageIO_h diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 40f90168d135..6c24ec7763ed 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ * limitations under the License. * *=========================================================================*/ + #ifndef itkMGHImageIOFactory_h #define itkMGHImageIOFactory_h diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 5ecad010f742..1e26ee20fcec 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ * limitations under the License. * *=========================================================================*/ + #include "itkMGHImageIO.h" #include "itkByteSwapper.h" #include "itkMetaDataObject.h" @@ -104,7 +105,7 @@ MGHImageIO ::MGHImageIO() { this->SetNumberOfDimensions(3); std::fill(m_Dimensions.begin(), m_Dimensions.end(), 0U); - m_ByteOrder = (ByteSwapper::SystemIsBigEndian()) ? BigEndian : LittleEndian; + m_ByteOrder = (ByteSwapper::SystemIsBigEndian()) ? IOByteOrderEnum::BigEndian : IOByteOrderEnum::LittleEndian; } MGHImageIO ::~MGHImageIO() @@ -217,33 +218,33 @@ MGHImageIO ::ReadVolumeHeader() { case MRI_UCHAR: { - m_ComponentType = UCHAR; + m_ComponentType = IOComponentEnum::UCHAR; } break; case MRI_INT: { - m_ComponentType = INT; + m_ComponentType = IOComponentEnum::INT; } break; case MRI_FLOAT: { - m_ComponentType = FLOAT; + m_ComponentType = IOComponentEnum::FLOAT; } break; case MRI_SHORT: { - m_ComponentType = SHORT; + m_ComponentType = IOComponentEnum::SHORT; } break; case MRI_TENSOR: { - m_ComponentType = FLOAT; + m_ComponentType = IOComponentEnum::FLOAT; m_NumberOfComponents = 9; } break; default: itkExceptionMacro(<< " Unknown data type " << type << " using float by default."); - m_ComponentType = FLOAT; + m_ComponentType = IOComponentEnum::FLOAT; } // Next short says whether RAS registration information is good. @@ -444,22 +445,22 @@ MGHImageIO ::SwapBytesIfNecessary(void * const buffer, const unsigned long numbe switch (m_ComponentType) { - case UCHAR: + case IOComponentEnum::UCHAR: { ByteSwapper::SwapRangeFromSystemToBigEndian((unsigned char *)buffer, numberOfPixels); } break; - case SHORT: + case IOComponentEnum::SHORT: { ByteSwapper::SwapRangeFromSystemToBigEndian((short *)buffer, numberOfPixels); } break; - case INT: + case IOComponentEnum::INT: { ByteSwapper::SwapRangeFromSystemToBigEndian((int *)buffer, numberOfPixels); } break; - case FLOAT: + case IOComponentEnum::FLOAT: { ByteSwapper::SwapRangeFromSystemToBigEndian((float *)buffer, numberOfPixels); } @@ -561,22 +562,22 @@ MGHImageIO ::WriteHeader() // type switch (m_ComponentType) { - case UCHAR: + case IOComponentEnum::UCHAR: { this->TWrite(MRI_UCHAR); } break; - case INT: + case IOComponentEnum::INT: { this->TWrite(MRI_INT); } break; - case FLOAT: + case IOComponentEnum::FLOAT: { this->TWrite(MRI_FLOAT); } break; - case SHORT: + case IOComponentEnum::SHORT: { this->TWrite(MRI_SHORT); } @@ -730,22 +731,22 @@ MGHImageIO ::GetComponentSize() const unsigned int returnValue; switch (m_ComponentType) { - case UCHAR: + case IOComponentEnum::UCHAR: { returnValue = sizeof(unsigned char); } break; - case SHORT: + case IOComponentEnum::SHORT: { returnValue = sizeof(short); } break; - case INT: + case IOComponentEnum::INT: { returnValue = sizeof(int); } break; - case FLOAT: + case IOComponentEnum::FLOAT: { returnValue = sizeof(float); } diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 4522a78b48c9..e83871dcc4ad 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ * limitations under the License. * *=========================================================================*/ + #include "itkMGHImageIOFactory.h" #include "itkMGHImageIO.h" #include "itkVersion.h" diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index d6e505adabd4..096ff00a0e36 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 2326be96bfa887f00725ed195008b0c48aaf11ce Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sun, 16 Feb 2020 18:26:30 -0600 Subject: [PATCH 45/68] STYLE: Remove redundant void argument lists Find and remove redundant void argument lists. --- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index e83871dcc4ad..220e307acaf4 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -35,7 +35,7 @@ MGHImageIOFactory::MGHImageIOFactory() MGHImageIOFactory::~MGHImageIOFactory() {} const char * -MGHImageIOFactory::GetITKSourceVersion(void) const +MGHImageIOFactory::GetITKSourceVersion() const { return ITK_SOURCE_VERSION; } @@ -51,7 +51,7 @@ MGHImageIOFactory::GetDescription() const static bool MGHImageIOFactoryHasBeenRegistered = false; void MGHIO_EXPORT - MGHImageIOFactoryRegister__Private(void) + MGHImageIOFactoryRegister__Private() { if (!MGHImageIOFactoryHasBeenRegistered) { From 363a4fe736fe69b3f7e7dfb488d2903e8e91c6e5 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sun, 16 Feb 2020 19:08:58 -0600 Subject: [PATCH 46/68] STYLE: Make prototype match definition names Enforce consistency in large projects, where it often happens that a definition of function is refactored, changing the parameter names, but its declaration in header file is not updated. With this check, we can easily find and correct such inconsistencies, keeping declaration and definition always in sync. Unnamed parameters are allowed and are not taken into account when comparing function declarations --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index b73725e70116..1b1ce8ffe71e 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -68,7 +68,7 @@ class MGHIO_EXPORT MGHImageIO : public ImageIOBase /** Reads the data from disk into the memory buffer provided. */ void - Read(void * buffer) override; + Read(void * pData) override; /*-------- This part of the interfaces deals with writing data. ----- */ @@ -78,7 +78,7 @@ class MGHIO_EXPORT MGHImageIO : public ImageIOBase * \return Returns true if this ImageIO can write the file specified. */ bool - CanWriteFile(const char * FileNameToWrite) override; + CanWriteFile(const char * name) override; /** Set the spacing and dimension information for the set filename. */ void From 000000f0e5e06bf287aa3774a18db6d6f9c02c57 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sun, 16 Feb 2020 22:07:45 -0600 Subject: [PATCH 47/68] STYLE: Replace integer literals which are cast to bool. Finds and replaces integer literals which are cast to bool. SRCDIR= #My local SRC BLDDIR= #My local BLD cd run-clang-tidy.py -extra-arg=-D__clang__ -checks=-*,modernize-use-bool-literals -header-filter=.* -fix --- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 220e307acaf4..1cfcbd758e7c 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -29,7 +29,8 @@ MGHImageIOFactory::PrintSelf(std::ostream &, Indent) const MGHImageIOFactory::MGHImageIOFactory() { - this->RegisterOverride("itkImageIOBase", "itkMGHImageIO", "MGH Image IO", 1, CreateObjectFunction::New()); + this->RegisterOverride( + "itkImageIOBase", "itkMGHImageIO", "MGH Image IO", true, CreateObjectFunction::New()); } MGHImageIOFactory::~MGHImageIOFactory() {} From 652e1ba146b19085aad19f94746fad5d46d9e8ad Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Mon, 17 Feb 2020 14:30:04 -0600 Subject: [PATCH 48/68] STYLE: Prefer = default to explicitly trivial implementations This check replaces default bodies of special member functions with = default;. The explicitly defaulted function declarations enable more opportunities in optimization, because the compiler might treat explicitly defaulted functions as trivial. Additionally, the C++11 use of = default more clearly expreses the intent for the special member functions. --- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 1cfcbd758e7c..3983978d52fb 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -33,7 +33,7 @@ MGHImageIOFactory::MGHImageIOFactory() "itkImageIOBase", "itkMGHImageIO", "MGH Image IO", true, CreateObjectFunction::New()); } -MGHImageIOFactory::~MGHImageIOFactory() {} +MGHImageIOFactory::~MGHImageIOFactory() = default; const char * MGHImageIOFactory::GetITKSourceVersion() const From 0f0ed3473f611cde6725a9a5bc34752045442d42 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Mon, 17 Feb 2020 14:48:39 -0600 Subject: [PATCH 49/68] STYLE: Remove redundant void argument lists Find and remove redundant void argument lists. --- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 6c24ec7763ed..caca233233a2 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -43,10 +43,10 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase /** Class methods used to interface with the registered factories **/ const char * - GetITKSourceVersion(void) const override; + GetITKSourceVersion() const override; const char * - GetDescription(void) const override; + GetDescription() const override; /** Method for class instantiation **/ itkFactorylessNewMacro(Self); @@ -56,7 +56,7 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase /** Register one factory of this type */ static void - RegisterOneFactory(void) + RegisterOneFactory() { MGHImageIOFactory::Pointer MGHFactory = MGHImageIOFactory::New(); From f320627bff89ae784d5e458caba4aeefc23f59cd Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Mon, 17 Feb 2020 23:52:09 -0600 Subject: [PATCH 50/68] PERF: readability container size empty The emptiness of a container should be checked using the empty() method instead of the size() method. It is not guaranteed that size() is a constant-time function, and it is generally more efficient and also shows clearer intent to use empty(). Furthermore some containers may implement the empty() method but not implement the size() method. Using empty() whenever possible makes it easier to switch to another container in the future. SRCDIR= #My local SRC BLDDIR= #My local BLD cd run-clang-tidy.py -extra-arg=-D__clang__ -checks=-*,readability-container-size-empty -header-filter=.* -fix --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 1e26ee20fcec..92b3e39a4902 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -148,7 +148,7 @@ MGHImageIO ::CanReadFile(const char * FileNameToRead) { const std::string filename(FileNameToRead); - if (filename == "") + if (filename.empty()) { itkExceptionMacro(<< "A FileName must be specified."); return false; From 019ee6df37513d85ddcb56ffc3a207cac0e88b1c Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Wed, 19 Feb 2020 10:45:25 -0600 Subject: [PATCH 51/68] DOC: Update copyright assignment to NumFOCUS The mission of NumFOCUS is to promote open practices in research, data, and scientific computing. https://numfocus.org --- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 9c90a9592493..93a2ed3cbcbe 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -1,6 +1,6 @@ /*========================================================================= * - * Copyright Insight Software Consortium + * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From e6ece2e89a819ea683ebda1a4041a5ba95114998 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 29 Feb 2020 16:06:48 -0600 Subject: [PATCH 52/68] ENH: Make similar to template --- Modules/IO/MGHIO/CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index ae6ceb70ac4f..f9cda3eb5254 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,5 +1,9 @@ cmake_minimum_required(VERSION 3.10.2) -project(MGHIO) + +project(MGHIO + VERSION 5.1.0 #Version should track with ITK + LANGUAGES CXX C) + set(MGHIO_LIBRARIES MGHIO) if(NOT ITK_SOURCE_DIR) From a96deb673c39bf9f392216a09b99ae14aa897543 Mon Sep 17 00:00:00 2001 From: Mathew Seng Date: Wed, 14 Oct 2020 10:34:06 -0500 Subject: [PATCH 53/68] STYLE: Rename ITK_DISALLOW_COPY_AND_ASSIGN to ITK_DISALLOW_COPY_AND_MOVE Fixes changes made in #2053. ITK_DISALLOW_COPY_AND_ASSIGN will be used if ITK_FUTURE_LEGACY_REMOVE=OFF. --- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index caca233233a2..1d606fa527ee 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -33,7 +33,7 @@ namespace itk class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase { public: - ITK_DISALLOW_COPY_AND_ASSIGN(MGHImageIOFactory); + ITK_DISALLOW_COPY_AND_MOVE(MGHImageIOFactory); /** Standard class type alias */ using Self = MGHImageIOFactory; From e069a8a26be1d612ecb78dfd5e098ae826f9d915 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Fri, 17 Dec 2021 12:18:40 -0600 Subject: [PATCH 54/68] STYLE: Prefer itk::Math::abs for consistency. --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 92b3e39a4902..46e01e964ed3 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -771,7 +771,7 @@ MGHImageIO ::GetOrientation(itk::Matrix directions) 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 (fabs(sag) > fabs(cor) && fabs(sag) > fabs(ax)) + if (itk::Math::abs(sag) > itk::Math::abs(cor) && itk::Math::abs(sag) > itk::Math::abs(ax)) { if (sag > 0) { @@ -783,7 +783,7 @@ MGHImageIO ::GetOrientation(itk::Matrix directions) } continue; } - if (fabs(cor) > fabs(ax)) + if (itk::Math::abs(cor) > itk::Math::abs(ax)) { if (cor > 0) { From ee3ff5277d5b2531799922eb4ce0aa440bfe1e35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?D=C5=BEenan=20Zuki=C4=87?= Date: Tue, 15 Feb 2022 11:39:16 -0500 Subject: [PATCH 55/68] STYLE: Standardize parameter names to argc and *argv[], replace ac/av This was done in the main repository about a month ago: https://github.com/InsightSoftwareConsortium/ITK/pull/3092 --- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 22 ++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 096ff00a0e36..4632b8842123 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -28,25 +28,25 @@ #include int -itkMGHImageIOTest(int ac, char * av[]) +itkMGHImageIOTest(int argc, char * argv[]) { itk::ObjectFactoryBase::UnRegisterAllFactories(); itk::MGHImageIOFactory::RegisterOneFactory(); - if (ac < 3) + if (argc < 3) { std::cerr << "ERROR: Incorrect number of arguments [ImageFileNameRead ImageFileNameWrite]" << std::endl; - std::cerr << "Only " << ac << " arguments given." << std::endl; + std::cerr << "Only " << argc << " arguments given." << std::endl; return EXIT_FAILURE; } - for (int i = 0; i < ac; ++i) + for (int i = 0; i < argc; ++i) { - std::cout << i << " av= " << av[i] << std::endl; + std::cout << i << " argv= " << argv[i] << std::endl; } // // first argument is passing in the writable directory to do all testing - itksys::SystemTools::ChangeDirectory(av[1]); + itksys::SystemTools::ChangeDirectory(argv[1]); static bool firstTime = true; if (firstTime) @@ -54,7 +54,7 @@ itkMGHImageIOTest(int ac, char * av[]) itk::ObjectFactoryBase::RegisterFactory(itk::MGHImageIOFactory::New()); firstTime = false; } - const std::string TestMode(av[2]); + const std::string TestMode(argv[2]); bool returnSucceeded = true; if (TestMode == std::string("FactoryCreationTest")) @@ -81,8 +81,8 @@ itkMGHImageIOTest(int ac, char * av[]) // testing. { using ImageType = itk::Image; - const std::string imageToBeRead(av[3]); - const std::string imageToBeWritten(av[4]); + const std::string imageToBeRead(argv[3]); + const std::string imageToBeWritten(argv[4]); try { std::cout << "Reading Image: " << imageToBeRead << std::endl; @@ -107,8 +107,8 @@ itkMGHImageIOTest(int ac, char * av[]) { using ImageType = itk::Image; ImageType::Pointer input; - const std::string imageToBeRead(av[3]); - const std::string imageToBeWritten(av[4]); + const std::string imageToBeRead(argv[3]); + const std::string imageToBeWritten(argv[4]); try { std::cout << "Reading Image: " << imageToBeRead << std::endl; From fe9374d9af01e7c59cb93dcec8381556aae6f23b Mon Sep 17 00:00:00 2001 From: Tom Birdsong Date: Tue, 31 May 2022 14:55:53 -0400 Subject: [PATCH 56/68] ENH: Bump ITK and change http to https --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 4 ++-- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 2 +- Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx | 2 +- Modules/IO/MGHIO/test/itkMGHImageIOTest.h | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index 1b1ce8ffe71e..cbf73c441d6e 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 1d606fa527ee..85acd89ebf5c 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 46e01e964ed3..1286daf5ea8f 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, @@ -258,7 +258,7 @@ MGHImageIO ::ReadVolumeHeader() this->TRead(m_Spacing[nSpacing]); } /* - From http://www.nmr.mgh.harvard.edu/~tosa/#coords: + 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) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 3983978d52fb..5376df69420c 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx index 4632b8842123..3e711920bdc3 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.cxx @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, diff --git a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h index 93a2ed3cbcbe..66c3c756823d 100644 --- a/Modules/IO/MGHIO/test/itkMGHImageIOTest.h +++ b/Modules/IO/MGHIO/test/itkMGHImageIOTest.h @@ -6,7 +6,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0.txt + * 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, From 12490eeade8db8125ec13601d839cbe1ef57dac9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20Haitz=20Legarreta=20Gorro=C3=B1o?= Date: Sat, 11 Nov 2023 16:20:03 -0500 Subject: [PATCH 57/68] BUG: Use the literal superclass name in itkTypeMacro Use the literal superclass name instead of the `Superclass` alias in `itkTypeMacro`: the string is used in an ITK macro which is using the input for run-time type information (although currently not using the superclass input): https://github.com/InsightSoftwareConsortium/ITK/blob/8844ee6549ebdc1294a17d471f8a65311440bd74/Modules/Core/Common/include/itkMacro.h#L438 --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index cbf73c441d6e..a850d32d1db1 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -50,7 +50,7 @@ class MGHIO_EXPORT MGHImageIO : public ImageIOBase itkNewMacro(Self); /** Run-time type information (and related methods). */ - itkTypeMacro(MGHImageIO, Superclass); + itkTypeMacro(MGHImageIO, ImageIOBase); /*-------- This part of the interfaces deals with reading data. ----- */ From 3e5d7d86aed9ea6c5b981cfe3ae5d0338a173a48 Mon Sep 17 00:00:00 2001 From: Hans Johnson Date: Sat, 25 Jan 2025 09:33:30 -0600 Subject: [PATCH 58/68] COMP: Use modern macro for name of class MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When preparing for the future with ITK by setting ITK_FUTURE_LEGACY_REMOVE:BOOL=ON ITK_LEGACY_REMOVEBOOL=ON The future preferred macro should be used │ - itkTypeMacro(MGHImageIOFactory, ObjectFactoryBase); │ + itkOverrideGetNameOfClassMacro(MGHImageIOFactory); --- Modules/IO/MGHIO/include/itkMGHImageIO.h | 2 +- Modules/IO/MGHIO/include/itkMGHImageIOFactory.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Modules/IO/MGHIO/include/itkMGHImageIO.h b/Modules/IO/MGHIO/include/itkMGHImageIO.h index a850d32d1db1..a3b3497b3eac 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIO.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIO.h @@ -50,7 +50,7 @@ class MGHIO_EXPORT MGHImageIO : public ImageIOBase itkNewMacro(Self); /** Run-time type information (and related methods). */ - itkTypeMacro(MGHImageIO, ImageIOBase); + itkOverrideGetNameOfClassMacro(MGHImageIO); /*-------- This part of the interfaces deals with reading data. ----- */ diff --git a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h index 85acd89ebf5c..b9b3e28d208d 100644 --- a/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h +++ b/Modules/IO/MGHIO/include/itkMGHImageIOFactory.h @@ -52,7 +52,7 @@ class MGHIO_EXPORT MGHImageIOFactory : public ObjectFactoryBase itkFactorylessNewMacro(Self); /** Run-time type information (and related methods). */ - itkTypeMacro(MGHImageIOFactory, ObjectFactoryBase); + itkOverrideGetNameOfClassMacro(MGHImageIOFactory); /** Register one factory of this type */ static void From c37212f4d4bd2c75a67d40e201d588d0c97dc93e Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 10 Nov 2025 13:47:14 -0600 Subject: [PATCH 59/68] STYLE: Update clang-format to match ITK 2025-11-10 --- Modules/IO/MGHIO/src/itkMGHImageIO.cxx | 4 ++-- Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx index 1286daf5ea8f..0180f474f659 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIO.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIO.cxx @@ -420,7 +420,7 @@ MGHImageIO ::Read(void * pData) *(pDst + byteCount) = *(pSrc + byteCount); } } // next ui - } // next frameIndex + } // next frameIndex // clear resources delete[] pBuffer; @@ -722,7 +722,7 @@ MGHImageIO ::PermuteFrameValues(const void * buffer, char * tempmemory) { std::copy(pSrc, pSrc + valueSize, pDst + frameSize * componentIndex); } // next component index - } // next pixelIndex + } // next pixelIndex } unsigned int diff --git a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx index 5376df69420c..5d9aa3233668 100644 --- a/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx +++ b/Modules/IO/MGHIO/src/itkMGHImageIOFactory.cxx @@ -52,7 +52,7 @@ MGHImageIOFactory::GetDescription() const static bool MGHImageIOFactoryHasBeenRegistered = false; void MGHIO_EXPORT - MGHImageIOFactoryRegister__Private() +MGHImageIOFactoryRegister__Private() { if (!MGHImageIOFactoryHasBeenRegistered) { From fd120c38abdbe9e0559f5ad13f8c9f2e46027fa9 Mon Sep 17 00:00:00 2001 From: Bradley Lowekamp Date: Tue, 27 Jan 2026 00:22:18 +0000 Subject: [PATCH 60/68] ENH: Modernize CMake to use itk_module_add_library Replace add_library with itk_module_add_library macro for better integration with ITK module system. This provides automatic dependency linking, include directory setup, and consistent target naming. --- Modules/IO/MGHIO/src/CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 134e6f90e0f3..772c62647fec 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -3,6 +3,4 @@ itkMGHImageIOFactory.cxx itkMGHImageIO.cxx ) -add_library(MGHIO ${ITK_LIBRARY_BUILD_TYPE} ${MGHIO_SRC}) -target_link_libraries(MGHIO ${ITKIOImageBase_LIBRARIES} ${ITKZLIB_LIBRARIES}) -itk_module_target(MGHIO) +itk_module_add_library(MGHIO ${MGHIO_SRC}) From c6448a2de5b4e918a79565508a64b41a0c048756 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Wed, 22 Apr 2026 21:23:25 -0500 Subject: [PATCH 61/68] ENH: Convert from md5 to .cid tags. (#49) --- Modules/IO/MGHIO/test/MD5/T1.mgz.cid | 1 + Modules/IO/MGHIO/test/MD5/T1.mgz.md5 | 1 - Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.cid | 1 + Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 | 1 - Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.cid | 1 + Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 | 1 - 6 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 Modules/IO/MGHIO/test/MD5/T1.mgz.cid delete mode 100644 Modules/IO/MGHIO/test/MD5/T1.mgz.md5 create mode 100644 Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.cid delete mode 100644 Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 create mode 100644 Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.cid delete mode 100644 Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 diff --git a/Modules/IO/MGHIO/test/MD5/T1.mgz.cid b/Modules/IO/MGHIO/test/MD5/T1.mgz.cid new file mode 100644 index 000000000000..a416ac4df70b --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1.mgz.cid @@ -0,0 +1 @@ +bafkreihdhvkddcmmtfgd5wugnrssr5cvzm4ab76lqj53e6f6tybyqrs3xy diff --git a/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 b/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 deleted file mode 100644 index 322e898af15f..000000000000 --- a/Modules/IO/MGHIO/test/MD5/T1.mgz.md5 +++ /dev/null @@ -1 +0,0 @@ -0409fb9d011d00b8a0d8f18997634017 diff --git a/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.cid b/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.cid new file mode 100644 index 000000000000..a416ac4df70b --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.cid @@ -0,0 +1 @@ +bafkreihdhvkddcmmtfgd5wugnrssr5cvzm4ab76lqj53e6f6tybyqrs3xy diff --git a/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 b/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 deleted file mode 100644 index 322e898af15f..000000000000 --- a/Modules/IO/MGHIO/test/MD5/T1_longname.mgh.gz.md5 +++ /dev/null @@ -1 +0,0 @@ -0409fb9d011d00b8a0d8f18997634017 diff --git a/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.cid b/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.cid new file mode 100644 index 000000000000..f517f3270109 --- /dev/null +++ b/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.cid @@ -0,0 +1 @@ +bafkreib3qleljdy2t7czavhmkyzst5hlpobk7rt5pyix2n74hiaspyhfzi diff --git a/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 b/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 deleted file mode 100644 index dbade93fef41..000000000000 --- a/Modules/IO/MGHIO/test/MD5/T1_uncompresed.mgh.md5 +++ /dev/null @@ -1 +0,0 @@ -c9957d62f0bda84055b4f41f4eef28ef From 94b0aa967316e6899bc766b5441469e81d10222a Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 15:38:09 -0500 Subject: [PATCH 62/68] DOC: Add README.md pointing at archived upstream for MGHIO --- Modules/IO/MGHIO/README.md | 66 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 Modules/IO/MGHIO/README.md diff --git a/Modules/IO/MGHIO/README.md b/Modules/IO/MGHIO/README.md new file mode 100644 index 000000000000..23a2cf2761d2 --- /dev/null +++ b/Modules/IO/MGHIO/README.md @@ -0,0 +1,66 @@ +# MGHIO + +In-tree ITK module providing an `itk::MGHImageIO` plugin for the +`.mgh` / `.mgz` (MGH) volume format used by the FreeSurfer +neuroimaging toolchain. The factory `itk::MGHImageIOFactory` +auto-registers with `itk::ImageIOFactory` so any +`itk::ImageFileReader` / `itk::ImageFileWriter` transparently picks +up `.mgh` / `.mgz` files when the module is enabled. + +## Origin + +Ingested from the standalone remote module +[**InsightSoftwareConsortium/itkMGHImageIO**](https://github.com/InsightSoftwareConsortium/itkMGHImageIO) +on 2026-04-27, at upstream commit +[`af74507c`](https://github.com/InsightSoftwareConsortium/itkMGHImageIO/commit/af74507c1ddc82722637c37d1f5d169e3000553a). +The upstream repository will be archived read-only after this PR +merges; it remains reachable at the URL above. + +## What lives here + +Per the v3 ingestion strategy (see +`Utilities/Maintenance/RemoteModuleIngest/INGESTION_STRATEGY.md`), only +paths matching the narrow whitelist (code, headers, tests, wrapping, +module CMake) crossed the merge boundary: + +- `include/` — public C++ headers (`itkMGHImageIO.h`, `itkMGHImageIOFactory.h`). +- `src/` — non-template implementation. +- `test/` — CTest drivers and content-link stubs. +- `wrapping/` — Python wrapping descriptors. +- `CMakeLists.txt`, `itk-module.cmake` — build + module descriptors. + +Every surviving commit preserves original authorship; `git blame` +walks across the merge boundary to upstream authors going back to the +module's earliest history. + +## What was intentionally left upstream + +Everything outside the whitelist stays in the archived upstream repo. +If you need any of it, clone +. + +| Content in upstream | Why it did not ingest | +|---|---| +| `.github/`, `azure-pipelines.yml`, `Dockerfile` | Standalone-build CI scaffolding; not useful in-tree. | +| `CTestConfig.cmake`, `pyproject.toml`, `LICENSE`, `.clang-format` | Packaging / CI / style scaffolding superseded by ITK root. | +| Historical `Old/`, `paper/`, `docs/`, demo asset trees | Stripped by the whitelist to protect ITK's git pack from bloat. | + +## Long-form documentation + +- **Format reference** — see the FreeSurfer documentation: + . +- **Standalone build + history** — see the archived upstream at + . + +## Compliance level + +Compliance Level 2 (Alpha — niche execution environment dependence: +FreeSurfer-format I/O). Carried forward from the +`MODULE_COMPLIANCE_LEVEL 2` declaration in the previous +`Modules/Remote/MGHIO.remote.cmake`. + +## Content-link status + +The 3 input content-links under `test/MD5/` are already in `.cid` +(IPFS Content Identifier) form; no `.md5` → `.cid` normalization is +required for this module. From eb67aa4ac5c920da9ae1ed4d9f85b124e0cc104f Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 15:38:12 -0500 Subject: [PATCH 63/68] COMP: Remove MGHIO.remote.cmake; now in-tree --- Modules/Remote/MGHIO.remote.cmake | 50 ------------------------------- 1 file changed, 50 deletions(-) delete mode 100644 Modules/Remote/MGHIO.remote.cmake diff --git a/Modules/Remote/MGHIO.remote.cmake b/Modules/Remote/MGHIO.remote.cmake deleted file mode 100644 index 9d91c36b707f..000000000000 --- a/Modules/Remote/MGHIO.remote.cmake +++ /dev/null @@ -1,50 +0,0 @@ -#-- # Grading Level Criteria Report -#-- EVALUATION DATE: 2020-03-01 -#-- EVALUATORS: [<>,<>] -#-- -#-- ## Compliance level 5 star (AKA ITK main modules, or remote modules that could become core modules) -#-- - [ ] Widespread community dependance -#-- - [ ] Above 90% code coverage -#-- - [ ] CI dashboards and testing monitored rigorously -#-- - [ ] Key API features are exposed in wrapping interface -#-- - [ ] All requirements of Levels 4,3,2,1 -#-- -#-- ## Compliance Level 4 star (Very high-quality code, perhaps small community dependance) -#-- - [ ] Meets all ITK code style standards -#-- - [ ] No external requirements beyond those needed by ITK proper -#-- - [ ] Builds and passes tests on all supported platforms within 1 month of each core tagged release -#-- - [ ] Windows Shared Library Build with Visual Studio -#-- - [ ] Mac with clang compiller -#-- - [ ] Linux with gcc compiler -#-- - [ ] Active developer community dedicated to maintaining code-base -#-- - [ ] 75% code coverage demonstrated for testing suite -#-- - [ ] Continuous integration testing performed -#-- - [ ] All requirements of Levels 3,2,1 -#-- -#-- ## Compliance Level 3 star (Quality beta code) -#-- - [ ] API | executable interface is considered mostly stable and feature complete -#-- - [ ] 10% C0-code coverage demonstrated for testing suite -#-- - [ ] Some tests exist and pass on at least some platform -#-- - [X] All requirements of Levels 2,1 -#-- -#-- ## Compliance Level 2 star (Alpha code feature API development or niche community/execution environment dependance ) -#-- - [X] Compiles for at least 1 niche set of execution envirionments, and perhaps others -#-- (may depend on specific external tools like a java environment, or specific external libraries to work ) -#-- - [X] All requirements of Levels 1 -#-- -#-- ## Compliance Level 1 star (Pre-alpha features under development and code of unknown quality) -#-- - [X] Code complies on at least 1 platform -#-- -#-- ## Compliance Level 0 star ( Code/Feature of known poor-quality or deprecated status ) -#-- - [ ] Code reviewed and explicitly identified as not recommended for use -#-- -#-- ### Please document here any justification for the criteria above -# Code style enforced by clang-format on 2020-02-19, and clang-tidy modernizations completed - -itk_fetch_module( - MGHIO - "MGHIO ImageIO plugin for ITK" - MODULE_COMPLIANCE_LEVEL 2 - GIT_REPOSITORY https://github.com/InsightSoftwareConsortium/itkMGHImageIO.git - GIT_TAG ef3756db3016378688c81ab7144126d9a7eb0904 - ) From 15058783251e4abce16b18bb80eb3f8c6113a866 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 15:38:14 -0500 Subject: [PATCH 64/68] ENH: Enable MGHIO in CI via configure-ci --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 94c367e0ffbb..75c5d8149738 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,7 @@ cmd = '''cmake -DModule_AnisotropicDiffusionLBR:BOOL=ON -DModule_Montage:BOOL=ON -DModule_GenericLabelInterpolator:BOOL=ON + -DModule_MGHIO:BOOL=ON -DITK_COMPUTER_MEMORY_SIZE:STRING=11 -DModule_StructuralSimilarity:BOOL=ON''' description = "Configure ITK for CI (with ccache compiler launcher)" From bae17f6a6d99dc73719427d9d543a290d1bf12ef Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 15:47:05 -0500 Subject: [PATCH 65/68] COMP: Fix normalize-ingest-commits.py merge-commit handling Previously the replay used ``git rev-list base..HEAD`` (which includes merge commits) and then invoked ``git cherry-pick`` without ``-m N``. ``cherry-pick`` rejects merge commits without an explicit ``-m``, so the very first merge in the upstream history aborted the entire replay. This blocked applying the v3 ingestion strategy's per-commit pre-commit replay step to any module whose upstream has merges in its surviving history (which is most of them). Fix: * ``git rev-list --no-merges`` now drops merge commits from the replay list. Merge commits typically carry no content of their own; the non-merge commits we keep collectively reproduce the final tree, and ``git blame`` after the merge boundary still walks back to original authors because authorship is preserved on the non-merge commits. * The dropped-merge count is reported on stderr so reviewers see what was elided. * Defense-in-depth: if a merge ever reaches the cherry-pick loop anyway (e.g. someone calls the script with a custom rev range), detect it via the parent count from ``%P`` and pass ``-m 1`` so cherry-pick succeeds rather than crashing the run. Surfaced while ingesting ITKMGHIO; would similarly bite any module whose surviving history contains a merge commit. --- .../normalize-ingest-commits.py | 57 +++++++++++++------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py b/Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py index b29288440d8e..3308386a379e 100755 --- a/Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py +++ b/Utilities/Maintenance/RemoteModuleIngest/normalize-ingest-commits.py @@ -124,12 +124,28 @@ def normalize_message(subj: str, body: str) -> tuple[str, str, bool]: def replay(base: str, *, dry_run: bool, run_pre_commit: bool) -> int: - out = required(["git", "rev-list", "--reverse", f"{base}..HEAD"]) + # Skip merge commits. ``git cherry-pick`` rejects them without ``-m N``, + # and even with ``-m 1`` a merge that has been linearized by replaying + # its non-merge ancestors would re-apply that content. The non-merge + # commits we keep in this list collectively reproduce the final tree + # without the merge nodes; ``git blame`` after the merge boundary + # still walks back to original authors because authorship is preserved. + out = required(["git", "rev-list", "--reverse", "--no-merges", f"{base}..HEAD"]) commits = out.split() if not commits: print("Nothing to do — branch contains no commits beyond base.") return 0 + # For visibility: report how many merges were dropped from the replay. + all_count = len(required(["git", "rev-list", "--reverse", f"{base}..HEAD"]).split()) + merge_count = all_count - len(commits) + if merge_count: + print( + f"Skipping {merge_count} merge commit(s); " + f"their content arrives via the {len(commits)} non-merge commits.", + file=sys.stderr, + ) + print(f"Replaying {len(commits)} commits onto {base}...", file=sys.stderr) if dry_run: @@ -162,31 +178,40 @@ def replay(base: str, *, dry_run: bool, run_pre_commit: bool) -> int: for sha in commits: meta = required( - ["git", "show", "-s", "--format=%an%x00%ae%x00%aI%x00%s%x00%b", sha] + ["git", "show", "-s", "--format=%an%x00%ae%x00%aI%x00%P%x00%s%x00%b", sha] ) - an, ae, ad, subj, body = meta.split("\x00", 4) + an, ae, ad, parents, subj, body = meta.split("\x00", 5) + # Defense in depth: ``--no-merges`` should have stripped these + # already, but if a merge commit ever reaches here, treat it as + # mainline-relative so cherry-pick succeeds rather than crashing. + is_merge = len(parents.split()) > 1 # ``-X theirs`` biases toward the cherry-picked commit's content # whenever pre-commit's auto-fix on an earlier commit clashes # with the base state this commit expects. Pre-commit re-runs # below and re-normalizes the merged tree. - cp = run( - [ - "git", - "cherry-pick", - "--allow-empty", - "--no-commit", - "--strategy=recursive", - "-X", - "theirs", - sha, - ] - ) + cp_args = [ + "git", + "cherry-pick", + "--allow-empty", + "--no-commit", + "--strategy=recursive", + "-X", + "theirs", + ] + if is_merge: + cp_args += ["-m", "1"] + cp_args.append(sha) + cp = run(cp_args) if cp.returncode != 0: # Fall back to default 3-way merge — sometimes a true # content conflict needs human review. run(["git", "cherry-pick", "--abort"]) - cp2 = run(["git", "cherry-pick", "--allow-empty", "--no-commit", sha]) + cp2_args = ["git", "cherry-pick", "--allow-empty", "--no-commit"] + if is_merge: + cp2_args += ["-m", "1"] + cp2_args.append(sha) + cp2 = run(cp2_args) if cp2.returncode != 0: sys.stderr.write(f"cherry-pick failed for {sha[:10]}:\n{cp2.stderr}") run(["git", "cherry-pick", "--abort"]) From a1801306449e30087cf81bd9ccaecd4d4093a3a3 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 16:23:20 -0500 Subject: [PATCH 66/68] STYLE: Simplify Modules/IO/MGHIO/CMakeLists.txt to in-tree pattern Drop the standalone-build conditional inherited from the remote-module days; once in-tree, the only path that matters is itk_module_impl(). Also drop the redundant cmake_minimum_required (ITK's root sets it) and the project() VERSION/LANGUAGES (the ITK module system supplies both via DEPENDS). Brings the file in line with siblings such as Modules/Filtering/GenericLabelInterpolator/CMakeLists.txt (post-ingest) and the established core IO modules (e.g. Modules/IO/HDF5/CMakeLists.txt). Addresses @dzenanz review comment on PR #6137. --- Modules/IO/MGHIO/CMakeLists.txt | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/Modules/IO/MGHIO/CMakeLists.txt b/Modules/IO/MGHIO/CMakeLists.txt index f9cda3eb5254..e0254d3d4fb1 100644 --- a/Modules/IO/MGHIO/CMakeLists.txt +++ b/Modules/IO/MGHIO/CMakeLists.txt @@ -1,15 +1,3 @@ -cmake_minimum_required(VERSION 3.10.2) - -project(MGHIO - VERSION 5.1.0 #Version should track with ITK - LANGUAGES CXX C) - +project(MGHIO) 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() +itk_module_impl() From ca6487a79529d290a3aa65f534aea1076ee35e67 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 16:25:01 -0500 Subject: [PATCH 67/68] STYLE: Apply pre-commit fixes to MGHIO test CMakeLists.txt * end-of-file-fixer stripped a trailing blank line * gersemi reformatted the file to match ITK's house CMake style (block-arg layout, lowercase CMake command names) Both hooks fired on the inherited upstream test driver. --- Modules/IO/MGHIO/test/CMakeLists.txt | 89 ++++++++++++++++++---------- 1 file changed, 58 insertions(+), 31 deletions(-) diff --git a/Modules/IO/MGHIO/test/CMakeLists.txt b/Modules/IO/MGHIO/test/CMakeLists.txt index a8794a1aca4f..bd38ae8a6623 100644 --- a/Modules/IO/MGHIO/test/CMakeLists.txt +++ b/Modules/IO/MGHIO/test/CMakeLists.txt @@ -1,40 +1,67 @@ itk_module_test() -set(MGHIOTests - itkMGHImageIOTest.cxx -) +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 ) +createtestdriver(MGHIO "${MGHIO-Test_LIBRARIES}" "${MGHIOTests}") -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 MGHFactoryCreationTest + COMMAND + MGHIOTestDriver + itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} + FactoryCreationTest +) -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_mgz + COMMAND + MGHIOTestDriver + itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} + ReadImagesTest + DATA{${MGH_DATA_ROOT}/T1.mgz} + TEST.mgz +) -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 MGHReadImagesTest_mgh + COMMAND + MGHIOTestDriver + itkMGHImageIOTest + ${ITK_TEST_OUTPUT_DIR} + ReadImagesTest + DATA{${MGH_DATA_ROOT}/T1_uncompresed.mgh} + TEST.mgh +) -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 - ) +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 +) From 0b375376cf799e57dc37d56751904591dfc47db7 Mon Sep 17 00:00:00 2001 From: "Hans J. Johnson" Date: Mon, 27 Apr 2026 17:27:12 -0500 Subject: [PATCH 68/68] STYLE: Apply gersemi to remaining MGHIO CMake files gersemi reformatted Modules/IO/MGHIO/itk-module.cmake and Modules/IO/MGHIO/src/CMakeLists.txt to match ITK's house CMake style; the prior pass at this had only covered the test/ tree. --- Modules/IO/MGHIO/itk-module.cmake | 13 ++++++++----- Modules/IO/MGHIO/src/CMakeLists.txt | 7 ++++--- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Modules/IO/MGHIO/itk-module.cmake b/Modules/IO/MGHIO/itk-module.cmake index 91be1e648826..7e148c79b7c7 100644 --- a/Modules/IO/MGHIO/itk-module.cmake +++ b/Modules/IO/MGHIO/itk-module.cmake @@ -1,7 +1,11 @@ -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.") +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 +itk_module( + MGHIO ENABLE_SHARED DEPENDS ITKIOImageBase @@ -12,6 +16,5 @@ itk_module(MGHIO EXCLUDE_FROM_DEFAULT FACTORY_NAMES ImageIO::MGH - DESCRIPTION - "${DOCUMENTATION}" + DESCRIPTION "${DOCUMENTATION}" ) diff --git a/Modules/IO/MGHIO/src/CMakeLists.txt b/Modules/IO/MGHIO/src/CMakeLists.txt index 772c62647fec..932468486b05 100644 --- a/Modules/IO/MGHIO/src/CMakeLists.txt +++ b/Modules/IO/MGHIO/src/CMakeLists.txt @@ -1,6 +1,7 @@ -set(MGHIO_SRC -itkMGHImageIOFactory.cxx -itkMGHImageIO.cxx +set( + MGHIO_SRC + itkMGHImageIOFactory.cxx + itkMGHImageIO.cxx ) itk_module_add_library(MGHIO ${MGHIO_SRC})