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