CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iDeformationElastic.cc
Go to the documentation of this file.
00001 
00008 #include "iDeformationElastic.hh"
00009 
00010 /*
00011   \fn public iDeformationElastic::iDeformationElastic()
00012   \brief Constructor of iDeformationElastic. Simply set all data members to default values.
00013 */
00014 iDeformationElastic::iDeformationElastic() : vDeformation()
00015 {
00016   m_pathToFwdDeformationFiles.clear();
00017   m_pathToBwdDeformationFiles.clear();
00018 
00019   //file_parser = ParserType::New();
00020   #ifdef CASTOR_ELASTIX
00021   ITK_inputImage  = ImageType::New();
00022   ITK_outputImage = ImageType::New();
00023   #endif
00024 }
00025 
00026 
00027 
00028 /*
00029   \fn public iDeformationElastic::iDeformationElastic()
00030   \brief Destructor of iDeformationElastic. Free memory from all allocated tabs.
00031 */
00032 iDeformationElastic::~iDeformationElastic() 
00033 {
00034   if( m_initialized)
00035   {
00036     m_pathToFwdDeformationFiles.clear();
00037     m_pathToBwdDeformationFiles.clear();
00038   }
00039 }
00040 
00041 
00042 
00043 /*
00044   \fn public void ShowHelp()
00045   \brief This function is an implementation of the pure virtual mother function. It is used to
00046          print out specific help about the deformation model and its options.
00047 */
00048 void iDeformationElastic::ShowHelp()
00049 {
00050   cout << "-- Motion correction based on non-rigid deformations calculated using the Elastix software (v.4.8) --" << endl;
00051   cout << "For the current implementation, a text file containing the filename of the Elastix deformations is required:" << endl; 
00052   cout << "The 1st line indicates the path to the forward transformation parameters, while the second line indicates the path to backward transformation parameters." << endl;
00053   cout << "The path should contain '%d' instead of the number of gates in order to adequately load the parameter files. Numbering should start from 1 (not 0)" << endl;
00054   cout << "(ex 'pathTo/parameterFiles_fileNumber.xxx' becomes 'pathTo/parameterFiles_%d.xxx' )" << endl;
00055 }
00056 
00057 
00058 /*
00059   \fn public virtual int ReadAndCheckConfigurationFile()
00060   \param const string& a_configurationFile
00061   \brief This function is an implementation of the pure virtual mother function. It is used to read options from a configuration file.
00062   \return 0 if success, other value otherwise.
00063 */
00064 int iDeformationElastic::ReadAndCheckConfigurationFile(const string& a_fileOptions)
00065 {
00066   // Implement here the reading of any options specific to this deformation model (i.e : parameters or path to deformation files), through a configuration file
00067   // The ReadDataASCIIFile() functions could be helpful to recover data from a file
00068   
00069   ifstream in_file(a_fileOptions.c_str(), ios::in);
00070   
00071   if(!in_file)
00072   {
00073     Cerr("***** iDeformationElastic::ReadAndCheckConfigurationFile -> Error while trying to read configuration file : " << a_fileOptions << endl);
00074     return 1;
00075   }
00076   
00077   string line;
00078   char* str_tmp;
00079   
00080   // Get forward files basename
00081   getline(in_file, line);
00082   str_tmp = new char[line.size()];
00083 
00084   for(int t=0 ; t<m_nbTransformations ; t++)
00085   {
00086     //TODO : error handling (incorrect string)
00087     sprintf(str_tmp, line.c_str(), t+1);
00088     m_pathToFwdDeformationFiles.push_back(str_tmp);
00089   }
00090 
00091   // Get backward files basename
00092   getline(in_file, line);
00093   
00094   delete str_tmp;
00095   str_tmp = new char[line.size()];
00096 
00097   for(int t=0 ; t<m_nbTransformations ; t++)
00098   {
00099     //TODO : error handling (incorrect string)
00100     sprintf(str_tmp, line.c_str(), t+1);
00101     //sprintf(str_tmp, line.c_str(), 1);
00102     m_pathToBwdDeformationFiles.push_back(str_tmp);
00103   }
00104   
00105   delete str_tmp;
00106   in_file.close();
00107   
00108   // Check if files exist
00109   for(int t=0 ; t<m_nbTransformations ; t++)
00110   {
00111     ifstream in_file_fwd(m_pathToFwdDeformationFiles.at(t).c_str(), ios::in);
00112     ifstream in_file_bwd(m_pathToFwdDeformationFiles.at(t).c_str(), ios::in);
00113     if(!in_file_fwd)
00114     {
00115       Cerr("***** iDeformationElastic::ReadAndCheckConfigurationFile -> Error while trying to read forward deformation vectors file number" << t <<  ": " 
00116            << m_pathToFwdDeformationFiles.at(t) << endl);
00117       return 1;
00118     }
00119     if(!in_file_bwd)
00120     {
00121       Cerr("***** iDeformationElastic::ReadAndCheckConfigurationFile -> Error while trying to read backward deformation vectors file number" << t <<  ": " 
00122            << m_pathToBwdDeformationFiles.at(t) << endl);
00123       return 1;
00124     }
00125     in_file_fwd.close();
00126     in_file_bwd.close();
00127   }
00128 
00129   return 0;
00130 }
00131 
00132 
00133 /*
00134   \fn public virtual int ReadAndCheckOptionsList()
00135   \param const string& a_optionsList
00136   \brief This function is an implementation of the pure virtual mother function. It is used to read options from a list of options.
00137   \return 0 if success, other value otherwise.
00138 */
00139 int iDeformationElastic::ReadAndCheckOptionsList(const string& a_listOptions)
00140 {
00141   // Implement here the reading of any options specific to this deformation model, through a list of options separated by commas
00142   // The ReadStringOption() function could be helpful to parse the list of parameters in an array
00143   
00144   // Normal end
00145   return 0;
00146 }
00147 
00148 
00149 
00150 /*
00151   \fn CheckSpecificParameters
00152   \brief This function is an implementation of the pure virtual mother function. It is used to
00153          check parameters of the child deformation model before initialization.
00154   \return 0 if success, other value otherwise.
00155 */
00156 int iDeformationElastic::CheckSpecificParameters()
00157 {
00158   // Implement here checks over parameters which should be read using either ReadAndCheckConfigurationFile() and ReadAndCheckOptionsList() functions
00159   
00160   
00161   // All the variables checked here are member variables of the mother deformation class 
00162   
00163   // Check image dimensions
00164   if (mp_ID==NULL)
00165   {
00166     Cerr("***** iDeformationElastic::CheckParameters() -> No image dimensions provided !" << endl);
00167     return 1;
00168   }
00169   
00170   // Check resp gates
00171   if (m_nbTransformations<0)
00172   {
00173     Cerr("***** iDeformationElastic::CheckParameters() -> Wrong number of gates !" << endl);
00174     return 1;
00175   }
00176   
00177   // Check verbosity
00178   if (m_verbose<0)
00179   {
00180     Cerr("***** iDeformationElastic::CheckParameters() -> Wrong verbosity level provided !" << endl);
00181     return 1;
00182   }
00183 
00184   // Check vector files
00185   if (m_pathToFwdDeformationFiles.empty() || m_pathToBwdDeformationFiles.empty())
00186   {
00187     Cerr("***** iDeformationElastic::CheckParameters() -> Vector files not initialized !" << endl);
00188     return 1;
00189   }
00190   
00191   // Normal end
00192   m_checked = true;
00193   return 0;
00194 }
00195 
00196 
00197 /*
00198   \fn public int Initialize()
00199   \brief This function is an implementation of the pure virtual mother function. It is used to
00200          initialize specific stuff to the child deformation model.
00201   \return 0 if success, other value otherwise.
00202 */
00203 int iDeformationElastic::Initialize()
00204 {
00205   // Implement here the allocation/initialization of whatever member variables specifically used by this deformation model
00206   
00207   
00208   // Check here if Castor has been compiled with CASTOR_ELASTIX option. Throw error otherwise.
00209   #ifndef CASTOR_ELASTIX
00210     Cerr("***** iDeformationElastic::Initialize() -> This specific deformation class should be compiled with the CASTOR_ELASTIX flag on in CMake !" << endl);
00211     Cerr("*****                                      It requires ITK and the elastix library !" << endl);
00212     return 1;
00213   #endif
00214 
00215 
00216   if (!m_checked)
00217   {
00218     Cerr("***** iDeformationElastic::Initialize() -> Parameters should be checked before Initialize() !" << endl);
00219     return 1;
00220   }
00221   
00222   // Normal end
00223   m_initialized = true;
00224   return 0;
00225 }
00226 
00227 
00228 
00229 
00230 
00231 /*
00232   \fn public virtual int  iDeformationElastic::ApplyDeformations()
00233   \param FLTNB* ap_inputImage : input image to deform
00234   \param FLTNB* ap_outputImage : image in which the output of the deformation should be recovered
00235   \param FLTNB* a_direction : a direction for the deformation to perform (forward or backward)
00236   \param int a_defIdx : index of the deformation
00237   \brief This function is an implementation of the pure virtual mother function. The actual deformation should be implemented here 
00238   \return 0 if success, other value otherwise.
00239 */
00240 int iDeformationElastic::ApplyDeformations(FLTNB* ap_inputImage, FLTNB* ap_outputImage, int a_direction, int a_defIdx)
00241 {
00242   // The deformation model should be implemented here, with the help of any private functions if required
00243   
00244   /* The 'a_defIdx' parameter defines the deformation index of the transformation
00245   * The 'a_direction' parameter is an integer which indicates the direction of the deformation to perform, i.e :
00246   * - FORWARD_DEFORMATION (from the reference position to the 'a_defIdx' position) 
00247   * - BACKWARD_DEFORMATION (from the 'a_defIdx' position to the reference position) 
00248   * The integers FORWARD_DEFORMATION & BACKWARD_DEFORMATION are macros defined in the beginning of vDeformation.hh
00249   */
00250   
00251   // The deformation should be applied to theap_inputImage matrix, and the resulting image should be recovered in ap_outputImage matrix
00252 
00253   /* IMAGE DIMENSIONS :
00254   * For code efficiency and readability, the spatial index of a voxel is a cumulative 1D index. That is to say, given a voxel [indexX,indexY,indexZ],
00255   * its cumulative 1D index is computed by 'index = indexZ*nbVoxXY + indexY*nbVoxX + indexX'.
00256   *
00257   * The image dimensions can be recovered from the mp_ID class
00258   * Total number of voxels         : mp_ID->GetNbVoxXYZ()
00259   * Number of voxels in a slice    : mp_ID->GetNbVoxXY()
00260   * Number of voxels on the X-axis : mp_ID->GetNbVoxX()
00261   */
00262     
00263   string path_to_deformation_file;
00264   
00265   if (a_direction==FORWARD_DEFORMATION) path_to_deformation_file = m_pathToFwdDeformationFiles.at(a_defIdx);
00266   else if (a_direction==BACKWARD_DEFORMATION) path_to_deformation_file = m_pathToBwdDeformationFiles.at(a_defIdx);
00267   else
00268   {
00269     Cerr("*****iDeformationElastic::ApplyDeformationToImage()->Error, unknown direction type( must be 'forward' or 'backward' # " << endl);
00270     return 1;
00271   }
00272    
00273   
00274   #ifdef CASTOR_ELASTIX
00275 
00276   //Convert the input image from the binary to the ITK format
00277 
00278   m_RegionSizeInputImage[0] = mp_ID->GetNbVoxX();
00279   m_RegionSizeInputImage[1] = mp_ID->GetNbVoxY();
00280   m_RegionSizeInputImage[2] = mp_ID->GetNbVoxZ();
00281 
00282   m_RegionStartInputImage[0] = 0;
00283   m_RegionStartInputImage[1] = 0;
00284   m_RegionStartInputImage[2] = 0;
00285 
00286   m_RegionInputImage.SetSize( m_RegionSizeInputImage );
00287   m_RegionInputImage.SetIndex( m_RegionStartInputImage );
00288 
00289   ITK_inputImage->SetRegions(m_RegionInputImage);
00290   ITK_inputImage->Allocate();
00291   ITK_inputImage->FillBuffer(0);
00292 
00293   m_RegionSpacingInputImage[0] = mp_ID->GetVoxSizeX();
00294   m_RegionSpacingInputImage[1] = mp_ID->GetVoxSizeY();
00295   m_RegionSpacingInputImage[2] = mp_ID->GetVoxSizeZ();
00296 
00297   ITK_inputImage->SetSpacing( m_RegionSpacingInputImage );
00298 
00299   
00300   for(int i = 0; i< mp_ID->GetNbVoxX(); i++)
00301    for(int j = 0; j< mp_ID->GetNbVoxY(); j++)
00302     for(int k = 0; k< mp_ID->GetNbVoxZ(); k++)
00303     {
00304       m_PixelIndex[0] = i;
00305       m_PixelIndex[1] = j;
00306       m_PixelIndex[2] = k;
00307      
00308       ITK_inputImage->SetPixel( m_PixelIndex, (float)ap_inputImage[i + j*mp_ID->GetNbVoxX() + k*mp_ID->GetNbVoxXY()] );
00309     }
00310 
00311   /*WriterType::Pointer writer = WriterType::New();
00312   writer->SetFileName( "/home/fred/ProjetC/ElasticRegistration_Elastix-v4.8/test_correctionmouvement/test.mhd" );
00313   writer->SetInput( ITK_inputImage );
00314   try
00315       {
00316       writer->Update();
00317       }
00318     catch( itk::ExceptionObject & err )
00319       {
00320       std::cerr << "ExceptionObject caught !" << std::endl;
00321       std::cerr << err << std::endl;
00322       return EXIT_FAILURE;
00323       }  */
00324 
00325 
00326   // Try parsing transform parameters text file.
00327   ParserType::Pointer file_parser = ParserType::New();
00328 
00329   file_parser->SetParameterFileName( path_to_deformation_file );
00330   
00331   try
00332       {
00333   file_parser->ReadParameterFile();
00334   }
00335   catch( itk::ExceptionObject & e )
00336   {
00337   std::cout << e.what() << std::endl;
00338   
00339   // Do some error handling!
00340   Cout("iDeformationElastic::ApplyDeformationToImage()-> ERROR Reading deformation coefficients # " << a_defIdx << ", direction: "<< a_direction << endl);
00341   return 1;
00342   }
00343 
00344   // Retrieve parameter settings as map.
00345   RegistrationParametersType transform_parameters = file_parser->GetParameterMap();
00346 
00347   // Create the Fixed Image
00348 
00349    /* ImageType::Pointer Fixed_Image = ImageType::New();
00350 
00351     string FixedImageName = "/home/fred/ProjetC/ElasticRegistration_Elastix-v4.8/test_correctionmouvement/test_gate1_recon_it7.mhd";
00352     cout << "Loading Fixed Image: " << "/home/fred/ProjetC/ElasticRegistration_Elastix-v4.8/test_correctionmouvement/test_gate1_recon_it7.mhd" << " ...\n";
00353 
00354     ReaderType::Pointer reader_fixed = ReaderType::New();
00355 
00356     reader_fixed->SetFileName( FixedImageName );
00357     reader_fixed->Update();
00358 
00359     Fixed_Image = reader_fixed->GetOutput();*/
00360 
00361 
00363   // We are ready to call the warping function  //
00365   TRANSFORMIX* transformix = new TRANSFORMIX();
00366   int error = 0;
00367 
00368   string results_dir = "/tmp";
00369   
00370   if(m_verbose>1)
00371       {
00372   Cout("iDeformationElastic::ApplyDeformationToImage()->Apply coefficients # " << a_defIdx << ", direction: "<< a_direction << endl);
00373   Cout("iDeformationElastic::Reading_coefficients # " << a_defIdx << ": "<< path_to_deformation_file << endl<<endl);
00374       }
00375 
00376   try
00377      {
00378   error = transformix->TransformImage(
00379     static_cast<typename itk::DataObject::Pointer>( ITK_inputImage.GetPointer() ),
00380           //static_cast<typename itk::DataObject::Pointer>( Fixed_Image.GetPointer() ),
00381      transform_parameters,    // Parameter map read in previous code
00382     results_dir,
00383           false,    // boolean write_log_file, Enable/disable writing of elastix.log
00384     false     // boolean output_to_console, Enable/disable output to console
00385     );
00386      }
00387      catch( itk::ExceptionObject &err )
00388      {  
00389     // Do some error handling.
00390     Cout("iDeformationElastic:: ApplyDeformationToImage()->ERROR Applying coefficients # " << a_defIdx << ", direction: "<< a_direction << endl);
00391     return 1;
00392      }
00393 
00394   if( error == 0 )
00395      {
00396   if( transformix->GetResultImage().IsNotNull() )
00397         {
00398     ITK_outputImage = static_cast<ImageType *>( transformix->GetResultImage().GetPointer() );
00399 
00400     //Convert the Output image from the ITK format to the binary format
00401     for(int i = 0; i< mp_ID->GetNbVoxX(); i++)
00402            for(int j = 0; j< mp_ID->GetNbVoxY(); j++)
00403             for(int k = 0; k< mp_ID->GetNbVoxZ(); k++)
00404        {
00405          m_PixelIndex[0] = i;
00406          m_PixelIndex[1] = j;
00407          m_PixelIndex[2] = k;
00408 
00409          if (ITK_outputImage->GetPixel( m_PixelIndex ) < 0.0) ap_outputImage[i + j*mp_ID->GetNbVoxX() + k*mp_ID->GetNbVoxXY()] = 0.0;
00410          else ap_outputImage[i + j*mp_ID->GetNbVoxX() + k*mp_ID->GetNbVoxXY()] = ITK_outputImage->GetPixel( m_PixelIndex );
00411     //ap_outputImage[i + j*mp_ID->GetNbVoxX() + k*mp_ID->GetNbVoxXY()] = ITK_inputImage->GetPixel( m_PixelIndex );
00412        }
00413         }
00414       else
00415       {
00416     // Registration failure. Do some error handling.
00417     Cout("iDeformationElastic:: ApplyDeformationToImage()->ERROR in saving the warped image after applying coefficients # " << a_defIdx << ", direction: "<< a_direction << endl);
00418     return 1;
00419         }
00420      }
00421 
00422   // Typedef the ITKImageType first...
00423   /*stringstream ss;
00424   ss << a_defIdx;
00425   WriterType::Pointer writer = WriterType::New();
00426   writer->SetFileName( "/home/fred/ProjetC/ElasticRegistration_Elastix-v4.8/test_correctionmouvement/test_warping_"+ss.str()+"_"+a_direction+".mhd" );
00427   writer->SetInput( ITK_outputImage );
00428   try
00429       {
00430       writer->Update();
00431       }
00432     catch( itk::ExceptionObject & err )
00433       {
00434       std::cerr << "ExceptionObject caught !" << std::endl;
00435       std::cerr << err << std::endl;
00436       return EXIT_FAILURE;
00437       }*/
00438   
00439 
00440   // Clean up memory.
00441   delete transformix;
00442 
00443   #endif
00444   
00445   
00446   
00447   // Any error should return a value >0.
00448   
00449   // Normal end
00450   return 0;
00451 }
 All Classes Files Functions Variables Typedefs Defines