/*========================================================================= Program: vtkINRIA3D Module: $Id: ImageRegistrationFactory.cxx 1 2008-01-22 19:01:33Z ntoussaint $ Language: C++ Author: $Author: ntoussaint $ Date: $Date: 2008-01-22 20:01:33 +0100 (Tue, 22 Jan 2008) $ Version: $Revision: 1 $ Copyright (c) 2007 INRIA - Asclepios Project. All rights reserved. See Copyright.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. =========================================================================*/ /** * This is a small tool that shows how to use the Registration Factory * Mostly inspired by Tom Vercauteren DemonsRegistration test code. * * The user can choose between different registration methods. * The user can also choose input transform file or input displacement field; * * * \author Nicolas Toussaint, INRIA */ #include // For ITK 3.20 that does not define correctly ptrdiff_t #include "itkCommand.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkTransformFileReader.h" #include "itkTransformFileWriter.h" #include #include "itkTranslationTransform.h" #include "itkTransformFactory.h" #include #include #include #include #include #ifndef WIN32 #include #else #include "getoptcompat/getopt.h" #endif //WIN32 #include struct arguments { std::string fixedImageFile; /* -f option */ std::string movingImageFile; /* -m option */ std::string inputFieldFile; /* -b option */ std::string inputTransformFile; /* -p option */ std::string outputImageFile; /* -o option */ std::string outputTransformFile; /* -O option */ std::string outputFieldFile; /* -O option */ unsigned int registrationType; /* -r option */ unsigned int verbosity; /* -v option */ arguments () : fixedImageFile(""), movingImageFile(""), inputFieldFile(""), inputTransformFile(""), outputImageFile("output.mha"), outputTransformFile("output.mat"), registrationType(0), verbosity(0u) { } friend std::ostream& operator<< (std::ostream& o, const arguments& args) { std::ostringstream osstr; std::string iterstr = "[ " + osstr.str() + "]"; return o <<"Arguments structure:"<."< parseUIntVector( const std::string & str) { std::vector vect; std::string::size_type crosspos = str.find('x',0); if (crosspos == std::string::npos) { // only one uint vect.push_back( static_cast( atoi(str.c_str()) )); return vect; } // first uint vect.push_back( static_cast( atoi( (str.substr(0,crosspos)).c_str() ) )); while(true) { std::string::size_type crossposfrom = crosspos; crosspos = str.find('x',crossposfrom+1); if (crosspos == std::string::npos) { vect.push_back( static_cast( atoi( (str.substr(crossposfrom+1,str.length()-crossposfrom-1)).c_str() ) )); return vect; } vect.push_back( static_cast( atoi( (str.substr(crossposfrom+1,crosspos)).c_str() ) )); } } void parseOpts (int argc, char **argv, struct arguments & args) { const std::string progname( "ImageRegistrationFactory" ); // Default values. args = arguments(); if (argc == 1) { display_usage(progname); } int opt = 0; /* it's actually going to hold a char */ int longIndex = 0; while ( (opt = getopt_long(argc, argv, optString, longOpts, &longIndex)) != -1 ) { switch( opt ) { case 'f': if (! optarg) display_usage(progname); args.fixedImageFile = optarg; break; case 'm': if (! optarg) display_usage(progname); args.movingImageFile = optarg; break; case 'b': if (! optarg) display_usage(progname); else args.inputFieldFile = optarg; break; case 'p': if (! optarg) display_usage(progname); else args.inputTransformFile = optarg; break; case 'o': if (! optarg) display_usage(progname); args.outputImageFile = optarg; break; case 'O': if (! optarg) args.outputFieldFile = "CHANGETHISSTRING"; else args.outputFieldFile = optarg; break; case 't': if (! optarg) display_usage(progname); else args.outputTransformFile = optarg; break; case 'r': if (! optarg) display_usage(progname); else args.registrationType = static_cast( atoi(optarg) ); break; case 'v': if (! optarg) args.verbosity++; else args.verbosity = static_cast( atoi(optarg) ); break; case 'h': /* fall-through is intentional */ case '?': /* fall-through is intentional */ default: display_usage(progname); break; } } if ( args.outputFieldFile=="CHANGETHISSTRING" ) { unsigned int pos = args.outputImageFile.find("."); if ( pos < args.outputFieldFile.size() ) { args.outputFieldFile = args.outputImageFile; args.outputFieldFile.replace(pos, args.outputFieldFile.size(), "-field.mha"); } else { args.outputFieldFile = args.outputImageFile + "-field.mha"; } } if ( !args.inputFieldFile.empty() && !args.inputTransformFile.empty() ) { std::cout<<"You cannot impose both an initial deformation field and an initial spatial transformation."< class CommandIterationUpdate : public itk::Command { public: typedef CommandIterationUpdate Self; typedef itk::Command Superclass; typedef itk::SmartPointer Pointer; itkNewMacro( Self ); private: std::ofstream m_Fid; bool m_headerwritten; public: void Execute(itk::Object *caller, const itk::EventObject & event) { Execute( (const itk::Object *)caller, event); } void Execute(const itk::Object * object, const itk::EventObject & event) { if( !(itk::IterationEvent().CheckEvent( &event )) ) { return; } unsigned int iter = -1; // if ( const DiffeomorphicDemonsRegistrationFilterType * filter = dynamic_cast< const DiffeomorphicDemonsRegistrationFilterType * >( object ) ) if ( 1) { } else { return; } std::cout<m_Fid.is_open()) { if (! m_headerwritten) { this->m_Fid<<"Iteration" <<", MSE before" <<", Harmonic energy" <<", min|Jac|" <<", 0.2% |Jac|" <<", 01% |Jac|" <<", 99% |Jac|" <<", 99.8% |Jac|" <<", max|Jac|" <<", ratio(|Jac|<=0)"; this->m_Fid<m_Fid<m_Fid<m_Fid.close(); } }; template void ImageRegistrationFactoryFunction( arguments args ) { // Declare the types of the images (float or double only) typedef TPixel PixelType; typedef itk::Image< PixelType, Dimension > ImageType; typedef itk::Vector< PixelType, Dimension > VectorPixelType; typedef typename itk::Image < VectorPixelType, Dimension > DisplacementFieldType; typedef itk::ImageRegistrationFactory ImageRegistrationFactoryType; // Set up the file readers typedef itk::ImageFileReader< ImageType > FixedImageReaderType; typedef itk::ImageFileReader< ImageType > MovingImageReaderType; typedef itk::ImageFileReader< DisplacementFieldType > FieldReaderType; typedef itk::TransformFileReader TransformReaderType; typedef typename ImageRegistrationFactoryType::TransformType InputTransformType; // registration methods to be added to the factory. typedef typename itk::RegistrationMethod MethodType; typedef typename itk::AffineRegistrationMethod AffineMethodType; typedef typename itk::RigidRegistrationMethod RigidMethodType; // typedef typename itk::DiffeomorphicDemonsRegistrationMethod DiffeomorphicDemonsMethodType; // Images we use typename ImageType::Pointer fixedImage = ITK_NULLPTR; typename ImageType::Pointer movingImage = ITK_NULLPTR; typename DisplacementFieldType::Pointer inputDefField = ITK_NULLPTR; typename InputTransformType::Pointer inputTransform = ITK_NULLPTR; typename FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); typename MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); fixedImageReader->SetFileName( args.fixedImageFile.c_str() ); movingImageReader->SetFileName( args.movingImageFile.c_str() ); // Update the reader try { fixedImageReader->Update(); movingImageReader->Update(); } catch( itk::ExceptionObject& err ) { std::cout << "Could not read one of the input images." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } fixedImage = fixedImageReader->GetOutput(); movingImage = movingImageReader->GetOutput(); if ( ! args.inputFieldFile.empty() ) { // Set up the file readers typename FieldReaderType::Pointer fieldReader = FieldReaderType::New(); fieldReader->SetFileName( args.inputFieldFile.c_str() ); // Update the reader try { fieldReader->Update(); } catch( itk::ExceptionObject& err ) { std::cout << "Could not read the input field." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } inputDefField = fieldReader->GetOutput(); inputDefField->DisconnectPipeline(); } else if ( ! args.inputTransformFile.empty() ) { std::cout<<"entering the transform file"<::RegisterTransform(); typedef typename ImageRegistrationFactoryType::LinearTransformType LinearTransformType; itk::TransformFactory::RegisterTransform (); typename TransformReaderType::Pointer transformReader = TransformReaderType::New(); transformReader->SetFileName( args.inputTransformFile.c_str() ); // Update the reader try { transformReader->Update(); } catch( itk::ExceptionObject& err ) { std::cout << "Could not read the input transform." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } typedef typename TransformReaderType::TransformType BaseTransformType; BaseTransformType* baseTrsf(0); const typename TransformReaderType::TransformListType* trsflistptr = transformReader->GetTransformList(); if ( trsflistptr->empty() ) { std::cout << "Could not read the input transform." << std::endl; exit( EXIT_FAILURE ); } else if (trsflistptr->size()>1 ) { std::cout << "The input transform file contains more than one transform, we use the first one." << std::endl; exit( EXIT_FAILURE ); } baseTrsf = trsflistptr->front(); if ( !baseTrsf ) { std::cout << "Could not read the input transform." << std::endl; exit( EXIT_FAILURE ); } // Set up the TransformToDisplacementFieldFilter typedef itk::TransformToDisplacementFieldFilter FieldGeneratorType; typedef typename FieldGeneratorType::TransformType TransformType; inputTransform = dynamic_cast(baseTrsf); if ( !inputTransform ) { std::cout << "Could not cast input transform to a usable transform for the factory." << std::endl; exit( EXIT_FAILURE ); } TransformType* trsf = dynamic_cast(baseTrsf); if ( !trsf ) { std::cout << "Could not cast input transform to a usable transform." << std::endl; exit( EXIT_FAILURE ); } typename FieldGeneratorType::Pointer fieldGenerator = FieldGeneratorType::New(); fieldGenerator->SetTransform( trsf ); fieldGenerator->SetOutputStartIndex(fixedImageReader->GetOutput()->GetRequestedRegion().GetIndex()); fieldGenerator->SetSize(fixedImageReader->GetOutput()->GetRequestedRegion().GetSize()); fieldGenerator->SetOutputSpacing(fixedImageReader->GetOutput()->GetSpacing()); fieldGenerator->SetOutputDirection(fixedImageReader->GetOutput()->GetDirection()); fieldGenerator->SetOutputOrigin(fixedImageReader->GetOutput()->GetOrigin()); // Update the fieldGenerator try { fieldGenerator->Update(); } catch( itk::ExceptionObject& err ) { std::cout << "Could not generate the input field." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } inputDefField = fieldGenerator->GetOutput(); inputDefField->DisconnectPipeline(); } typename ImageRegistrationFactoryType::Pointer factory = itk::ImageRegistrationFactory::New(); factory->UseFixedImageOff(); factory->UseInnerTransformationOff (); typename MethodType::Pointer method = ITK_NULLPTR; switch( args.registrationType ) { default: case 0: method = AffineMethodType::New(); break; case 1: method = RigidMethodType::New(); break; } factory->AddRegistrationMethod (0, method.GetPointer()); factory->SetFixedImage (fixedImage); factory->SetMovingImage (movingImage); std::cout << factory->CheckImagesConsistency(fixedImage, movingImage) << std::endl; if (!inputTransform.IsNull()) { factory->SetInitialTransform (inputTransform.GetPointer()); } // Update the factory try { factory->Initialize(); if (!factory->CheckImagesConsistency (fixedImage, movingImage)) { factory->SkipResamplingOff(); factory->UpdateLargestPossibleRegion(); } factory->ApplyRegistrationMethod (0); factory->Update(); factory->WriteOutput(args.outputImageFile.c_str()); if ( ! args.outputTransformFile.empty() ) { factory->WriteGlobalLinearTransform (args.outputTransformFile.c_str()); } } catch( itk::ExceptionObject& err ) { std::cout << "Could not register images !." << std::endl; std::cout << err << std::endl; exit( EXIT_FAILURE ); } factory->RemoveRegistrationMethod(0); }; int main( int argc, char *argv[] ) { struct arguments args; parseOpts (argc, argv, args); itk::MultiThreaderBase::SetGlobalDefaultNumberOfThreads(2); std::cout<<"Starting registration with the following arguments:"<SetFileName(args.fixedImageFile.c_str()); imageIO->ReadImageInformation(); } catch(itk::ExceptionObject &e) { std::cerr << e; exit( EXIT_FAILURE ); } switch ( imageIO->GetNumberOfDimensions() ) { case 3: ImageRegistrationFactoryFunction(args); break; default: std::cerr << "Unsupported dimension" << std::endl; exit( EXIT_FAILURE ); } return EXIT_SUCCESS; }