CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
oImageProcessingManager.cc
Go to the documentation of this file.
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 // =====================================================================
 All Classes Files Functions Variables Typedefs Defines