/*========================================================================= Program: Tensor ToolKit - TTK Module: $URL$ Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) INRIA 2010. All rights reserved. See LICENSE.txt for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "itkImageConverterCommand.h" #include #include #include #include #include #include #include #include "ttkConfigure.h" #ifdef TTK_USE_MIPS #include "mipsInrimageImageIOFactory.h" #endif #ifdef TTK_USE_VTKINRIA3D #include "itkGISImageIOFactory.h" #endif #ifdef Module_ITKIOPhilipsREC #include #include #include #endif // macro for templated ITK read and write #define ReadWriteImageMacro(dimension, type) \ using CorrectImageType = itk::Image ; \ itk::ImageFileReader< CorrectImageType >::Pointer Reader = itk::ImageFileReader< itk::Image >::New(); \ Reader->SetFileName ( filename1 ); \ try \ { \ Reader->Update(); \ } \ catch (itk::ExceptionObject &e) { \ std::cerr << e; \ return EXIT_FAILURE; \ } \ if (isparrec) \ { \ using CorrectDirectionType = CorrectImageType::DirectionType ; \ using CorrectPointType = CorrectImageType::PointType ; \ CorrectDirectionType direction; \ direction.SetIdentity(); \ for (unsigned int i=0; i<3; i++) \ for (unsigned int j=0; j<3; j++) \ direction[i][j] = correctdirection[i][j]; \ CorrectPointType origin; \ origin.Fill(0.0); \ for (unsigned int i=0; i<3; i++) \ origin[i] = correctorigin[i]; \ Reader->GetOutput()->SetDirection (direction); \ Reader->GetOutput()->SetOrigin (origin); \ } \ itk::ImageFileWriter< itk::Image >::Pointer Writer = itk::ImageFileWriter< itk::Image >::New(); \ Writer->SetFileName ( filename2 ); \ Writer->SetInput(Reader->GetOutput()); \ try \ { \ Writer->Update(); \ } \ catch (itk::ExceptionObject &e) { \ std::cerr << e; \ return EXIT_FAILURE; \ } \ namespace itk { ImageConverterCommand::ImageConverterCommand() { m_ShortDescription = "Convert an image file into another format"; m_LongDescription = "Usage:\n"; m_LongDescription += " \n\n"; m_LongDescription += m_ShortDescription; } ImageConverterCommand::~ImageConverterCommand() = default; int ImageConverterCommand::Execute(int narg, const char* arg[]) { if(narg!=3) { std::cout << this->GetLongDescription() << std::endl; return EXIT_FAILURE; } const char* filename1 = arg[1]; const char* filename2 = arg[2]; itk::NiftiImageIOFactory::RegisterOneFactory(); #ifdef TTK_USE_MIPS itk::InrimageImageIOFactory::RegisterOneFactory(); #endif #ifdef Module_ITKIOPhilipsREC itk::PhilipsRECImageIOFactory::RegisterOneFactory(); #endif #ifdef TTK_USE_VTKINRIA3D itk::GISImageIOFactory::RegisterOneFactory(); #endif // dummy reading information to get type and dimension using ImageType = FloatImageType; using ReaderType = itk::ImageFileReader; ReaderType::Pointer informationreader = ReaderType::New(); informationreader->SetFileName(filename1); try { informationreader->Update(); } catch(itk::ExceptionObject &e) { std::cerr << e; return EXIT_FAILURE; } std::cerr << "Dimension: " << informationreader->GetImageIO()->GetNumberOfDimensions() << std::endl; std::cerr << "Component Type: " << informationreader->GetImageIO()->GetComponentTypeAsString(informationreader->GetImageIO()->GetComponentType()) << std::endl; std::cerr << "Pixel Type: " << informationreader->GetImageIO()->GetPixelTypeAsString(informationreader->GetImageIO()->GetPixelType()) << std::endl; if(informationreader->GetImageIO()->GetPixelType() != IOPixelEnum::SCALAR) { std::cerr << "Only scalar images can be converted" << std::endl; return EXIT_FAILURE; } // real reading with dimension and type unsigned int dim = informationreader->GetImageIO()->GetNumberOfDimensions(); CommonEnums::IOComponent componenttype = informationreader->GetImageIO()->GetComponentType(); bool isparrec = !strcmp (informationreader->GetImageIO()->GetNameOfClass(), "PhilipsRECImageIO"); FloatImageType::DirectionType correctdirection; FloatImageType::PointType correctorigin; correctorigin.Fill(0.0); if (isparrec) { correctdirection = this->ExtractPARRECImageOrientation(filename1); correctorigin = this->ExtractPARRECImageOrigin (filename1, correctdirection); } if (dim > 6) { std::cerr << "Dimension Too High." << dim<< std::endl; return -1; } switch (componenttype) { case IOComponentEnum::UCHAR: if (dim == 2) { ReadWriteImageMacro (2, unsigned char); } else if (dim == 3) { ReadWriteImageMacro (3, unsigned char); } else if (dim == 4) { ReadWriteImageMacro (4, unsigned char); } else if (dim == 5) { ReadWriteImageMacro (5, unsigned char); } else if (dim == 6) { ReadWriteImageMacro (6, unsigned char); } break; case IOComponentEnum::CHAR: if (dim == 2) { ReadWriteImageMacro (2, char); } else if (dim == 3) { ReadWriteImageMacro (3, char); } else if (dim == 4) { ReadWriteImageMacro (4, char); } else if (dim == 5) { ReadWriteImageMacro (5, char); } else if (dim == 6) { ReadWriteImageMacro (6, char); } break; case IOComponentEnum::USHORT: if (dim == 2) { ReadWriteImageMacro (2, unsigned short); } else if (dim == 3) { ReadWriteImageMacro (3, unsigned short); } else if (dim == 4) { ReadWriteImageMacro (4, unsigned short); } else if (dim == 5) { ReadWriteImageMacro (5, unsigned short); } else if (dim == 6) { ReadWriteImageMacro (6, unsigned short); } break; case IOComponentEnum::SHORT: if (dim == 2) { ReadWriteImageMacro (2, short); } else if (dim == 3) { ReadWriteImageMacro (3, short); } else if (dim == 4) { ReadWriteImageMacro (4, short); } else if (dim == 5) { ReadWriteImageMacro (5, short); } else if (dim == 6) { ReadWriteImageMacro (6, short); } break; case IOComponentEnum::UINT: if (dim == 2) { ReadWriteImageMacro (2, unsigned int); } else if (dim == 3) { ReadWriteImageMacro (3, unsigned int); } else if (dim == 4) { ReadWriteImageMacro (4, unsigned int); } else if (dim == 5) { ReadWriteImageMacro (5, unsigned int); } else if (dim == 6) { ReadWriteImageMacro (6, unsigned int); } break; case IOComponentEnum::INT: if (dim == 2) { ReadWriteImageMacro (2, int); } else if (dim == 3) { ReadWriteImageMacro (3, int); } else if (dim == 4) { ReadWriteImageMacro (4, int); } else if (dim == 5) { ReadWriteImageMacro (5, int); } else if (dim == 6) { ReadWriteImageMacro (6, int); } break; case IOComponentEnum::ULONG: if (dim == 2) { ReadWriteImageMacro (2, unsigned long); } else if (dim == 3) { ReadWriteImageMacro (3, unsigned long); } else if (dim == 4) { ReadWriteImageMacro (4, unsigned long); } else if (dim == 5) { ReadWriteImageMacro (5, unsigned long); } else if (dim == 6) { ReadWriteImageMacro (6, unsigned long); } break; case IOComponentEnum::LONG: if (dim == 2) { ReadWriteImageMacro (2, long); } else if (dim == 3) { ReadWriteImageMacro (3, long); } else if (dim == 4) { ReadWriteImageMacro (4, long); } else if (dim == 5) { ReadWriteImageMacro (5, long); } else if (dim == 6) { ReadWriteImageMacro (6, long); } break; case IOComponentEnum::FLOAT: if (dim == 2) { ReadWriteImageMacro (2, float); } else if (dim == 3) { ReadWriteImageMacro (3, float); } else if (dim == 4) { ReadWriteImageMacro (4, float); } else if (dim == 5) { ReadWriteImageMacro (5, float); } else if (dim == 6) { ReadWriteImageMacro (6, float); } break; case IOComponentEnum::DOUBLE: if (dim == 2) { ReadWriteImageMacro (2, double); } else if (dim == 3) { ReadWriteImageMacro (3, double); } else if (dim == 4) { ReadWriteImageMacro (4, double); } else if (dim == 5) { ReadWriteImageMacro (5, double); } else if (dim == 6) { ReadWriteImageMacro (6, double); } break; default: std::cerr << "Unrecognized Component Type : " << informationreader->GetImageIO()->GetComponentTypeAsString(componenttype) << std::endl; return -1; break; } if (isparrec) { std::ostringstream gradientfilename; gradientfilename << itksys::SystemTools::GetFilenameWithoutExtension (filename2) <<".grad"; GradientWriterType::Pointer gradientwriter = GradientWriterType::New(); gradientwriter->SetGradientList (this->ExtractPARRECGradientDirections (filename1, correctdirection)); gradientwriter->SetFileName (gradientfilename.str().c_str()); try { gradientwriter->Update(); } catch(itk::ExceptionObject &e) { std::cerr << e; return EXIT_FAILURE; } } return EXIT_SUCCESS; } ImageConverterCommand::FloatImageType::PointType ImageConverterCommand::ExtractPARRECImageOrigin (const char* filename, FloatImageType::DirectionType direction) { using PointType = FloatImageType::PointType; PointType nullptrorigin; nullptrorigin[0] = nullptrorigin[1] = nullptrorigin[2] = 0.0; #ifndef Module_ITKIOPhilipsREC std::cerr<<"cannot correct for PAR-REC angulation without Module_ITKIOPhilipsREC to ON"<SetFileName(filename); try { philipsIO->ReadImageInformation(); } catch(itk::ExceptionObject &e) { std::cerr << e; } itk::MetaDataDictionary PARheader = philipsIO->GetMetaDataDictionary(); using OffCentreType = itk::PhilipsRECImageIO::OffCentreMidSliceType ; OffCentreType offcenter; bool valid = itk::ExposeMetaData(PARheader, "PAR_OffCentreMidSlice", offcenter); if (!valid) { std::cerr<<"cannot find off-center information in PAR header, no correction"<GetDimensions (0); dimensions[1] = philipsIO->GetDimensions (1); dimensions[2] = philipsIO->GetDimensions (2); FloatImageType::SpacingType midoffset; midoffset[0] = philipsIO->GetSpacing (0) * (dimensions[0] - 1) / 2.0; midoffset[1] = philipsIO->GetSpacing (1) * (dimensions[1] - 1) / 2.0; midoffset[2] = philipsIO->GetSpacing (2) * (dimensions[2] - 1) / 2.0; midoffset = direction * midoffset; PointType offcenterpoint; offcenterpoint[0] = offcenter[0]; offcenterpoint[1] = offcenter[1]; offcenterpoint[2] = offcenter[2]; FloatImageType::DirectionType AFRtoLPS; AFRtoLPS.Fill (0); AFRtoLPS[0][2] = 1; AFRtoLPS[1][0] = 1; AFRtoLPS[2][1] = 1; offcenterpoint = AFRtoLPS * offcenterpoint; offcenterpoint -= midoffset; return offcenterpoint; #endif } ImageConverterCommand::FloatImageType::DirectionType ImageConverterCommand::ExtractPARRECImageOrientation (const char* filename) { using DirectionType = FloatImageType::DirectionType ; DirectionType eyedir; eyedir.SetIdentity(); #ifndef Module_ITKIOPhilipsREC std::cerr<<"cannot correct for PAR-REC angulation without Module_ITKIOPhilipsREC to ON"<SetFileName(filename); try { philipsIO->ReadImageInformation(); } catch(itk::ExceptionObject &e) { std::cerr << e; } itk::MetaDataDictionary PARheader = philipsIO->GetMetaDataDictionary(); using AngulationType = itk::PhilipsRECImageIO::AngulationMidSliceType ; AngulationType angulation; int sliceorientation = 0; bool valid = itk::ExposeMetaData(PARheader, "PAR_AngulationMidSlice", angulation); if (!valid) { std::cerr<<"cannot find angulation in PAR header, no correction"<(PARheader, "PAR_SliceOrientation", sliceorientation); if (!valid) { std::cerr<<"cannot find slice orientation in PAR header, no correction"<SetFileName(filename); try { philipsIO->ReadImageInformation(); } catch(itk::ExceptionObject &e) { std::cerr << e; } itk::MetaDataDictionary PARheader = philipsIO->GetMetaDataDictionary(); using GradientDirectionType = itk::PhilipsRECImageIO::GradientDirectionType ; using GradientDirectionContainerType = itk::PhilipsRECImageIO::GradientDirectionContainerType ; GradientDirectionContainerType::Pointer parrecgradients = GradientDirectionContainerType::New(); bool valid = itk::ExposeMetaData(PARheader, "PAR_GradientDirectionValues", parrecgradients); if (!valid) { std::cerr<<"cannot find gradient information in PAR header..."<Size(); i++) { GradientDirectionType parrecgradient = parrecgradients->ElementAt (i); VectorType gradient; for (unsigned int j=0; j<3; j++) gradient[j] = parrecgradient[j]; gradient = inverse * AFRtoLPS * gradient; gradients.push_back (gradient); } return gradients; #endif } }