![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
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 }