CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iDeformationRigid.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class iDeformationRigid
00004 
00005   - separators: X
00006   - doxygen: X
00007   - default initialization: X
00008   - CASTOR_DEBUG: X
00009   - CASTOR_VERBOSE: X
00010 */
00011 
00018 #include "iDeformationRigid.hh"
00019 
00020 
00021 // =====================================================================
00022 // ---------------------------------------------------------------------
00023 // ---------------------------------------------------------------------
00024 // =====================================================================
00025 /*
00026   \fn iDeformationRigid
00027   \brief Constructor of iDeformationRigid. Simply set all data members to default values.
00028 */
00029 iDeformationRigid::iDeformationRigid() : vDeformation()
00030 {
00031   m_pathToFwdDeformationFiles.clear();
00032   m_pathToBwdDeformationFiles.clear();
00033   m_OriginalArray = NULL;
00034   m_OutputArray = NULL;
00035   mp_vectorX = NULL;
00036   mp_vectorY = NULL;
00037   mp_vectorZ = NULL;
00038 }
00039 
00040 
00041 
00042 
00043 // =====================================================================
00044 // ---------------------------------------------------------------------
00045 // ---------------------------------------------------------------------
00046 // =====================================================================
00047 /*
00048   \fn ~iDeformationRigid
00049   \brief Destructor of iDeformationRigid. Free memory from all allocated tabs.
00050 */
00051 iDeformationRigid::~iDeformationRigid() 
00052 {
00053   if(m_initialized)
00054   {
00055     m_pathToFwdDeformationFiles.clear();
00056     m_pathToBwdDeformationFiles.clear();
00057     if(m_OriginalArray) delete[] m_OriginalArray;
00058     if(m_OutputArray) delete[] m_OutputArray;  
00059     if(mp_vectorX) delete[] mp_vectorX; 
00060     if(mp_vectorY) delete[] mp_vectorY; 
00061     if(mp_vectorZ) delete[] mp_vectorZ; 
00062   }
00063 }
00064 
00065 
00066 
00067 
00068 // =====================================================================
00069 // ---------------------------------------------------------------------
00070 // ---------------------------------------------------------------------
00071 // =====================================================================
00072 /*
00073   \fn ShowHelp
00074   \brief This function is used to print out specific help about the deformation and its options.
00075 */
00076 void iDeformationRigid::ShowHelp()
00077 {
00078   // todo : really we should rather use param files in binary format here
00079   cout << "-- Rigid transformation algorithm based on trilinear interpolation --" << endl;
00080   cout << "It requires a set of ASCII transformation files containing the forward and backward deformation vectors" << endl;
00081   cout << endl;
00082   cout << "The path and basename of the transformation files must be provided through a main ASCII header file" <<endl;
00083   cout << "(1) First provide the path to the file using the -rm (respiratory) -cm (cardiac) or -im (patient) motion correction option :" << endl;
00084   cout << "-rm/cm/im deformationRigid:path_to/header_init_file.txt" << endl;
00085   cout << "The header must contain the keywords 'Forward vector files' and 'Backward vector files'," << endl;
00086   cout << "which provide the basename of the vector files related to the forward and backward deformation respectively" << endl;
00087   cout << "Ex :" << endl;
00088   cout << "--------------------------------------------------------" << endl;
00089   cout << "header_init_file.txt :" << endl;
00090   cout << "--------------------------------------------------------" << endl;
00091   cout << "Forward vector files  : pathTo/parameterFiles_Fwd_%d.xxx" << endl;
00092   cout << "Backward vector files : pathTo/parameterFiles_Bwd_%d.xxx" << endl;
00093   cout << "--------------------------------------------------------" << endl;
00094   cout << "In the header file, the gate index should be replaced by '%d' as presented in the exemple above." << endl;
00095   cout << "The Forward/Backward vector ASCII files must be ordered from 1 (not 0) to the last transformation index." << endl;
00096   cout << "For each voxel, the x,y,z components of the vector must be provided on a new line, as in the following template :" << endl;
00097   cout << "Ex :" << endl;
00098   cout << "--------------------------------------------------------" << endl;
00099   cout << "parameterFiles_Fwd_1.txt :" << endl;
00100   cout << "--------------------------------------------------------" << endl;
00101   cout << "vox0_x" << endl;
00102   cout << "vox0_y" << endl;
00103   cout << "vox0_z" << endl;
00104   cout << "vox1_x" << endl;
00105   cout << "vox1_y" << endl;
00106   cout << "vox1_z" << endl;
00107   cout << "ect ..." << endl;
00108   cout << "--------------------------------------------------------" << endl;
00109 }
00110 
00111 
00112 
00113 
00114 // =====================================================================
00115 // ---------------------------------------------------------------------
00116 // ---------------------------------------------------------------------
00117 // =====================================================================
00118 /*
00119   \fn ReadAndCheckConfigurationFile
00120   \param a_configurationFile
00121   \brief This function is used to read options from a configuration file.
00122   \return 0 if success, other value otherwise.
00123 */
00124 int iDeformationRigid::ReadAndCheckConfigurationFile(const string& a_fileOptions)
00125 {
00126   if (m_verbose >=2) Cout("iDeformationRigid::ReadAndCheckConfigurationFile ..."<< endl); 
00127   
00128   // First, check the nb of transformations has correctly been initializeds
00129   if (m_nbTransformations<0)
00130   {
00131     Cerr("***** iDeformationRigid::ReadAndCheckConfigurationFile() -> Number of transformations in the deformation has not been initialized  !" << endl);
00132     return 1;
00133   }
00134   
00135   // Need to know the gate numbers before
00136   ifstream in_file(a_fileOptions.c_str(), ios::in);
00137   
00138   if(!in_file)
00139   {
00140     Cerr("***** iDeformationRigid::ReadAndCheckConfigurationFile -> Error while trying to read configuration file : " << a_fileOptions << endl);
00141     return 1;
00142   }
00143   
00144   string line;
00145   char* str_tmp;
00146   
00147   // --- Recover forward files basename (1st string in the file) --- //
00148   getline(in_file, line);
00149   str_tmp = new char[line.size()];
00150 
00151   for(int t=0 ; t<m_nbTransformations ; t++)
00152   {
00153     sprintf(str_tmp, line.c_str(), t+1);
00154     m_pathToFwdDeformationFiles.push_back(str_tmp);
00155   }
00156 
00157 
00158   // --- Recover backward files basename (2nd string in the file) --- //
00159   getline(in_file, line);
00160   
00161   delete str_tmp;
00162   str_tmp = new char[line.size()];
00163 
00164   for(int t=0 ; t<m_nbTransformations ; t++)
00165   {
00166     sprintf(str_tmp, line.c_str(), t+1);
00167     m_pathToBwdDeformationFiles.push_back(str_tmp);
00168   }
00169   
00170   
00171   // Delete local objects
00172   delete str_tmp;
00173   in_file.close();
00174   
00175   
00176   // --- Check file existence --- //
00177   
00178    // \todo Perhaps more checks on the consistency of the file. May do this in initialization though
00179   
00180   for(int t=0 ; t<m_nbTransformations ; t++)
00181   {
00182     ifstream in_file_fwd(m_pathToFwdDeformationFiles.at(t).c_str(), ios::in);
00183     ifstream in_file_bwd(m_pathToBwdDeformationFiles.at(t).c_str(), ios::in);
00184     
00185     if(!in_file_fwd)
00186     {
00187       Cerr("***** iDeformationRigid::ReadAndCheckConfigurationFile -> Error while trying to read forward deformation vectors file number" << t <<  ": " 
00188            << m_pathToFwdDeformationFiles.at(t) << endl);
00189       return 1;
00190     }
00191 
00192     if(!in_file_bwd)
00193     {
00194       Cerr("***** iDeformationRigid::ReadAndCheckConfigurationFile -> Error while trying to read backward deformation vectors file number" << t <<  ": " 
00195            << m_pathToBwdDeformationFiles.at(t) << endl);
00196       return 1;
00197     }
00198     in_file_fwd.close();
00199     in_file_bwd.close();
00200   }
00201 
00202   return 0;  
00203 }
00204 
00205 // =====================================================================
00206 // ---------------------------------------------------------------------
00207 // ---------------------------------------------------------------------
00208 // =====================================================================
00209 /*
00210   \fn ReadAndCheckOptionsList
00211   \param a_optionsList
00212   \brief This function is used to read options from a list of options.
00213          Throw error by defaut for this method, as a file has to be used for initialization
00214   \return 0 if success, other value otherwise.
00215 */
00216 int iDeformationRigid::ReadAndCheckOptionsList(const string& a_listOptions)
00217 {
00218   if(m_verbose >=2) Cout("iDeformationRigid::ReadAndCheckOptionsList ..."<< endl); 
00219   
00220   Cerr("***** iDeformationRigid::ReadAndCheckOptionsList -> This deformation algorithm needs to use a file for its initialization. Use help for more info !" << endl);
00221   return 1;
00222 }
00223 
00224 // =====================================================================
00225 // ---------------------------------------------------------------------
00226 // ---------------------------------------------------------------------
00227 // =====================================================================
00228 /*
00229   \fn CheckSpecificParameters
00230   \brief This function is used to check parameters after the latter
00231          have been all set using Set functions.
00232   \return 0 if success, positive value otherwise.
00233 */
00234 int iDeformationRigid::CheckSpecificParameters()
00235 {
00236   if(m_verbose >=2) Cout("iDeformationRigid::CheckSpecificParameters ..."<< endl); 
00237   
00238   // Check vector files
00239   if (m_pathToFwdDeformationFiles.empty() || 
00240       m_pathToBwdDeformationFiles.empty() )
00241   {
00242     Cerr("***** iDeformationRigid::CheckSpecificParameters() -> Vector files not initialized !" << endl);
00243     return 1;
00244   }
00245   
00246   // todo consistency of param files here
00247   
00248   // Normal end
00249   m_checked = true;
00250   return 0;
00251 }
00252 
00253 // =====================================================================
00254 // ---------------------------------------------------------------------
00255 // ---------------------------------------------------------------------
00256 // =====================================================================
00257 /*
00258   \fn Initialize
00259   \brief This function is used to initialize specific stuff in the deformation model.
00260   \details Allocate memory for image matrices, and initialize images containing transformation parameters
00261   \return 0 if success, other value otherwise.
00262 */
00263 int iDeformationRigid::Initialize()
00264 {
00265   if(m_verbose >=2) Cout("iDeformationRigid::Initialize ..."<< endl); 
00266   
00267   // Forbid initialization without check
00268   if (!m_checked)
00269   {
00270     Cerr("***** iDeformationRigid::Initialize() -> Parameters should be checked before Initialize() !" << endl);
00271     return 1;
00272   }
00273   
00274   // Memory allocation
00275   m_OriginalArray = new double [mp_ID->GetNbVoxXYZ()];
00276   m_OutputArray   = new double [mp_ID->GetNbVoxXYZ()];
00277   mp_vectorX = new FLTNB [mp_ID->GetNbVoxXYZ()];
00278   mp_vectorY = new FLTNB [mp_ID->GetNbVoxXYZ()];
00279   mp_vectorZ = new FLTNB [mp_ID->GetNbVoxXYZ()];
00280   
00281   for (int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
00282   {
00283     mp_vectorX[v] = 0;
00284     mp_vectorY[v] = 0;
00285     mp_vectorZ[v] = 0;
00286   }
00287 
00288   // Normal end
00289   m_initialized = true;
00290   return 0;
00291 }
00292 
00293 // =====================================================================
00294 // ---------------------------------------------------------------------
00295 // ---------------------------------------------------------------------
00296 // =====================================================================
00297 /*
00298   \fn ApplyDeformations
00299   \param ap_inputImage : input image to deform
00300   \param ap_outputImage : image in which the output of the deformation should be recovered
00301   \param a_direction : a direction for the deformation to perform (forward or backward)
00302   \param a_defIdx : index of the deformation
00303   \brief This function prepares the deformation to perform 
00304   \details 1. Selects the right deformation parameters file according to the direction and deformation index argument
00305            2. Copy the image to deform in the buffer image of this class
00306            3. Call the deformation function (WarpImage)
00307            4. Copy back the output of the deformation image to the output image matrice passed in argument
00308   \return 0 if success, other value otherwise.
00309 */
00310 int iDeformationRigid::ApplyDeformations(FLTNB* ap_inputImage, FLTNB* ap_outputImage, int a_direction, int a_defIdx)
00311 {
00312   #ifdef CASTOR_DEBUG
00313   if (!m_initialized)
00314   {
00315     Cerr("***** iDeformationRigid::ApplyDeformations() -> Called while not initialized !" << endl);
00316     Exit(EXIT_DEBUG);
00317   }
00318   #endif
00319 
00320   #ifdef CASTOR_VERBOSE
00321   if(m_verbose >=4) Cout("iDeformationRigid::ApplyDeformations ... "<< endl); 
00322   #endif
00323   
00324   string path_to_deformation_file = "";
00325   if (a_direction==FORWARD_DEFORMATION) path_to_deformation_file = m_pathToFwdDeformationFiles.at(a_defIdx);
00326   else if (a_direction==BACKWARD_DEFORMATION) path_to_deformation_file = m_pathToBwdDeformationFiles.at(a_defIdx);
00327   else
00328   {
00329     Cerr("*****iDeformationRigid::ApplyDeformationToForwardImage()->Error, unknown direction type( must be 'forward' or 'backward' # " << endl);
00330     return 1;
00331   }
00332 
00333   for(int v=0; v<mp_ID->GetNbVoxXYZ(); v++)
00334   {
00335     m_OriginalArray[v] = (double) ap_inputImage[v];
00336     m_OutputArray[v] = 0.0;
00337   }
00338   
00339   // Apply all required deformations
00340   WarpImage(path_to_deformation_file, m_OriginalArray, m_OutputArray); 
00341 
00342   for(int v=0; v<mp_ID->GetNbVoxXYZ(); v++)
00343   {
00344     if (m_OutputArray[v] < 0) m_OutputArray[v] = 0;
00345     ap_outputImage[v] = (FLTNB) m_OutputArray[v];
00346   }
00347   
00348   return 0;
00349 }
00350 
00351 
00352 
00353 
00354 // =====================================================================
00355 // ---------------------------------------------------------------------
00356 // ---------------------------------------------------------------------
00357 // =====================================================================
00358 /*
00359   \fn WarpImage
00360   \param a_vectorFileIdx : deformation vector file
00361   \param ap_inputImage : image on which the deformation should be performed
00362   \param ap_outputImage : matrice which recovers the image after deformation
00363   \brief This function performs a rigid transformation using x,y,z displacement vectors and trilinear interpolation
00364   \details 1. Load the X,Y,Z transformation vectors from the file passed in argument
00365            2. Loop on the voxels and compute the new voxels value using trilinear interpolation
00366   \todo : perhaps add options to load all the vector parameters in RAM during initialization, instead on reading files during reconstruction
00367   \todo : perhaps use padded image in order to avoid if statements
00368   \return 0 if success, other value otherwise.
00369 */
00370 int iDeformationRigid::WarpImage(string a_vectorFileIdx, double *ap_inputImage, double *ap_outputImage)
00371 {
00372   #ifdef CASTOR_VERBOSE
00373   if(m_verbose >=4)
00374   {
00375     Cout("iDeformationRigid::WarpImage using the following coefficients file : "<< endl); 
00376     Cout(a_vectorFileIdx << endl); 
00377   }
00378   #endif
00379   
00380   // Get the vector coefficients
00381   // Todo : perhaps add options to load all the vector parameters in images matrices during initialization
00382   //        require more memory (x2*nb_transformations), but avoid data reading during reconstruction
00383   if(LoadVectorFiles(a_vectorFileIdx) )
00384   {
00385     Cerr("*****iDeformationRigid::WarpImage()-> An error occured while trying to read a deformation parameters file !" << endl);
00386     return 1;
00387   }
00388   
00389   for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
00390   {
00391     // For each axis component, get floor value, sign and fractional part of the vector
00392     int DepXEnt = (int) (mp_vectorX[v]) ;
00393     int DepXSign = (int) ( (mp_vectorX[v]==0) ? 0: mp_vectorX[v]/fabs(mp_vectorX[v]));
00394     float DX = fabs(mp_vectorX[v] - DepXEnt) ;
00395     
00396     int DepYEnt = (int) (mp_vectorY[v]) ;
00397     int DepYSign = (int) ((mp_vectorY[v]==0) ? 0: mp_vectorY[v]/fabs(mp_vectorY[v]));
00398     float DY = fabs(mp_vectorY[v] - DepYEnt) ;
00399     
00400     int DepZEnt = (int) (mp_vectorZ[v]) ;
00401     int DepZSign = (int) ((mp_vectorZ[v]==0) ? 0: mp_vectorZ[v]/fabs(mp_vectorZ[v]));
00402     float DZ = fabs(mp_vectorZ[v] - DepZEnt) ;
00403             
00404     // Get position of central voxel
00405     int q = v
00406             + DepXEnt 
00407             + DepYEnt * mp_ID->GetNbVoxX()
00408             + DepZEnt * mp_ID->GetNbVoxXY();
00409     
00410     // Trilinear interpolation
00411     // Todo : Use padded image in order to avoid 'if' statements ?
00412     if ((q <  mp_ID->GetNbVoxXYZ()) 
00413      && (q >= 0)) 
00414       ap_outputImage[v] = ap_inputImage[q] * (1-DX)*(1-DY)*(1-DZ);
00415              
00416     if ((q+DepXSign <  mp_ID->GetNbVoxXYZ()) 
00417      && (q+DepXSign >= 0))
00418         ap_outputImage[v] += ap_inputImage[q+DepXSign] * DX*(1-DY)*(1-DZ);
00419                 
00420     if ((q+DepYSign*mp_ID->GetNbVoxX() <  mp_ID->GetNbVoxXYZ() )
00421     &&  (q+DepYSign*mp_ID->GetNbVoxX() >= 0))
00422         ap_outputImage[v] += ap_inputImage[q +DepYSign*mp_ID->GetNbVoxX()] * (1-DX)*DY*(1-DZ);
00423                                  
00424     if ((q+DepXSign+DepYSign*mp_ID->GetNbVoxX() <  mp_ID->GetNbVoxXYZ()) 
00425     && ( q+DepXSign+DepYSign*mp_ID->GetNbVoxX() >= 0))
00426         ap_outputImage[v] += ap_inputImage[q+DepXSign+DepYSign*mp_ID->GetNbVoxX()] * DX*DY*(1-DZ);
00427                 
00428     if ((q+DepZSign*mp_ID->GetNbVoxXY()  <  mp_ID->GetNbVoxXYZ()) 
00429      && (q+DepZSign*mp_ID->GetNbVoxXY()) >= 0)
00430         ap_outputImage[v] += ap_inputImage[q+DepZSign*mp_ID->GetNbVoxXY()] * (1-DX)*(1-DY)*DZ;
00431 
00432     if ((q+DepXSign+DepZSign*mp_ID->GetNbVoxXY()) <  mp_ID->GetNbVoxXYZ()  
00433     &&  (q+DepXSign+DepZSign*mp_ID->GetNbVoxXY()) >=0 )
00434         ap_outputImage[v] += ap_inputImage[q+DepXSign+DepZSign*mp_ID->GetNbVoxXY()] * DX*(1-DY)*DZ;
00435 
00436     if ((q+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY() <  mp_ID->GetNbVoxXYZ()) 
00437      && (q+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY() >= 0))
00438         ap_outputImage[v] += ap_inputImage[q+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY()] * (1-DX)*DY*DZ;
00439 
00440     if ((q+DepXSign+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY() <  mp_ID->GetNbVoxXYZ()) 
00441     &&  (q+DepXSign+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY() >= 0))
00442         ap_outputImage[v] += ap_inputImage[q+DepXSign+DepYSign*mp_ID->GetNbVoxX()+DepZSign*mp_ID->GetNbVoxXY()] *DX*DY*DZ;
00443   }  
00444   
00445   return 0;
00446 }
00447 
00448 
00449 
00450 
00451 // =====================================================================
00452 // ---------------------------------------------------------------------
00453 // ---------------------------------------------------------------------
00454 // =====================================================================
00455 /*
00456   \fn LoadVectorFiles
00457   \param a_vectorFileIdx : deformation vector file
00458   \brief Load the transformation parameters from an ASCII file provided in argument
00459   \return 0 if success, other value otherwise.
00460 */
00461 int iDeformationRigid::LoadVectorFiles(string a_vectorFileIdx)
00462 {
00463   #ifdef CASTOR_VERBOSE
00464   if(m_verbose >=4) Cout("iDeformationRigid::LoadVectorFiles ... "<< endl); 
00465   #endif
00466   
00467   ifstream vector_file(a_vectorFileIdx.c_str(), ios::in);
00468   
00469   if(!vector_file) 
00470   {
00471     Cerr("*****iDeformationRigid::LoadVectorFiles()-> An error occured while trying to read the file " << a_vectorFileIdx << " !" << endl);
00472     return 1;
00473   }
00474   
00475   for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
00476   {
00477     vector_file >> mp_vectorX[v];
00478     vector_file >> mp_vectorY[v];
00479     vector_file >> mp_vectorZ[v];
00480   }
00481 
00482   return 0;
00483 }
 All Classes Files Functions Variables Typedefs Defines