![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
00001 00002 /* 00003 Implementation of class oImageProcessingManager 00004 00005 - separators: done 00006 - doxygen: done 00007 - default initialization: done 00008 - CASTOR_DEBUG: 00009 - CASTOR_VERBOSE: 00010 */ 00011 00018 #include "oImageProcessingManager.hh" 00019 #include "sAddonManager.hh" 00020 00021 // ===================================================================== 00022 // --------------------------------------------------------------------- 00023 // --------------------------------------------------------------------- 00024 // ===================================================================== 00025 00026 oImageProcessingManager::oImageProcessingManager() 00027 { 00028 // Image dimensions 00029 mp_ImageDimensionsAndQuantification = NULL; 00030 // Options 00031 m_options = {}; 00032 // Image processing objects and associated bool 00033 m_nbImageProcessingModules = 0; 00034 m2p_ImageProcessingModules = NULL; 00035 mp_applyForward = NULL; 00036 mp_applyIntra = NULL; 00037 mp_applyPost = NULL; 00038 // Booleans 00039 m_checked = false; 00040 m_initialized = false; 00041 // Verbosity 00042 m_verbose = -1; 00043 } 00044 00045 // ===================================================================== 00046 // --------------------------------------------------------------------- 00047 // --------------------------------------------------------------------- 00048 // ===================================================================== 00049 00050 oImageProcessingManager::~oImageProcessingManager() 00051 { 00052 // Delete object 00053 if (m2p_ImageProcessingModules) 00054 { 00055 for (int c=0; c<m_nbImageProcessingModules; c++) if (m2p_ImageProcessingModules[c]) delete m2p_ImageProcessingModules[c]; 00056 free(m2p_ImageProcessingModules); 00057 } 00058 } 00059 00060 // ===================================================================== 00061 // --------------------------------------------------------------------- 00062 // --------------------------------------------------------------------- 00063 // ===================================================================== 00064 00065 int oImageProcessingManager::CheckParameters() 00066 { 00067 // Check image dimensions 00068 if (mp_ImageDimensionsAndQuantification==NULL) 00069 { 00070 Cerr("***** oImageProcessingManager::CheckParameters() -> No image dimensions provided !" << endl); 00071 return 1; 00072 } 00073 // Check verbosity 00074 if (m_verbose<0) 00075 { 00076 Cerr("***** oImageProcessingManager::CheckParameters() -> Wrong verbosity level provided !" << endl); 00077 return 1; 00078 } 00079 // All set 00080 m_checked = true; 00081 // Normal end 00082 return 0; 00083 } 00084 00085 // ===================================================================== 00086 // --------------------------------------------------------------------- 00087 // --------------------------------------------------------------------- 00088 // ===================================================================== 00089 00090 void oImageProcessingManager::ShowCommonHelp() 00091 { 00092 // Return when using MPI and mpi_rank is not 0 00093 #ifdef CASTOR_MPI 00094 int mpi_rank = 0; 00095 MPI_Comm_rank(MPI_COMM_WORLD, &mpi_rank); 00096 if (mpi_rank!=0) return; 00097 #endif 00098 // Show help 00099 cout << "------------------------------------------------------------------" << endl; 00100 cout << "----- How to use an image processing module" << endl; 00101 cout << "------------------------------------------------------------------" << endl; 00102 cout << endl; 00103 cout << "An image processing module is called through the -proc option. The provided argument describes the processing module to be used," << endl; 00104 cout << "its options, and when to include it within the algorithm. The syntax of the argument must obey one of the three following options:" << endl; 00105 cout << " proc::when (in this case, the default configuration file of the processing module is used to set the options values)" << endl; 00106 cout << " proc:file.conf::when (in this case, the provided configuration is used)" << endl; 00107 cout << " proc,param1,param2,...::when (in this case, the options values are directly provided in the argument)" << endl; 00108 cout << "In any case, the description of the options specific to each processing module, their order in the list and their configuration" << endl; 00109 cout << "files syntax are provided in the specific help of each module." << endl; 00110 cout << "The 'when' parameter is an argument describing when to include the processing module within the algorithm. It is a list of keywords" << endl; 00111 cout << "separating by commas. The following keywords can be used:" << endl; 00112 cout << " forward (include module into forward model; the processed current estimate is forward-projected)" << endl; 00113 cout << " post (apply module before saving the image; the processed image is not put back as the estimate for the next update)" << endl; 00114 cout << " intra (apply module to the updated image use it as the current estimate for the next update)" << endl; 00115 cout << endl; 00116 } 00117 00118 // ===================================================================== 00119 // --------------------------------------------------------------------- 00120 // --------------------------------------------------------------------- 00121 // ===================================================================== 00122 00123 int oImageProcessingManager::Initialize() 00124 { 00125 // Check if parameters have been checked 00126 if (!m_checked) 00127 { 00128 Cerr("***** oImageProcessingManager::Initialize() -> Parameters have not been checked ! Please call CheckParameters() before." << endl); 00129 return 1; 00130 } 00131 // Case with no options (no image processing module) 00132 if (m_options.size()==0) 00133 { 00134 m_initialized = true; 00135 return 0; 00136 } 00137 // Verbose 00138 if (m_verbose>=1) Cout("oImageProcessingManager::Initialize() -> Initialize image processing modules" << endl); 00139 // Parse image processing modules options and initialize them 00140 if (ParseOptionsAndInitializeImageProcessingModules()) 00141 { 00142 Cerr("***** oImageProcessingManager::Initialize() -> A problem occured while parsing image processing modules options and initializing them !" << endl); 00143 return 1; 00144 } 00145 // All set 00146 m_initialized = true; 00147 // Normal end 00148 return 0; 00149 } 00150 00151 // ===================================================================== 00152 // --------------------------------------------------------------------- 00153 // --------------------------------------------------------------------- 00154 // ===================================================================== 00155 00156 int oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() 00157 { 00158 // =================================================================== 00159 // First get the number of processing modules from the list of options 00160 // =================================================================== 00161 00162 m_nbImageProcessingModules = m_options.size(); 00163 00164 // Allocate the tables 00165 m2p_ImageProcessingModules = (vImageProcessingModule**)malloc(m_nbImageProcessingModules*sizeof(vImageProcessingModule*)); 00166 mp_applyForward = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool)); 00167 mp_applyIntra = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool)); 00168 mp_applyPost = (bool*)malloc(m_nbImageProcessingModules*sizeof(bool)); 00169 00170 // =================================================================== 00171 // Then we loop over all modules, read options and initialize them 00172 // =================================================================== 00173 00174 // This is for the automatic initialization of the processing modules 00175 typedef vImageProcessingModule *(*maker_image_processing_module) (); 00176 // Get image processing modules list from addon manager 00177 std::map <string,maker_image_processing_module> list = sAddonManager::GetInstance()->mp_listOfImageProcessingModules; 00178 00179 // Start the loop 00180 for (int c=0; c<m_nbImageProcessingModules; c++) 00181 { 00182 // Default initializations 00183 m2p_ImageProcessingModules[c] = NULL; 00184 mp_applyForward[c] = false; 00185 mp_applyIntra[c] = false; 00186 mp_applyPost[c] = false; 00187 00188 // ___________________________________________________________________________________ 00189 // Search for a double-colon and isolate the module's options from the 'when' actions 00190 00191 size_t double_colon = m_options[c].find_first_of("::"); 00192 00193 // Send an error if no double-colon 00194 if (double_colon==string::npos) 00195 { 00196 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Wrong syntax in the " << c+1 << "th image processing module !" << endl); 00197 Cerr(" No double-colon \"::\" found." << endl); 00198 ShowCommonHelp(); 00199 return 1; 00200 } 00201 00202 // Separate the two arguments 00203 string proc_part_options = m_options[c].substr(0,double_colon); 00204 string when_part_options = m_options[c].substr(double_colon+2); 00205 00206 // ___________________________________________________________________________________ 00207 // Get the module name in the options and isolate the actual module's options 00208 00209 // Useful strings 00210 string module = ""; 00211 string list_options = ""; 00212 string file_options = ""; 00213 00214 // Search for a colon ":", this indicates that a configuration file is provided after the module's name 00215 size_t colon = proc_part_options.find_first_of(":"); 00216 size_t comma = proc_part_options.find_first_of(","); 00217 00218 // Case 1: we have a colon 00219 if (colon!=string::npos) 00220 { 00221 // Get the image processing module name before the colon 00222 module = proc_part_options.substr(0,colon); 00223 // Get the configuration file after the colon 00224 file_options = proc_part_options.substr(colon+1); 00225 // List of options is empty 00226 list_options = ""; 00227 } 00228 // Case 2: we have a comma 00229 else if (comma!=string::npos) 00230 { 00231 // Get the image processing module name before the first comma 00232 module = proc_part_options.substr(0,comma); 00233 // Get the list of options after the first comma 00234 list_options = proc_part_options.substr(comma+1); 00235 // Configuration file is empty 00236 file_options = ""; 00237 } 00238 // Case 3: no colon and no comma (a single image processing module name) 00239 else 00240 { 00241 // Get the image processing module name 00242 module = proc_part_options; 00243 // List of options is empty 00244 list_options = ""; 00245 // Build the default configuration file 00246 file_options = sOutputManager::GetInstance()->GetPathToConfigDir() + "/processing/" + module + ".conf"; 00247 } 00248 00249 // ___________________________________________________________________________________ 00250 // Read the 'when' actions 00251 00252 // Loop while commas are found 00253 while ((comma=when_part_options.find_first_of(",")) != string::npos) 00254 { 00255 // Extract the first option 00256 string option = when_part_options.substr(0,comma); 00257 // Extract the rest 00258 when_part_options = when_part_options.substr(comma+1); 00259 // Check the meaning of the option 00260 if (option=="forward") {mp_applyForward[c] = true;} 00261 else if (option=="post") {mp_applyPost[c] = true;} 00262 else if (option=="intra") {mp_applyIntra[c] = true;} 00263 else 00264 { 00265 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << option << "' provided in options list !" << endl); 00266 ShowCommonHelp(); 00267 return 1; 00268 } 00269 } 00270 // Last option 00271 if (when_part_options=="forward") {mp_applyForward[c] = true;} 00272 else if (when_part_options=="post") {mp_applyPost[c] = true;} 00273 else if (when_part_options=="intra") {mp_applyIntra[c] = true;} 00274 else 00275 { 00276 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Unknown keyword '" << when_part_options << "' provided in options list !" << endl); 00277 ShowCommonHelp(); 00278 return 1; 00279 } 00280 00281 // ______________________________________________________________________________ 00282 // Create processing module and call associated functions 00283 00284 // Create the image processing module 00285 if (list[module]) m2p_ImageProcessingModules[c] = list[module](); 00286 else 00287 { 00288 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Image processing module '" << module << "' does not exist !" << endl); 00289 sAddonManager::GetInstance()->ShowHelpImageProcessingModule(); 00290 return 1; 00291 } 00292 // Set parameters 00293 m2p_ImageProcessingModules[c]->SetImageDimensionsAndQuantification(mp_ImageDimensionsAndQuantification); 00294 m2p_ImageProcessingModules[c]->SetVerbose(m_verbose); 00295 // Provide configuration file if any 00296 if (file_options!="" && m2p_ImageProcessingModules[c]->ReadConfigurationFile(file_options)) 00297 { 00298 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while reading and checking configuration file for image processing module '" << module << "' !" << endl); 00299 return 1; 00300 } 00301 // Provide options if any 00302 if (list_options!="" && m2p_ImageProcessingModules[c]->ReadOptionsList(list_options)) 00303 { 00304 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while parsing and reading options list for image processing module '" << module << "' !" << endl); 00305 return 1; 00306 } 00307 // Check parameters 00308 if (m2p_ImageProcessingModules[c]->CheckParameters()) 00309 { 00310 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while checking parameters for image processing module '" << module << "' !" << endl); 00311 return 1; 00312 } 00313 // Initialize the image processing module 00314 if (m2p_ImageProcessingModules[c]->Initialize()) 00315 { 00316 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> A problem occured while initializing image processing module '" << module << "' !" << endl); 00317 return 1; 00318 } 00319 // Check if processing module is dynamic and if dynamic basis functions are used, then it is not compatible if used inside the reconstruction (all but 'post') 00320 bool intra_reconstruction = mp_applyForward[c] || mp_applyIntra[c]; 00321 bool condition1 = m2p_ImageProcessingModules[c]->GetAffectTimeDimensionFlag() && !mp_ImageDimensionsAndQuantification->GetTimeStaticFlag(); 00322 bool condition2 = m2p_ImageProcessingModules[c]->GetAffectRespDimensionFlag() && !mp_ImageDimensionsAndQuantification->GetRespStaticFlag(); 00323 bool condition3 = m2p_ImageProcessingModules[c]->GetAffectCardDimensionFlag() && !mp_ImageDimensionsAndQuantification->GetCardStaticFlag(); 00324 if (intra_reconstruction && (condition1 || condition2 || condition3)) 00325 { 00326 Cerr("***** oImageProcessingManager::ParseOptionsAndInitializeImageProcessingModules() -> Cannot use dynamic image processing module '" << module << "' along with dynamic basis functions inside the reconstruction !" << endl); 00327 return 1; 00328 } 00329 } 00330 00331 // Normal end 00332 return 0; 00333 } 00334 00335 // ===================================================================== 00336 // --------------------------------------------------------------------- 00337 // --------------------------------------------------------------------- 00338 // ===================================================================== 00339 00340 int oImageProcessingManager::ApplyProcessingForward(oImageSpace* ap_ImageSpace) 00341 { 00342 #ifdef CASTOR_DEBUG 00343 // Check if initialized 00344 if (!m_initialized) 00345 { 00346 Cerr("***** oImageProcessingManager::ApplyProcessingForward() -> Called while not initialized !" << endl); 00347 return 1; 00348 } 00349 #endif 00350 // Loop on processing modules 00351 for (int c=0; c<m_nbImageProcessingModules; c++) 00352 { 00353 // Apply it only if asked for 00354 if (mp_applyForward[c]) 00355 { 00356 // Verbose 00357 if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingForward() -> Apply image processing module " << c+1 << " to forward image" << endl); 00358 // Get the pointer to the image 00359 FLTNB**** image = ap_ImageSpace->m4p_forwardImage; 00360 // Apply convolution 00361 m2p_ImageProcessingModules[c]->Process(image); 00362 } 00363 } 00364 // Normal end 00365 return 0; 00366 } 00367 00368 // ===================================================================== 00369 // --------------------------------------------------------------------- 00370 // --------------------------------------------------------------------- 00371 // ===================================================================== 00372 00373 int oImageProcessingManager::ApplyProcessingIntra(oImageSpace* ap_ImageSpace) 00374 { 00375 #ifdef CASTOR_DEBUG 00376 // Check if initialized 00377 if (!m_initialized) 00378 { 00379 Cerr("***** oImageProcessingManager::ApplyProcessingIntra() -> Called while not initialized !" << endl); 00380 return 1; 00381 } 00382 #endif 00383 // Loop on processing modules 00384 for (int c=0; c<m_nbImageProcessingModules; c++) 00385 { 00386 // Apply it only if asked for 00387 if (mp_applyIntra[c]) 00388 { 00389 // Verbose 00390 if (m_verbose>=2) Cout("oImageProcessingrManager::ApplyProcessingIntra() -> Apply image processing module " << c+1 << " to current image" << endl); 00391 // Get the pointer to the image 00392 FLTNB**** image = ap_ImageSpace->m4p_image; 00393 // Apply processing module 00394 m2p_ImageProcessingModules[c]->Process(image); 00395 } 00396 } 00397 // Normal end 00398 return 0; 00399 } 00400 00401 // ===================================================================== 00402 // --------------------------------------------------------------------- 00403 // --------------------------------------------------------------------- 00404 // ===================================================================== 00405 00406 int oImageProcessingManager::ApplyProcessingPost(oImageSpace* ap_ImageSpace) 00407 { 00408 #ifdef CASTOR_DEBUG 00409 // Check if initialized 00410 if (!m_initialized) 00411 { 00412 Cerr("***** oImageProcessingManager::ApplyProcessingPost() -> Called while not initialized !" << endl); 00413 return 1; 00414 } 00415 #endif 00416 // Loop on processing modules 00417 for (int c=0; c<m_nbImageProcessingModules; c++) 00418 { 00419 // Apply it only if asked for 00420 if (mp_applyPost[c]) 00421 { 00422 // Verbose 00423 if (m_verbose>=2) Cout("oImageProcessingManager::ApplyProcessingPost() -> Apply image processing module " << c+1 << " to output image" << endl); 00424 // Get the pointer to the output image 00425 FLTNB**** image = ap_ImageSpace->m4p_outputImage; 00426 // Apply processing module 00427 m2p_ImageProcessingModules[c]->Process(image); 00428 } 00429 } 00430 // Normal end 00431 return 0; 00432 } 00433 00434 // ===================================================================== 00435 // --------------------------------------------------------------------- 00436 // --------------------------------------------------------------------- 00437 // =====================================================================