CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
00001 00002 /* 00003 Implementation of class iPatlakModel 00004 00005 - separators: X 00006 - doxygen: X 00007 - default initialization: none (require user inputs (Patlak basis functions), no sense to provide 'standard' configuration file as for optimizer/projector) 00008 - CASTOR_DEBUG: X 00009 - CASTOR_VERBOSE: X 00010 */ 00011 00019 #include "iPatlakModel.hh" 00020 00021 00022 // ===================================================================== 00023 // --------------------------------------------------------------------- 00024 // --------------------------------------------------------------------- 00025 // ===================================================================== 00026 /* 00027 \fn iPatlakModel 00028 \brief Constructor of iPatlakModel. Simply set all data members to default values. 00029 */ 00030 iPatlakModel::iPatlakModel() : vDynamicModel() 00031 { 00032 m_nbTimeBF = 2; // Two basis functions in the Patlak model 00033 m2p_parametricImages = NULL; 00034 m2p_patlakTACs = NULL; 00035 00036 m_fileOptions = ""; 00037 m_listOptions = ""; 00038 00039 m_savePImgFlag = true; 00040 } 00041 00042 00043 00044 00045 // ===================================================================== 00046 // --------------------------------------------------------------------- 00047 // --------------------------------------------------------------------- 00048 // ===================================================================== 00049 /* 00050 \fn ~iPatlakModel 00051 \brief Destructor of iPatlakModel 00052 */ 00053 iPatlakModel::~iPatlakModel() 00054 { 00055 if(m_initialized) 00056 { 00057 for(int b=0 ; b<m_nbTimeBF ; b++) 00058 { 00059 if (m2p_patlakTACs[b]) delete m2p_patlakTACs[b]; 00060 if (m2p_parametricImages[b]) delete m2p_parametricImages[b]; 00061 } 00062 00063 if (m2p_patlakTACs) delete[] m2p_patlakTACs; 00064 if (m2p_parametricImages) delete[] m2p_parametricImages; 00065 } 00066 } 00067 00068 00069 00070 00071 // ===================================================================== 00072 // --------------------------------------------------------------------- 00073 // --------------------------------------------------------------------- 00074 // ===================================================================== 00075 /* 00076 \fn ShowHelp 00077 \brief Print out specific help about the implementation of the Patlak 00078 model and its initialization 00079 */ 00080 void iPatlakModel::ShowHelp() 00081 { 00082 cout << "-- This class implements the Patlak Reference Tissue Model : " << endl; 00083 cout << "-- Patlak CS, Blasberg RG: Graphical evaluation of blood-to-brain transfer constants from multiple-time uptake data" << endl; 00084 cout << "-- J Cereb Blood Flow Metab 1985, 5(4):5 84-590." << endl; 00085 cout << "-- DOI http://dx.doi.org/10.1038/jcbfm.1985.87" << endl; 00086 cout << "-- It is used to model radiotracers which follows as 2-tissue compartment model with irreversible trapping " << endl; 00087 cout << "-- The Patlak temporal basis functions are composed of the Patlak slope (integral of the reference TAC from the injection time " << endl; 00088 cout << " divided by the instantaneous reference activity), and intercept (reference tissue TAC) " << endl; 00089 cout << endl; 00090 cout << " It can be initialized using either an ASCII file or a list of option with the following keywords and information :" << endl; 00091 cout << " - The ASCII file must contain the following keywords :" << endl; 00092 cout << " 'Patlak_functions:' (mandatory) Enter the coefficients of Patlak plot and intercept for each time frame (tf) "; 00093 cout << " on two successive lines, separated by ',' :" << endl; 00094 cout << " -> Patlak_functions: " << endl; 00095 cout << " -> coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn" << endl; 00096 cout << " -> coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn" << endl; 00097 cout << " 'Parametric_image_init:' (optional) path to an interfile image to be used as initialization for the parametric images" << endl; 00098 cout << " 'Patlak_save_images:' (optional) boolean indicating if the parametric images should be saved (1) or not (0)" << endl; 00099 cout << endl; 00100 cout << " - The list of options must contain the coefficients of both Patlak functions separated by commas, with the following template :" << endl; 00101 cout << " coeff_Pplot_tf1,coeff_Pplot_tf2,...,coeff_Pplot_tfn,"; 00102 cout << " coeff_Pintc_tf1,coeff_Pintc_tf2,...,coeff_Pintc_tfn "<< endl; 00103 cout << " Parametric images will be initialized with 1.0 by default " << endl; 00104 cout << " The parametric images estimations will be written on disk for each iteration" << endl; 00105 cout << " " << endl; 00106 } 00107 00108 00109 00110 00111 // ===================================================================== 00112 // --------------------------------------------------------------------- 00113 // --------------------------------------------------------------------- 00114 // ===================================================================== 00115 /* 00116 \fn ReadAndCheckConfigurationFile 00117 \param const string& a_configurationFile : ASCII file containing informations about a dynamic model 00118 \brief This function is used to read options from a configuration file. 00119 \return 0 if success, other value otherwise. 00120 */ 00121 int iPatlakModel::ReadAndCheckConfigurationFile(string a_fileOptions) 00122 { 00123 if(m_verbose >=2) Cout("iPatlakModel::ReadAndCheckConfigurationFile ..."<< endl); 00124 00125 // Recover the file path here, it will be processed in the Initialize() function 00126 m_fileOptions = a_fileOptions; 00127 00128 ifstream in_file(a_fileOptions.c_str(), ios::in); 00129 00130 if(in_file) 00131 { 00132 if( ReadDataASCIIFile(a_fileOptions, "Patlak_save_images", &m_savePImgFlag, 1, KEYWORD_OPTIONAL) == 1) 00133 { 00134 Cerr("***** iPatlakModel::ReadAndCheckConfigurationFile -> Error while trying to read 'Patlak_save_images' flag in " << a_fileOptions << endl); 00135 return 1; 00136 } 00137 } 00138 else 00139 { 00140 Cerr("***** iPatlakModel::ReadAndCheckConfigurationFile -> Error while trying to read configuration file at: " << a_fileOptions << endl); 00141 return 1; 00142 } 00143 00144 return 0; 00145 } 00146 00147 00148 00149 00150 // ===================================================================== 00151 // --------------------------------------------------------------------- 00152 // --------------------------------------------------------------------- 00153 // ===================================================================== 00154 /* 00155 \fn ReadAndCheckOptionsList 00156 \param const string& a_optionsList : a list of parameters separated by commas 00157 \brief This function is used to read parameters from a string. 00158 \return 0 if success, other value otherwise. 00159 */ 00160 int iPatlakModel::ReadAndCheckOptionsList(string a_listOptions) 00161 { 00162 if(m_verbose >=2) Cout("iPatlakModel::ReadAndCheckOptionsList ..."<< endl); 00163 00164 // Just recover the string here, it will be processed in the Initialize() function 00165 m_listOptions = a_listOptions; 00166 00167 // Normal end 00168 return 0; 00169 } 00170 00171 00172 00173 00174 // ===================================================================== 00175 // --------------------------------------------------------------------- 00176 // --------------------------------------------------------------------- 00177 // ===================================================================== 00178 /* 00179 \fn CheckSpecificParameters 00180 \brief This function is used to check whether all member variables 00181 have been correctly initialized or not. 00182 \return 0 if success, positive value otherwise. 00183 */ 00184 int iPatlakModel::CheckSpecificParameters() 00185 { 00186 if(m_verbose >=2) Cout("iPatlakModel::CheckSpecificParameters ..."<< endl); 00187 00188 // Check image dimensions 00189 if (mp_ID==NULL) 00190 { 00191 Cerr("***** iPatlakModel::CheckParameters() -> ImageDimensions object has not been provided !" << endl); 00192 return 1; 00193 } 00194 00195 // Check number time basis functions 00196 if (m_nbTimeBF<0) 00197 { 00198 Cerr("***** iPatlakModel::CheckParameters() -> Wrong number of time frame basis functions !" << endl); 00199 return 1; 00200 } 00201 00202 // Check if we have somehow both a file and a list of options for init... 00203 if(m_listOptions != "" && m_fileOptions != "") 00204 { 00205 Cerr("***** iPatlakModel::Initialize -> Either a file or a list of options have to be selected to initialize the model, but not both ! " << endl); 00206 return 1; 00207 } 00208 00209 // Check if we have no file not list of options for some reason... 00210 if(m_listOptions == "" && m_fileOptions == "") 00211 { 00212 Cerr("***** iPatlakModel::Initialize -> Either a file or a list of options should have been provided at this point ! " << endl); 00213 return 1; 00214 } 00215 00216 // Check if we reconstruct gated data. Throw warning if it is the case 00217 if(mp_ID->GetNbRespGates()>1 || mp_ID->GetNbCardGates()>1) 00218 { 00219 Cerr("***** iPatlakModel::Initialize -> WARNING : the implemented Patlak model should not be used with gated reconstruction (parametric images will be the same for each gate)! " << endl); 00220 //return 1; 00221 } 00222 00223 00224 // Normal end 00225 return 0; 00226 } 00227 00228 00229 00230 00231 // ===================================================================== 00232 // --------------------------------------------------------------------- 00233 // --------------------------------------------------------------------- 00234 // ===================================================================== 00235 /* 00236 \fn Initialize 00237 \brief This function is used to initialize Patlak parametric images and basis functions 00238 \return 0 if success, other value otherwise. 00239 */ 00240 int iPatlakModel::Initialize() 00241 { 00242 if(m_verbose >=2) Cout("iPatlakModel::Initialize ..."<< endl); 00243 00244 // Forbid initialization without check 00245 if (!m_checked) 00246 { 00247 Cerr("***** oDynamicModelManager::Initialize() -> Must call CheckParameters functions before Initialize() !" << endl); 00248 return 1; 00249 } 00250 00251 // --- Memory Allocation --- // 00252 00253 // Allocate memory for Parametric images and functions of Patlak model 00254 m2p_patlakTACs = new FLTNB*[m_nbTimeBF]; 00255 m2p_parametricImages = new FLTNB*[m_nbTimeBF]; 00256 00257 for(int b=0 ; b<m_nbTimeBF ; b++) 00258 { 00259 m2p_patlakTACs[b] = new FLTNB[mp_ID->GetNbTimeFrames()]; 00260 m2p_parametricImages[b] = new FLTNB[mp_ID->GetNbVoxXYZ()]; 00261 } 00262 00263 00264 // --- Data Initialization with a configuration file --- // 00265 00266 if(m_fileOptions != "") 00267 { 00268 ifstream in_file(m_fileOptions.c_str(), ios::in); 00269 00270 if(in_file) 00271 { 00272 // Patlak basis functions Initialization 00273 if( ReadDataASCIIFile(m_fileOptions, 00274 "Patlak_functions", 00275 m2p_patlakTACs, 00276 mp_ID->GetNbTimeFrames(), 00277 m_nbTimeBF, 00278 KEYWORD_MANDATORY) ) 00279 { 00280 Cerr("***** iPatlakModel::Initialize -> Error while trying to read Patlak functions coefficients !" << endl); 00281 Cerr(" 'Patlak_functions' keyword in " << m_fileOptions << endl); 00282 return 1; 00283 } 00284 00285 // Patlak Parametric images initialization 00286 string input_image = ""; 00287 int return_value = 0; 00288 00289 return_value = ReadDataASCIIFile(m_fileOptions, 00290 "Parametric_images_init", 00291 &input_image, 00292 1, 00293 KEYWORD_OPTIONAL); 00294 00295 if( return_value == 0) // Image have been provided 00296 { 00297 // Read image // INTF_LERP_DISABLED = interpolation disabled for input image reading 00298 if( IntfReadImgDynCoeffFile(input_image, 00299 m2p_parametricImages, 00300 mp_ID, 00301 m_nbTimeBF, 00302 m_verbose, 00303 INTF_LERP_DISABLED) ) // Image have been provided 00304 { 00305 Cerr("***** iPatlakModel::Initialize -> Error while trying to read the provided initialization parametric images : " << input_image << endl); 00306 return 1; 00307 } 00308 00309 //normal end 00310 return 0; 00311 } 00312 else if( return_value == 1) // Error during reading 00313 { 00314 Cerr("***** iPatlakModel::Initialize -> Error while trying to read Patlak functions coefficients !" << endl); 00315 Cerr(" 'Parametric_image_init' keyword in " << m_fileOptions << endl); 00316 return 1; 00317 } 00318 else //(return_value >= 1 ) // Keyword not found : no initialization provided 00319 { 00320 // Standard initialization 00321 for(int b=0 ; b<m_nbTimeBF ; b++) 00322 for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00323 m2p_parametricImages[b][v] = 1.; 00324 } 00325 00326 } 00327 00328 else 00329 { 00330 Cerr("***** iPatlakModel::Initialize() -> Error while trying to read configuration file at: " << m_fileOptions << endl); 00331 return 1; 00332 } 00333 } 00334 00335 00336 // --- Data Initialization with a list of options --- // 00337 00338 if(m_listOptions != "") 00339 { 00340 // We expect here the coefficients of the Patlak functions for each time point 00341 // Patlak slope before Patlak intercept 00342 00343 // Allocate memory to recover the elements in one tmp vector 00344 FLTNB *p_coeffs = new FLTNB[m_nbTimeBF * mp_ID->GetNbTimeFrames()]; 00345 00346 // Read them 00347 if (ReadStringOption(m_listOptions, 00348 p_coeffs, 00349 m_nbTimeBF * mp_ID->GetNbTimeFrames(), 00350 ",", 00351 "Patlak model configuration")) 00352 { 00353 Cerr("***** iPatlakModel::Initialize() -> Failed to correctly read the list of options !" << endl); 00354 return 1; 00355 } 00356 00357 // Affect coeffs 00358 for(int c=0 ; c<m_nbTimeBF * mp_ID->GetNbTimeFrames() ; c++) 00359 { 00360 int bf = int(c/mp_ID->GetNbTimeFrames()); // Patlak basis function index 00361 int fr = int(c%mp_ID->GetNbTimeFrames()); // Frame index 00362 m2p_patlakTACs[bf][fr] = p_coeffs[c]; 00363 } 00364 00365 // Delete the tmp vector 00366 delete[] p_coeffs; 00367 00368 00369 // Standard initialization for the parametric images 00370 for(int b=0 ; b<m_nbTimeBF ; b++) 00371 for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00372 m2p_parametricImages[b][v] = 1.; 00373 } 00374 00375 // Display Patlak TACs 00376 if(m_verbose >=2) 00377 { 00378 Cout("iPatlakModel::Initialize() -> Patlak Normalized Time TAC coefficients :" << endl); 00379 Cout(" "); 00380 for(int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00381 Cout(m2p_patlakTACs[0][fr] << ", "); 00382 Cout(endl); 00383 Cout("iPatlakModel::Initialize() -> Patlak Reference Time TAC coefficients :" << endl); 00384 Cout(" "); 00385 for(int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00386 Cout(m2p_patlakTACs[1][fr] << ", "); 00387 Cout(endl); 00388 } 00389 00390 // Normal end 00391 m_initialized = true; 00392 return 0; 00393 } 00394 00395 00396 00397 00398 // ===================================================================== 00399 // --------------------------------------------------------------------- 00400 // --------------------------------------------------------------------- 00401 // ===================================================================== 00402 /* 00403 \fn EstimateModelParameters 00404 \param ap_ImageS : pointer to the ImageSpace 00405 \param a_ite : index of the actual iteration (not used) 00406 \param a_sset : index of the actual subset (not used) 00407 \brief Estimate Patlak parametric images 00408 \return 0 if success, other value otherwise. 00409 */ 00410 int iPatlakModel::EstimateModelParameters(oImageSpace* ap_ImageS, int a_ite, int a_sset) 00411 { 00412 if(m_verbose >=2) Cout("iPatlakModel::EstimateModelParameters ..." <<endl); 00413 00414 #ifdef CASTOR_DEBUG 00415 if (!m_initialized) 00416 { 00417 Cerr("***** iPatlakModel::EstimateModelParameters() -> Called while not initialized !" << endl); 00418 Exit(EXIT_DEBUG); 00419 } 00420 #endif 00421 00422 // Generate estimated image from coefficients and basis functions 00423 // (We use the backward image which is useless at this point, as temporary image 00424 // to estimate the image generated using the current estimation of the Patlak parametric images) 00425 for (int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00426 for (int rg=0 ; rg<mp_ID->GetNbRespGates() ; rg++) 00427 for (int cg=0 ; cg<mp_ID->GetNbCardGates() ; cg++) 00428 for (int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00429 { 00430 // Reset this voxel to 0 00431 ap_ImageS->m6p_backwardImage[0][0][fr][rg][cg][v] = 0; 00432 00433 // Retrieve current estimation of image according to the current value of Patlak parametric images and basis functions 00434 // C(fr,v) = Patlak Parametric(v) * normalized time(fr) + 00435 // Patlak Intercept(v) * Reference tissue TAC(fr) 00436 for (int b=0 ; b<m_nbTimeBF ; b++) 00437 ap_ImageS->m6p_backwardImage[0][0][fr][rg][cg][v] += m2p_patlakTACs[b][fr] * m2p_parametricImages[b][v]; 00438 } 00439 00440 // Get correction images using the ratio of the current estimation of the image (m4p_image) 00441 // and the image generated with the combination of Patlak functions and parametric images (stored in ap_Image->m6p_backwardImage) 00442 // (Again, use backward image as temporary image to get the result) 00443 for (int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00444 for (int rg=0 ; rg<mp_ID->GetNbRespGates() ; rg++) 00445 for (int cg=0 ; cg<mp_ID->GetNbCardGates() ; cg++) 00446 for (int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00447 ap_ImageS->m6p_backwardImage[0][0][fr][rg][cg][v] = ap_ImageS->m4p_image[fr][rg][cg][v] / ap_ImageS->m6p_backwardImage[0][0][fr][rg][cg][v]; 00448 00449 00450 // Loop on the 2 Patlak parametric images 00451 for (int b=0 ; b<m_nbTimeBF ; b++) 00452 { 00453 double temporal_basis_functions_norm = 0; 00454 00455 // Compute normalization related to the temporal basis functions. 00456 for (int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00457 temporal_basis_functions_norm += m2p_patlakTACs[b][fr]; 00458 00459 // Compute voxelwise corrections for the parametric images 00460 int v; 00461 #pragma omp parallel for private(v) schedule(guided) 00462 for (v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00463 { 00464 double corr_factor = 0.; 00465 00466 // Note : We don't consider here parametric images specific to respiratory (rg) or cardiac gates (cg) 00467 // The model is applied to every voxels in the image 00468 for (int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00469 for (int rg=0 ; rg<mp_ID->GetNbRespGates() ; rg++) 00470 for (int cg=0 ; cg<mp_ID->GetNbCardGates() ; cg++) 00471 corr_factor += ap_ImageS->m6p_backwardImage[0][0][fr][rg][cg][v] * m2p_patlakTACs[b][fr]; 00472 00473 // Apply corrections and normalization to the vowelwise time basis functions coefficients. 00474 if (corr_factor > 0.) 00475 m2p_parametricImages[b][v] *= corr_factor/temporal_basis_functions_norm; 00476 } 00477 } 00478 00479 return 0; 00480 } 00481 00482 00483 00484 // ===================================================================== 00485 // --------------------------------------------------------------------- 00486 // --------------------------------------------------------------------- 00487 // ===================================================================== 00488 /* 00489 \fn FitModel 00490 \param ap_ImageS : pointer to the ImageSpace 00491 \param a_ite : index of the actual iteration (not used) 00492 \param a_sset : index of the actual subset (not used) 00493 \brief Estimate image using Patlak parametric images and basis functions 00494 \return 0 if success, other value otherwise. 00495 */ 00496 int iPatlakModel::FitModel(oImageSpace* ap_ImageS, int a_ite, int a_sset) 00497 { 00498 if(m_verbose >= 2) Cout("iPatlakModel::FitModel ... " <<endl); 00499 00500 #ifdef CASTOR_DEBUG 00501 if (!m_initialized) 00502 { 00503 Cerr("***** iPatlakModel::FitModel() -> Called while not initialized !" << endl); 00504 Exit(EXIT_DEBUG); 00505 } 00506 #endif 00507 00508 for (int fr=0 ; fr<mp_ID->GetNbTimeFrames() ; fr++) 00509 for (int rg=0 ; rg<mp_ID->GetNbRespGates() ; rg++) 00510 for (int cg=0 ; cg<mp_ID->GetNbCardGates() ; cg++) 00511 for (int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++) 00512 { 00513 // Reset current estimated value 00514 ap_ImageS->m4p_image[fr][rg][cg][v] = 0; 00515 00516 // C(fr,v) = Patlak Parametric(v) * normalized time(fr) + 00517 // Patlak Intercept(v) * Reference tissue TAC(fr) 00518 for (int b=0 ; b<m_nbTimeBF ; b++) 00519 ap_ImageS->m4p_image[fr][rg][cg][v] += m2p_parametricImages[b][v] * m2p_patlakTACs[b][fr]; 00520 } 00521 00522 return 0; 00523 } 00524 00525 00526 00527 00528 00529 // ===================================================================== 00530 // --------------------------------------------------------------------- 00531 // --------------------------------------------------------------------- 00532 // ===================================================================== 00533 /* 00534 \fn SaveParametricImages 00535 \param ap_ImageS : pointer to the ImageSpace 00536 \param a_ite : index of the actual iteration 00537 \brief Write parametric images on disk if 'm_savePImgFlag' is enabled 00538 \todo Interfile management 00539 \return 0 if success, other value otherwise. 00540 */ 00541 int iPatlakModel::SaveParametricImages(int a_ite) 00542 { 00543 if(m_verbose >=2) Cout("iPatlakModel::SaveParametricImages ..." <<endl); 00544 00545 if(m_savePImgFlag) 00546 { 00547 // Get the output manager 00548 sOutputManager* p_output_manager = sOutputManager::GetInstance(); 00549 /* 00550 for(int bimg=0 ; bimg<m_nbTimeBF ; bimg++) 00551 { 00552 string data_file = p_output_manager->GetPathName() + p_output_manager->GetBaseName(); 00553 if (a_ite >= 0) // Add a suffix for iteration 00554 { 00555 stringstream ss; 00556 ss << a_ite; 00557 data_file.append("_ite_").append(ss.str()); 00558 } 00559 00560 // Add a suffix for (basis functions) coefficients images 00561 stringstream ss; 00562 ss << bimg; 00563 data_file.append("_fbimg_").append(ss.str()).append(".bin"); 00564 00565 ofstream out_dfile; 00566 00567 out_dfile.open(data_file.c_str(), ios::binary | ios::out); 00568 00569 if(!out_dfile.is_open()) 00570 { 00571 cout<<"***** iPatlakModel::SaveCoeffImages()->Failed to create output file for the dynamic image : "<< data_file.c_str() << endl; 00572 return 1; 00573 } 00574 00575 out_dfile.write(reinterpret_cast<char*>(m2p_parametricImages[bimg]), mp_ID->GetNbVoxXYZ()*sizeof(FLTNB)); 00576 out_dfile.close(); 00577 } 00578 */ 00579 00580 // Interfile 00581 string path_to_image = p_output_manager->GetPathName() + p_output_manager->GetBaseName(); 00582 00583 // Add a suffix for iteration 00584 if (a_ite >= 0) 00585 { 00586 stringstream ss; ss << a_ite + 1; 00587 path_to_image.append("patlak_it").append(ss.str()); 00588 } 00589 00590 // Write interfile parametric image 00591 if(IntfWriteImgDynCoeffFile(path_to_image, 00592 m2p_parametricImages, 00593 mp_ID, 00594 m_nbTimeBF, 00595 m_verbose) ) 00596 { 00597 Cerr("***** iPatlakModel::SaveParametricImages()-> Error writing Interfile of output image !" << endl); 00598 return 1; 00599 } 00600 00601 } 00602 00603 return 0; 00604 } 00605 00606