![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
00001 00002 /* 00003 Implementation of class vOptimizer 00004 00005 - separators: X 00006 - doxygen: 00007 - default initialization: X 00008 - CASTOR_DEBUG: 00009 - CASTOR_VERBOSE: 00010 */ 00011 00018 #include "vOptimizer.hh" 00019 00020 // ===================================================================== 00021 // --------------------------------------------------------------------- 00022 // --------------------------------------------------------------------- 00023 // ===================================================================== 00024 00025 vOptimizer::vOptimizer() 00026 { 00027 // Affect default values 00028 mp_ImageDimensionsAndQuantification = NULL; 00029 m_nbBackwardImages = 0; 00030 m_nbTOFBins = 0; 00031 m_initialValue = 0.; 00032 m_listmodeCompatibility = false; 00033 m_histogramCompatibility = false; 00034 m2p_forwardValues = NULL; 00035 m3p_backwardValues = NULL; 00036 m_dataMode = MODE_UNKNOWN; 00037 m_dataType = TYPE_UNKNOWN; 00038 m_optimizerFOMFlag = false; 00039 m_optimizerImageStatFlag = false; 00040 m4p_FOMLogLikelihood = NULL; 00041 m4p_FOMNbBins = NULL; 00042 m4p_FOMRMSE = NULL; 00043 m4p_FOMNbData = NULL; 00044 m_verbose = 0; 00045 m2p_attenuationImage = NULL; 00046 mp_imageStatNbVox = NULL; 00047 mp_imageStatMin = NULL; 00048 mp_imageStatMax = NULL; 00049 mp_imageStatMean = NULL; 00050 mp_imageStatVariance = NULL; 00051 mp_correctionStatMean = NULL; 00052 mp_correctionStatVariance = NULL; 00053 //m_penaltyEnergyFunctionDerivativesOrder = 0; 00054 } 00055 00056 // ===================================================================== 00057 // --------------------------------------------------------------------- 00058 // --------------------------------------------------------------------- 00059 // ===================================================================== 00060 00061 vOptimizer::~vOptimizer() 00062 { 00063 // Free forward and backward buffers 00064 if (m2p_forwardValues) 00065 { 00066 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(); th++) 00067 if (m2p_forwardValues[th]) free(m2p_forwardValues[th]); 00068 free(m2p_forwardValues); 00069 } 00070 if (m3p_backwardValues) 00071 { 00072 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsMax(); th++) 00073 { 00074 if (m3p_backwardValues[th]) 00075 { 00076 for (int tof=0; tof<m_nbTOFBins; tof++) if (m3p_backwardValues[th][tof]) free(m3p_backwardValues[th][tof]); 00077 free(m3p_backwardValues[th]); 00078 } 00079 } 00080 free(m3p_backwardValues); 00081 } 00082 // Free pointers to attenuation images for SPECT 00083 if (m2p_attenuationImage) free(m2p_attenuationImage); 00084 // Delete all image update statistics tables 00085 if (m_optimizerImageStatFlag) 00086 { 00087 if (mp_imageStatNbVox) free(mp_imageStatNbVox); 00088 if (mp_imageStatMin) free(mp_imageStatMin); 00089 if (mp_imageStatMax) free(mp_imageStatMax); 00090 if (mp_imageStatMean) free(mp_imageStatMean); 00091 if (mp_imageStatVariance) free(mp_imageStatVariance); 00092 if (mp_correctionStatMean) free(mp_correctionStatMean); 00093 if (mp_correctionStatVariance) free(mp_correctionStatVariance); 00094 } 00095 // Delete FOM tables 00096 if (m_optimizerFOMFlag) 00097 { 00098 // Delete the log-likelihood table 00099 if (m4p_FOMLogLikelihood) 00100 { 00101 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00102 { 00103 if (m4p_FOMLogLikelihood[fr]) 00104 { 00105 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00106 { 00107 if (m4p_FOMLogLikelihood[fr][rg]) 00108 { 00109 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00110 if (m4p_FOMLogLikelihood[fr][rg][cg]) free(m4p_FOMLogLikelihood[fr][rg][cg]); 00111 free(m4p_FOMLogLikelihood[fr][rg]); 00112 } 00113 } 00114 free(m4p_FOMLogLikelihood[fr]); 00115 } 00116 } 00117 free(m4p_FOMLogLikelihood); 00118 } 00119 // Delete the RMSE table 00120 if (m4p_FOMRMSE) 00121 { 00122 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00123 { 00124 if (m4p_FOMRMSE[fr]) 00125 { 00126 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00127 { 00128 if (m4p_FOMRMSE[fr][rg]) 00129 { 00130 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00131 if (m4p_FOMRMSE[fr][rg][cg]) free(m4p_FOMRMSE[fr][rg][cg]); 00132 free(m4p_FOMRMSE[fr][rg]); 00133 } 00134 } 00135 free(m4p_FOMRMSE[fr]); 00136 } 00137 } 00138 free(m4p_FOMRMSE); 00139 } 00140 // Delete the nbBins table 00141 if (m4p_FOMNbBins) 00142 { 00143 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00144 { 00145 if (m4p_FOMNbBins[fr]) 00146 { 00147 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00148 { 00149 if (m4p_FOMNbBins[fr][rg]) 00150 { 00151 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00152 if (m4p_FOMNbBins[fr][rg][cg]) free(m4p_FOMNbBins[fr][rg][cg]); 00153 free(m4p_FOMNbBins[fr][rg]); 00154 } 00155 } 00156 free(m4p_FOMNbBins[fr]); 00157 } 00158 } 00159 free(m4p_FOMNbBins); 00160 } 00161 // Delete the nbData table 00162 if (m4p_FOMNbData) 00163 { 00164 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00165 { 00166 if (m4p_FOMNbData[fr]) 00167 { 00168 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00169 { 00170 if (m4p_FOMNbData[fr][rg]) 00171 { 00172 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00173 if (m4p_FOMNbData[fr][rg][cg]) free(m4p_FOMNbData[fr][rg][cg]); 00174 free(m4p_FOMNbData[fr][rg]); 00175 } 00176 } 00177 free(m4p_FOMNbData[fr]); 00178 } 00179 } 00180 free(m4p_FOMNbData); 00181 } 00182 } 00183 } 00184 00185 // ===================================================================== 00186 // --------------------------------------------------------------------- 00187 // --------------------------------------------------------------------- 00188 // ===================================================================== 00189 00190 void vOptimizer::ShowHelp() 00191 { 00192 // Call the specific help function from the children 00193 ShowHelpSpecific(); 00194 // Then, say if the child optimizer is compatible with histogram and/or list-mode data 00195 if (m_listmodeCompatibility && m_histogramCompatibility) cout << "This optimizer is compatible with both histogram and list-mode data." << endl; 00196 else if (m_listmodeCompatibility) cout << "This optimizer is only compatible with list-mode data." << endl; 00197 else if (m_histogramCompatibility) cout << "This optimizer is only compatible with histogram data." << endl; 00198 else cout << "This optimizer is a total non-sense, not compatible with histogram nor list-mode data !!!" << endl; 00199 } 00200 00201 // ===================================================================== 00202 // --------------------------------------------------------------------- 00203 // --------------------------------------------------------------------- 00204 // ===================================================================== 00205 00206 int vOptimizer::CheckParameters() 00207 { 00208 // Check image dimensions 00209 if (mp_ImageDimensionsAndQuantification==NULL) 00210 { 00211 Cerr("***** vOptimizer::CheckParameters() -> oImageDimensionsAndQuantification is null !" << endl); 00212 return 1; 00213 } 00214 // Check data mode 00215 if (m_dataMode==MODE_UNKNOWN || (m_dataMode!=MODE_LIST && m_dataMode!=MODE_HISTOGRAM)) 00216 { 00217 Cerr("***** vOptimizer::CheckParameters() -> No or meaningless data mode provided !" << endl); 00218 return 1; 00219 } 00220 // Check data type 00221 if (m_dataType==TYPE_UNKNOWN || (m_dataType!=TYPE_PET && m_dataType!=TYPE_SPECT && m_dataType!=TYPE_TRANSMISSION)) 00222 { 00223 Cerr("***** vOptimizer::CheckParameters() -> No or meaningless data type provided !" << endl); 00224 return 1; 00225 } 00226 // Check verbose level 00227 if (m_verbose<0) 00228 { 00229 Cerr("***** vOptimizer::CheckParameters() -> Verbose level is negative !" << endl); 00230 return 1; 00231 } 00232 // Listmode incompatibility 00233 if (m_dataMode==MODE_LIST && !m_listmodeCompatibility) 00234 { 00235 Cerr("***** vOptimizer::CheckParameters() -> The selected optimizer is not compatible with listmode data !" << endl); 00236 return 1; 00237 } 00238 // Histogram incompatibility 00239 if (m_dataMode==MODE_HISTOGRAM && !m_histogramCompatibility) 00240 { 00241 Cerr("***** vOptimizer::CheckParameters() -> The selected optimizer is not compatible with histogram data !" << endl); 00242 return 1; 00243 } 00244 // Send an error if FOM computation is required and verbose is null 00245 if (m_optimizerFOMFlag && m_verbose==0) 00246 { 00247 Cerr("***** vOptimizer::CheckParameters() -> Asked to compute FOMs in the data-space whereas the verbose is not set !" << endl); 00248 return 1; 00249 } 00250 // Send an error if image statistics computation is required and verbose is null 00251 if (m_optimizerImageStatFlag && m_verbose==0) 00252 { 00253 Cerr("***** vOptimizer::CheckParameters() -> Asked to compute image update statistics whereas the verbose is not set !" << endl); 00254 return 1; 00255 } 00256 // Send an error if FOM computation with list-mode data (it has no sense) 00257 if (m_optimizerFOMFlag && m_dataMode==MODE_LIST) 00258 { 00259 Cerr("***** vOptimizer::CheckParameters() -> Computing FOMs in the data-space with list-mode data is not possible !" << endl); 00260 return 1; 00261 } 00262 // Call the CheckSpecificParameters function of the child 00263 if (CheckSpecificParameters()) 00264 { 00265 Cerr("***** vOptimizer::CheckParameters() -> A problem occured while checking parameters specific to the optimizer module !" << endl); 00266 return 1; 00267 } 00268 // Normal end 00269 return 0; 00270 } 00271 00272 // ===================================================================== 00273 // --------------------------------------------------------------------- 00274 // --------------------------------------------------------------------- 00275 // ===================================================================== 00276 00277 int vOptimizer::Initialize() 00278 { 00279 // Allocate forward buffers (as many as threads and as many as TOF bins) 00280 m2p_forwardValues = (FLTNB**)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(FLTNB*)); 00281 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(); th++) 00282 m2p_forwardValues[th] = (FLTNB*)malloc(m_nbTOFBins*sizeof(FLTNB)); 00283 00284 // Allocate backward buffers (as many as threads then as many as TOF bins and as many as backward images) 00285 m3p_backwardValues = (FLTNB***)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsMax()*sizeof(FLTNB**)); 00286 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsMax(); th++) 00287 { 00288 m3p_backwardValues[th] = (FLTNB**)malloc(m_nbTOFBins*sizeof(FLTNB*)); 00289 for (int tof=0; tof<m_nbTOFBins; tof++) 00290 m3p_backwardValues[th][tof] = (FLTNB*)malloc(m_nbBackwardImages*sizeof(FLTNB)); 00291 } 00292 00293 // Allocate pointers to the current attenuation image for SPECT attenuation correction 00294 m2p_attenuationImage = (FLTNB**)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(FLTNB*)); 00295 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(); th++) m2p_attenuationImage[th] = NULL; 00296 00297 // Allocate the thread-safe tables for image update statistics computation 00298 if (m_optimizerImageStatFlag) 00299 { 00300 mp_imageStatNbVox = (INTNB*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(INTNB)); 00301 mp_imageStatMin = (FLTNB*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(FLTNB)); 00302 mp_imageStatMax = (FLTNB*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(FLTNB)); 00303 mp_imageStatMean = (double*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(double)); 00304 mp_imageStatVariance = (double*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(double)); 00305 mp_correctionStatMean = (double*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(double)); 00306 mp_correctionStatVariance = (double*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()*sizeof(double)); 00307 } 00308 00309 // We allocate the tables that hold the figures-of-merit if FOM flag is on 00310 if (m_optimizerFOMFlag) 00311 { 00312 m4p_FOMNbBins = (uint64_t****)malloc(mp_ImageDimensionsAndQuantification->GetNbTimeFrames()*sizeof(uint64_t***)); 00313 m4p_FOMNbData = (double****)malloc(mp_ImageDimensionsAndQuantification->GetNbTimeFrames()*sizeof(double***)); 00314 m4p_FOMLogLikelihood = (FLTNB****)malloc(mp_ImageDimensionsAndQuantification->GetNbTimeFrames()*sizeof(FLTNB***)); 00315 m4p_FOMRMSE = (FLTNB****)malloc(mp_ImageDimensionsAndQuantification->GetNbTimeFrames()*sizeof(FLTNB***)); 00316 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00317 { 00318 m4p_FOMNbBins[fr] = (uint64_t***)malloc(mp_ImageDimensionsAndQuantification->GetNbRespGates()*sizeof(uint64_t**)); 00319 m4p_FOMNbData[fr] = (double***)malloc(mp_ImageDimensionsAndQuantification->GetNbRespGates()*sizeof(double**)); 00320 m4p_FOMLogLikelihood[fr] = (FLTNB***)malloc(mp_ImageDimensionsAndQuantification->GetNbRespGates()*sizeof(FLTNB**)); 00321 m4p_FOMRMSE[fr] = (FLTNB***)malloc(mp_ImageDimensionsAndQuantification->GetNbRespGates()*sizeof(FLTNB**)); 00322 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00323 { 00324 m4p_FOMNbBins[fr][rg] = (uint64_t**)malloc(mp_ImageDimensionsAndQuantification->GetNbCardGates()*sizeof(uint64_t*)); 00325 m4p_FOMNbData[fr][rg] = (double**)malloc(mp_ImageDimensionsAndQuantification->GetNbCardGates()*sizeof(double*)); 00326 m4p_FOMLogLikelihood[fr][rg] = (FLTNB**)malloc(mp_ImageDimensionsAndQuantification->GetNbCardGates()*sizeof(FLTNB*)); 00327 m4p_FOMRMSE[fr][rg] = (FLTNB**)malloc(mp_ImageDimensionsAndQuantification->GetNbCardGates()*sizeof(FLTNB*)); 00328 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00329 { 00330 m4p_FOMNbBins[fr][rg][cg] = (uint64_t*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(uint64_t)); 00331 m4p_FOMNbData[fr][rg][cg] = (double*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(double)); 00332 m4p_FOMLogLikelihood[fr][rg][cg] = (FLTNB*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(FLTNB)); 00333 m4p_FOMRMSE[fr][rg][cg] = (FLTNB*)malloc(mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection()*sizeof(FLTNB)); 00334 } 00335 } 00336 } 00337 } 00338 00339 // Call the specific initialization function of the child 00340 if (InitializeSpecific()) 00341 { 00342 Cerr("***** vOptimizer::Initialize() -> A problem occured while initializing stuff specific to the optimizer module !" << endl); 00343 return 1; 00344 } 00345 00346 // Normal end 00347 return 0; 00348 } 00349 00350 // ===================================================================== 00351 // --------------------------------------------------------------------- 00352 // --------------------------------------------------------------------- 00353 // ===================================================================== 00354 00355 int vOptimizer::PreDataUpdateStep(int a_iteration, int a_nbIterations, int a_subset, int a_nbSubsets) 00356 { 00357 // Simply reset FOMs if activated 00358 if (m_optimizerFOMFlag) 00359 { 00360 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00361 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00362 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00363 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(); th++) 00364 { 00365 m4p_FOMNbBins[fr][rg][cg][th] = 0; 00366 m4p_FOMNbData[fr][rg][cg][th] = 0.; 00367 m4p_FOMLogLikelihood[fr][rg][cg][th] = 0.; 00368 m4p_FOMRMSE[fr][rg][cg][th] = 0.; 00369 } 00370 } 00371 // Then call the specific pre-update-step function from the child optimizer 00372 if (PreDataUpdateSpecificStep(a_iteration, a_nbIterations, a_subset, a_nbSubsets)) 00373 { 00374 Cerr("***** vOptimizer::PreDataUpdateStep() -> A problem occured while applying the specific pre-data-update step of the optimizer module !" << endl); 00375 return 1; 00376 } 00377 // Normal end 00378 return 0; 00379 } 00380 00381 // ===================================================================== 00382 // --------------------------------------------------------------------- 00383 // --------------------------------------------------------------------- 00384 // ===================================================================== 00385 00386 int vOptimizer::PreDataUpdateSpecificStep(int a_iteration, int a_nbIterations, int a_subset, int a_nbSubsets) 00387 { 00388 // By default, just do nothing here. This function is designed to be overloaded by the specific optimizer if needed 00389 return 0; 00390 } 00391 00392 // ===================================================================== 00393 // --------------------------------------------------------------------- 00394 // --------------------------------------------------------------------- 00395 // ===================================================================== 00396 00397 int vOptimizer::PostDataUpdateStep(int a_iteration, int a_nbIterations, int a_subset, int a_nbSubsets) 00398 { 00399 // Print out the FOMs if activated 00400 if (m_optimizerFOMFlag) 00401 { 00402 // Verbose 00403 Cout("vOptimizer::PostDataUpdateStep() -> Data-space figures-of-merit" << endl); 00404 // Number of spaces for printing 00405 string spaces_fr = ""; if (mp_ImageDimensionsAndQuantification->GetNbTimeFrames()>1) spaces_fr += " "; 00406 string spaces_rg = ""; if (mp_ImageDimensionsAndQuantification->GetNbRespGates()>1) spaces_rg += " "; 00407 string spaces_cg = ""; if (mp_ImageDimensionsAndQuantification->GetNbCardGates()>1) spaces_cg += " "; 00408 // Loop on frames and gates 00409 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00410 { 00411 // Verbose 00412 if (mp_ImageDimensionsAndQuantification->GetNbTimeFrames()>1) 00413 Cout(spaces_fr << "Frame " << fr+1 << " on " << mp_ImageDimensionsAndQuantification->GetNbTimeFrames() << endl); 00414 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00415 { 00416 // Verbose 00417 if (mp_ImageDimensionsAndQuantification->GetNbRespGates()>1) 00418 Cout(spaces_fr << spaces_rg << "Respiratory gate " << rg+1 << " on " << mp_ImageDimensionsAndQuantification->GetNbRespGates() << endl); 00419 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00420 { 00421 // Verbose 00422 if (mp_ImageDimensionsAndQuantification->GetNbCardGates()>1) 00423 Cout(spaces_fr << spaces_rg << spaces_cg << "Cardiac gate " << cg+1 << " on " << mp_ImageDimensionsAndQuantification->GetNbCardGates() << endl); 00424 // Merge thread results 00425 for (int th=1; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForProjection(); th++) 00426 { 00427 m4p_FOMNbBins[fr][rg][cg][0] += m4p_FOMNbBins[fr][rg][cg][th]; 00428 m4p_FOMNbData[fr][rg][cg][0] += m4p_FOMNbData[fr][rg][cg][th]; 00429 m4p_FOMLogLikelihood[fr][rg][cg][0] += m4p_FOMLogLikelihood[fr][rg][cg][th]; 00430 m4p_FOMRMSE[fr][rg][cg][0] += m4p_FOMRMSE[fr][rg][cg][th]; 00431 } 00432 // Finish mean number of data counts per channel 00433 m4p_FOMNbData[fr][rg][cg][0] /= ((double)(m4p_FOMNbBins[fr][rg][cg][0])); 00434 // Finish RMSE computation 00435 m4p_FOMRMSE[fr][rg][cg][0] /= ((FLTNB)(m4p_FOMNbBins[fr][rg][cg][0])); 00436 m4p_FOMRMSE[fr][rg][cg][0] = sqrt(m4p_FOMRMSE[fr][rg][cg][0]); 00437 // Print out 00438 Cout(spaces_fr << spaces_rg << spaces_cg << " --> Number of data channels used in optimization: " << m4p_FOMNbBins[fr][rg][cg][0] << endl); 00439 Cout(spaces_fr << spaces_rg << spaces_cg << " --> Mean number of data counts per channel: " << m4p_FOMNbData[fr][rg][cg][0] << endl); 00440 Cout(spaces_fr << spaces_rg << spaces_cg << " --> Log-likelihood: " << m4p_FOMLogLikelihood[fr][rg][cg][0] << endl); 00441 Cout(spaces_fr << spaces_rg << spaces_cg << " --> RMSE: " << m4p_FOMRMSE[fr][rg][cg][0] << endl); 00442 } 00443 } 00444 } 00445 } 00446 // Then call the specific post-update-step function from the child optimizer 00447 if (PostDataUpdateSpecificStep(a_iteration, a_nbIterations, a_subset, a_nbSubsets)) 00448 { 00449 Cerr("***** vOptimizer::PostDataUpdateStep() -> A problem occured while applying the specific post-data-update step of the optimizer module !" << endl); 00450 return 1; 00451 } 00452 // Normal end 00453 return 0; 00454 } 00455 00456 // ===================================================================== 00457 // --------------------------------------------------------------------- 00458 // --------------------------------------------------------------------- 00459 // ===================================================================== 00460 00461 int vOptimizer::PostDataUpdateSpecificStep(int a_iteration, int a_nbIterations, int a_subset, int a_nbSubsets) 00462 { 00463 // By default, just do nothing here. This function is designed to be overloaded by the specific optimizer if needed 00464 return 0; 00465 } 00466 00467 // ===================================================================== 00468 // --------------------------------------------------------------------- 00469 // --------------------------------------------------------------------- 00470 // ===================================================================== 00471 00472 int vOptimizer::DataStep1ForwardProjectModel( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00473 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00474 int a_th ) 00475 { 00476 // ======================================================================= 00477 // 4D forward projection including framing, respiratory and cardiac gating 00478 // ======================================================================= 00479 00480 // Clean buffers 00481 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00482 { 00483 m2p_forwardValues[a_th][b] = 0.; 00484 for (int img=0; img<m_nbBackwardImages; img++) m3p_backwardValues[a_th][b][img] = 0.; 00485 } 00486 00487 // Loop over time basis functions 00488 for (int tbf=0; tbf<mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions(); tbf++) 00489 { 00490 // Get frame/basis coefficient and continue if null 00491 FLTNB time_basis_coef = mp_ImageDimensionsAndQuantification->GetTimeBasisCoefficient(tbf,a_timeFrame); 00492 if (time_basis_coef==0.) continue; 00493 // Loop over respiratory basis functions 00494 for (int rbf=0; rbf<mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions(); rbf++) 00495 { 00496 // Get resp_gate/basis coefficient and continue if null 00497 FLTNB resp_basis_coef = mp_ImageDimensionsAndQuantification->GetRespBasisCoefficient(rbf,a_respGate); 00498 if (resp_basis_coef==0.) continue; 00499 // Loop over cardiac basis functions 00500 for (int cbf=0; cbf<mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions(); cbf++) 00501 { 00502 // Get card_gate_basis coefficient and continue if null 00503 FLTNB card_basis_coef = mp_ImageDimensionsAndQuantification->GetCardBasisCoefficient(cbf,a_cardGate); 00504 if (card_basis_coef==0.) continue; 00505 // Compute global coefficient 00506 FLTNB global_basis_coef = time_basis_coef * resp_basis_coef * card_basis_coef; 00507 // Loop over TOF bins 00508 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00509 { 00510 // Set the current TOF bin 00511 ap_Line->SetCurrentTOFBin(b); 00512 // Project the image and apply dynamic coefficient converions 00513 m2p_forwardValues[a_th][b] += ForwardProject(ap_Line,ap_Image->m4p_forwardImage[tbf][rbf][cbf]) * global_basis_coef; 00514 } 00515 } 00516 } 00517 } 00518 00519 // ===================================== 00520 // Include the additive correction terms 00521 // ===================================== 00522 00523 // Add additive terms (we multiply by the frame duration because the additive terms are provided as rates) 00524 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) m2p_forwardValues[a_th][b] += ap_Event->GetAdditiveCorrections(b) * mp_ImageDimensionsAndQuantification->GetFrameDurationInSec(a_bed, a_timeFrame); 00525 00526 // End 00527 return 0; 00528 } 00529 00530 // ===================================================================== 00531 // --------------------------------------------------------------------- 00532 // --------------------------------------------------------------------- 00533 // ===================================================================== 00534 00535 int vOptimizer::DataStep2Optional( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00536 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00537 int a_iteration, int a_th ) 00538 { 00539 // Deliberately do nothing! 00540 return 0; 00541 } 00542 00543 // ===================================================================== 00544 // --------------------------------------------------------------------- 00545 // --------------------------------------------------------------------- 00546 // ===================================================================== 00547 00548 int vOptimizer::DataStep3BackwardProjectSensitivity( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00549 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00550 int a_th ) 00551 { 00552 // Loop over TOF bins 00553 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00554 { 00555 // Set the current TOF bin of the projection-line 00556 ap_Line->SetCurrentTOFBin(b); 00557 // The weight associated to the line to be backprojected 00558 FLTNB weight = 0.; 00559 // Call the function to compute specific sensitivity 00560 if (SensitivitySpecificOperations 00561 ( 00562 ap_Event->GetEventValue(b), // 1: the measured data 00563 m2p_forwardValues[a_th][b], // 2: the forward model 00564 &weight, // 3: the sensitivity weight 00565 ap_Event->GetMultiplicativeCorrections(), // 4: the multiplicative corrections 00566 ap_Event->GetAdditiveCorrections(b)*mp_ImageDimensionsAndQuantification->GetFrameDurationInSec(a_bed, a_timeFrame), // 5: the additive corrections 00567 mp_ImageDimensionsAndQuantification->GetQuantificationFactor(a_bed,a_timeFrame, a_respGate, a_cardGate), // 6: the quantification factor 00568 ap_Line // 7: the projection line 00569 )) 00570 { 00571 Cerr("***** vOptimizer::DataStep3BackwardProjectSensitivity() -> A problem occured while performing the sensitivity specific operations !" << endl); 00572 return 1; 00573 } 00574 // Back-project the weight into the sensitivity matrix 00575 BackwardProject(ap_Line, ap_Image->m5p_sensitivity[a_th][a_timeFrame][a_respGate][a_cardGate], weight); 00576 } 00577 00578 // End 00579 return 0; 00580 } 00581 00582 // ===================================================================== 00583 // --------------------------------------------------------------------- 00584 // --------------------------------------------------------------------- 00585 // ===================================================================== 00586 00587 int vOptimizer::DataStep4Optional( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00588 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00589 int a_iteration, int a_th ) 00590 { 00591 // Deliberately do nothing! 00592 return 0; 00593 } 00594 00595 // ===================================================================== 00596 // --------------------------------------------------------------------- 00597 // --------------------------------------------------------------------- 00598 // ===================================================================== 00599 00600 int vOptimizer::DataStep5ComputeCorrections( oProjectionLine* ap_Line, vEvent* ap_Event, 00601 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00602 int a_th ) 00603 { 00604 // Loop on TOF bins 00605 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00606 { 00607 // Set the current TOF bin of the projection-line 00608 ap_Line->SetCurrentTOFBin(b); 00609 // Then call the pure virtual function for specific data space operations 00610 if (DataSpaceSpecificOperations 00611 ( 00612 ap_Event->GetEventValue(b), // 1: the measured data 00613 m2p_forwardValues[a_th][b], // 2: the forward model 00614 m3p_backwardValues[a_th][b], // 3: the backward values (the result) 00615 ap_Event->GetMultiplicativeCorrections(), // 4: the multiplicative corrections 00616 ap_Event->GetAdditiveCorrections(b)*mp_ImageDimensionsAndQuantification->GetFrameDurationInSec(a_bed, a_timeFrame), // 5: the additive corrections 00617 mp_ImageDimensionsAndQuantification->GetQuantificationFactor(a_bed,a_timeFrame, a_respGate, a_cardGate), // 6: the quantification factor 00618 ap_Line // 7: the projection line 00619 )) 00620 { 00621 Cerr("***** vOptimizer::DataStep5ComputeCorrections() -> A problem occured while performing specific data space operations !" << endl); 00622 return 1; 00623 } 00624 } 00625 00626 // End 00627 return 0; 00628 } 00629 00630 // ===================================================================== 00631 // --------------------------------------------------------------------- 00632 // --------------------------------------------------------------------- 00633 // ===================================================================== 00634 00635 int vOptimizer::DataStep6Optional( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00636 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00637 int a_iteration, int a_th ) 00638 { 00639 // Deliberately do nothing! 00640 return 0; 00641 } 00642 00643 // ===================================================================== 00644 // --------------------------------------------------------------------- 00645 // --------------------------------------------------------------------- 00646 // ===================================================================== 00647 00648 int vOptimizer::DataStep7BackwardProjectCorrections( oProjectionLine* ap_Line, oImageSpace* ap_Image, vEvent* ap_Event, 00649 int a_bed, int a_timeFrame, int a_respGate, int a_cardGate, 00650 int a_th ) 00651 { 00652 // ======================================================================== 00653 // 4D backward projection including framing, respiratory and cardiac gating 00654 // ======================================================================== 00655 00656 // Loop over time basis functions 00657 for (int tbf=0; tbf<mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions(); tbf++) 00658 { 00659 // Get frame/basis coefficient and continue if null 00660 FLTNB time_basis_coef = mp_ImageDimensionsAndQuantification->GetTimeBasisCoefficient(tbf,a_timeFrame); 00661 if (time_basis_coef==0.) continue; 00662 // Loop over respiratory basis functions 00663 for (int rbf=0; rbf<mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions(); rbf++) 00664 { 00665 // Get resp_gate/basis coefficient and continue if null 00666 FLTNB resp_basis_coef = mp_ImageDimensionsAndQuantification->GetRespBasisCoefficient(rbf,a_respGate); 00667 if (resp_basis_coef==0.) continue; 00668 // Loop over cardiac basis functions 00669 for (int cbf=0; cbf<mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions(); cbf++) 00670 { 00671 // Get card_gate_basis coefficient and continue if null 00672 FLTNB card_basis_coef = mp_ImageDimensionsAndQuantification->GetCardBasisCoefficient(cbf,a_cardGate); 00673 if (card_basis_coef==0.) continue; 00674 // Compute global coefficient 00675 FLTNB global_basis_coef = time_basis_coef * resp_basis_coef * card_basis_coef; 00676 // Loop over TOF bins 00677 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00678 { 00679 // Set the current TOF bin of the projection-line 00680 ap_Line->SetCurrentTOFBin(b); 00681 // Loop over backprojection images 00682 for (int img=0; img<m_nbBackwardImages; img++) 00683 { 00684 // Continue if backproj is null or infinity 00685 if (m3p_backwardValues[a_th][b][img]==0. || !isfinite(m3p_backwardValues[a_th][b][img])) continue; 00686 // Backward project into the backward image 00687 BackwardProject( ap_Line, ap_Image->m6p_backwardImage[img][a_th][tbf][rbf][cbf] , m3p_backwardValues[a_th][b][img] * global_basis_coef ); 00688 } 00689 } 00690 } 00691 } 00692 } 00693 00694 // End 00695 return 0; 00696 } 00697 00698 // ===================================================================== 00699 // --------------------------------------------------------------------- 00700 // --------------------------------------------------------------------- 00701 // ===================================================================== 00702 00703 int vOptimizer::DataStep8ComputeFOM( oProjectionLine* ap_Line, vEvent* ap_Event, 00704 int a_timeFrame, int a_respGate, int a_cardGate, 00705 int a_thread ) 00706 { 00707 // Loop on TOF bins 00708 for (int b=0; b<ap_Line->GetNbTOFBins(); b++) 00709 { 00710 // Get the model and the data 00711 FLTNB model = m2p_forwardValues[a_thread][b]; 00712 FLTNB data = ap_Event->GetEventValue(b); 00713 // Update log likelihood only if model is strictly positive (to avoid numerical issues, we use a threshold at e-10) 00714 if (model>1.e-10) m4p_FOMLogLikelihood[a_timeFrame][a_respGate][a_cardGate][a_thread] += data*log(model)-model; 00715 // Update RMSE 00716 m4p_FOMRMSE[a_timeFrame][a_respGate][a_cardGate][a_thread] += (data-model)*(data-model); 00717 // Update number of data channels 00718 m4p_FOMNbBins[a_timeFrame][a_respGate][a_cardGate][a_thread]++; 00719 // Update the number of data counts 00720 m4p_FOMNbData[a_timeFrame][a_respGate][a_cardGate][a_thread] += ((double)data); 00721 } 00722 // Normal end 00723 return 0; 00724 } 00725 00726 // ===================================================================== 00727 // --------------------------------------------------------------------- 00728 // --------------------------------------------------------------------- 00729 // ===================================================================== 00730 00731 int vOptimizer::UpdateVisitedVoxels( oImageSpace* ap_Image ) 00732 { 00733 // Verbose 00734 if (m_verbose>=3) Cout("vOptimizer::UpdateVisitedVoxels() -> Tick visited voxels based on sensitivity" << endl); 00735 00736 // We loop on the sensitivity for the first frame/gates and look if voxels were 'visited' by LORs 00737 int thread0 = 0; int frame0 = 0; int resp_gate0 = 0; int card_gate0 = 0; 00738 for (int v=0; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ(); v++) 00739 // If the voxel has been visited, we add 1. to the ap_Image->mp_visitedVoxelsImage 00740 if (ap_Image->m5p_sensitivity[thread0][frame0][resp_gate0][card_gate0][v]!=0.) ap_Image->mp_visitedVoxelsImage[v] += 1.; 00741 00742 // End 00743 return 0; 00744 } 00745 00746 // ===================================================================== 00747 // --------------------------------------------------------------------- 00748 // --------------------------------------------------------------------- 00749 // ===================================================================== 00750 00751 int vOptimizer::ImageUpdateStep( oImageSpace* ap_Image, int a_iteration, int a_nbSubsets ) 00752 { 00753 // Verbose 00754 if (m_verbose>=2 || m_optimizerImageStatFlag) Cout("vOptimizer::ImageUpdateStep() -> Start image update" << endl); 00755 // Number of spaces for nice printing 00756 string spaces_tbf = ""; if (mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions()>1) spaces_tbf += " "; 00757 string spaces_rbf = ""; if (mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions()>1) spaces_rbf += " "; 00758 string spaces_cbf = ""; if (mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions()>1) spaces_cbf += " "; 00759 // Loop over time basis functions 00760 for (int tbf=0; tbf<mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions(); tbf++) 00761 { 00762 // Verbose 00763 if (mp_ImageDimensionsAndQuantification->GetNbTimeBasisFunctions()>1 && (m_verbose>=3 || m_optimizerImageStatFlag)) 00764 { 00765 if (mp_ImageDimensionsAndQuantification->GetTimeStaticFlag()) Cout(spaces_tbf << "--> Time frame " << tbf+1 << endl); 00766 else Cout(spaces_tbf << "--> Time basis function: " << tbf+1 << endl); 00767 } 00768 // Loop over respiratory basis functions 00769 for (int rbf=0; rbf<mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions(); rbf++) 00770 { 00771 // Verbose 00772 if (mp_ImageDimensionsAndQuantification->GetNbRespBasisFunctions()>1 && (m_verbose>=3 || m_optimizerImageStatFlag)) 00773 { 00774 if (mp_ImageDimensionsAndQuantification->GetRespStaticFlag()) Cout(spaces_tbf << spaces_rbf << "--> Respiratory gate " << rbf+1 << endl); 00775 else Cout(spaces_tbf << spaces_rbf << "--> Respiratory basis function: " << rbf+1 << endl); 00776 } 00777 // Loop over cardiac basis functions 00778 for (int cbf=0; cbf<mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions(); cbf++) 00779 { 00780 // Verbose 00781 if (mp_ImageDimensionsAndQuantification->GetNbCardBasisFunctions()>1 && (m_verbose>=3 || m_optimizerImageStatFlag)) 00782 { 00783 if (mp_ImageDimensionsAndQuantification->GetCardStaticFlag()) Cout(spaces_tbf << spaces_rbf << spaces_cbf << "--> Cardiac gate " << cbf+1 << endl); 00784 else Cout(spaces_tbf << spaces_rbf << spaces_cbf << "--> Cardiac basis function: " << cbf+1 << endl); 00785 } 00786 // Set the number of threads for image computation 00787 #ifdef CASTOR_OMP 00788 omp_set_num_threads(mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation()); 00789 #endif 00790 // Reset counter for image stats 00791 if (m_optimizerImageStatFlag) 00792 { 00793 for (int th=0; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation(); th++) 00794 { 00795 mp_imageStatNbVox[th] = 0; 00796 mp_imageStatMin[th] = ap_Image->m4p_image[tbf][rbf][cbf][0]; 00797 mp_imageStatMax[th] = ap_Image->m4p_image[tbf][rbf][cbf][0]; 00798 mp_imageStatMean[th] = 0.; 00799 mp_imageStatVariance[th] = 0.; 00800 mp_correctionStatMean[th] = 0.; 00801 mp_correctionStatVariance[th] = 0.; 00802 } 00803 } 00804 // OMP loop over voxels 00805 int v; 00806 bool error = false; 00807 #pragma omp parallel for private(v) schedule(guided) 00808 for (v=0 ; v<mp_ImageDimensionsAndQuantification->GetNbVoxXYZ() ; v++) 00809 { 00810 // Get the thread index 00811 int th = 0; 00812 #ifdef CASTOR_OMP 00813 th = omp_get_thread_num(); 00814 #endif 00815 // Compute sensitivity 00816 FLTNB sensitivity = ComputeSensitivity(ap_Image->m5p_sensitivity[0],tbf,rbf,cbf,v,a_nbSubsets); 00817 // If the sensitivity is negative or null, we skip this voxel 00818 if (sensitivity<=0.) continue; 00819 // Keep the current image value in a buffer for update statistics 00820 FLTNB old_image_value = ap_Image->m4p_image[tbf][rbf][cbf][v]; 00821 // Fill class-local buffer of backward values (thread-safe) 00822 for (int nb=0; nb<m_nbBackwardImages; nb++) 00823 m3p_backwardValues[th][0][nb] = ap_Image->m6p_backwardImage[nb][0][tbf][rbf][cbf][v]; 00824 // Then call the pure virtual function for specific data space operations 00825 if (ImageSpaceSpecificOperations 00826 ( 00827 ap_Image->m4p_image[tbf][rbf][cbf][v], 00828 // Note: have to be carefull here because we pass rbf and cbf as the actual respgate and cardgate. It may be wrong if one would like 00829 // to perform MLAA reconstruction but using PET basis functions different from diracs for example... In this case, we would get 00830 // segmentation faults. But actually, this function would be overloaded by MLAA anyway... 00831 //ap_Image->m4p_attenuation != NULL ? ap_Image->m4p_attenuation[tbf][rbf][cbf][v] : 0. , 00832 &ap_Image->m4p_image[tbf][rbf][cbf][v], 00833 //ap_Image->m4p_attenuation != NULL ? &ap_Image->m4p_attenuation[tbf][rbf][cbf][v] : NULL , 00834 sensitivity, 00835 m3p_backwardValues[th][0] 00836 )) 00837 { 00838 Cerr("***** vOptimizer::ImageUpdateStep() -> A problem occured in while performing image space specific operations of the optimizer !" << endl); 00839 error = true; 00840 } 00841 // Do some image statistics 00842 if (m_optimizerImageStatFlag) 00843 { 00844 if (mp_imageStatMin[th]>ap_Image->m4p_image[tbf][rbf][cbf][v]) mp_imageStatMin[th] = ap_Image->m4p_image[tbf][rbf][cbf][v]; 00845 if (mp_imageStatMax[th]<ap_Image->m4p_image[tbf][rbf][cbf][v]) mp_imageStatMax[th] = ap_Image->m4p_image[tbf][rbf][cbf][v]; 00846 // The one pass algorithm is used to compute the variance here for both the image and correction step. 00847 // Do not change anyhting to the order of the operations ! 00848 mp_imageStatNbVox[th]++; 00849 double sample = ((double)(ap_Image->m4p_image[tbf][rbf][cbf][v])); 00850 double delta = sample - mp_imageStatMean[th]; 00851 mp_imageStatMean[th] += delta / ((double)(mp_imageStatNbVox[th])); 00852 mp_imageStatVariance[th] += delta * (sample - mp_imageStatMean[th]); 00853 // Same one-pass variance algorithm for the correction step 00854 sample = ((double)(ap_Image->m4p_image[tbf][rbf][cbf][v] - old_image_value)); 00855 delta = sample - mp_correctionStatMean[th]; 00856 mp_correctionStatMean[th] += delta / ((double)(mp_imageStatNbVox[th])); 00857 mp_correctionStatVariance[th] += delta * (sample - mp_correctionStatMean[th]); 00858 } 00859 } 00860 // Check for errors (we cannot stop the multi-threaded loop so we do it here) 00861 if (error) return 1; 00862 // Finish image update statistics computations: these operations are specific to the merging of the 00863 // multi-threaded one-pass variance estimations used above. 00864 if (m_optimizerImageStatFlag) 00865 { 00866 for (int th=1; th<mp_ImageDimensionsAndQuantification->GetNbThreadsForImageComputation(); th++) 00867 { 00868 // Image minimum and maximum 00869 if (mp_imageStatMin[0]>mp_imageStatMin[th]) mp_imageStatMin[0] = mp_imageStatMin[th]; 00870 if (mp_imageStatMax[0]<mp_imageStatMax[th]) mp_imageStatMax[0] = mp_imageStatMax[th]; 00871 // Cast the counts into double 00872 double count1 = ((double)(mp_imageStatNbVox[0])); 00873 double count2 = ((double)(mp_imageStatNbVox[th])); 00874 // Update the count 00875 mp_imageStatNbVox[0] += mp_imageStatNbVox[th]; 00876 double count12 = ((double)(mp_imageStatNbVox[0])); 00877 // Compute the delta mean 00878 double delta = mp_imageStatMean[0] - mp_imageStatMean[th]; 00879 // Update the variance 00880 mp_imageStatVariance[0] += mp_imageStatVariance[th] + delta * delta * count1 * count2 / count12; 00881 // Update the mean 00882 mp_imageStatMean[0] = (count1*mp_imageStatMean[0] + count2*mp_imageStatMean[th]) / count12; 00883 // Do the same for the correction step 00884 delta = mp_correctionStatMean[0] - mp_correctionStatMean[th]; 00885 mp_correctionStatVariance[0] += mp_correctionStatVariance[th] + delta * delta * count1 * count2 / count12; 00886 mp_correctionStatMean[0] = (count1*mp_correctionStatMean[0] + count2*mp_correctionStatMean[th]) / count12; 00887 } 00888 // Finish variance computation 00889 mp_imageStatVariance[0] /= ((double)(mp_imageStatNbVox[0])); 00890 mp_correctionStatVariance[0] /= ((double)(mp_imageStatNbVox[0])); 00891 // Print out 00892 Cout(spaces_tbf << spaces_rbf << spaces_cbf << " --> Image update step " 00893 << " | mean: " << mp_correctionStatMean[0] 00894 << " | stdv: " << sqrt(mp_correctionStatVariance[0]) << endl); 00895 Cout(spaces_tbf << spaces_rbf << spaces_cbf << " --> New image estimate" 00896 << " | mean: " << mp_imageStatMean[0] 00897 << " | stdv: " << sqrt(mp_imageStatVariance[0]) 00898 << " | min/max: " << mp_imageStatMin[0] << "/" << mp_imageStatMax[0] << endl); 00899 } 00900 } 00901 } 00902 } 00903 00904 // End 00905 return 0; 00906 } 00907 00908 // ===================================================================== 00909 // --------------------------------------------------------------------- 00910 // --------------------------------------------------------------------- 00911 // ===================================================================== 00912 00913 FLTNB vOptimizer::ForwardProject(oProjectionLine* ap_Line, FLTNB* ap_image) 00914 { 00915 // Particular case for SPECT with attenuation correction 00916 if (m_dataType==TYPE_SPECT && m2p_attenuationImage[ap_Line->GetThreadNumber()]!=NULL) 00917 return ap_Line->ForwardProjectWithSPECTAttenuation( m2p_attenuationImage[ap_Line->GetThreadNumber()], ap_image ); 00918 // Otherwise call the function without attenuation 00919 else 00920 return ap_Line->ForwardProject( ap_image ); 00921 } 00922 00923 // ===================================================================== 00924 // --------------------------------------------------------------------- 00925 // --------------------------------------------------------------------- 00926 // ===================================================================== 00927 00928 void vOptimizer::BackwardProject(oProjectionLine* ap_Line, FLTNB* ap_image, FLTNB a_value) 00929 { 00930 // Particular case for SPECT with attenuation correction 00931 if (m_dataType==TYPE_SPECT && m2p_attenuationImage[ap_Line->GetThreadNumber()]!=NULL) 00932 ap_Line->BackwardProjectWithSPECTAttenuation( m2p_attenuationImage[ap_Line->GetThreadNumber()], ap_image, a_value ); 00933 // Otherwise call the function without attenuation 00934 else 00935 ap_Line->BackwardProject( ap_image, a_value ); 00936 } 00937 00938 // ===================================================================== 00939 // --------------------------------------------------------------------- 00940 // --------------------------------------------------------------------- 00941 // ===================================================================== 00942 00943 FLTNB vOptimizer::ComputeSensitivity( FLTNB**** a4p_sensitivityMatrix, 00944 int a_timeBasisFunction, int a_respBasisFunction, int a_cardBasisFunction, 00945 int a_voxel, int a_nbSubsets ) 00946 { 00947 // The sensitivity to be computed 00948 FLTNB sensitivity = 0.; 00949 // Loop over time frames 00950 for (int fr=0; fr<mp_ImageDimensionsAndQuantification->GetNbTimeFrames(); fr++) 00951 { 00952 // Get frame/basis coefficient and continue if null 00953 FLTNB time_basis_coef = mp_ImageDimensionsAndQuantification->GetTimeBasisCoefficient(a_timeBasisFunction,fr); 00954 if (time_basis_coef==0.) continue; 00955 // Loop over respiratory gates 00956 for (int rg=0; rg<mp_ImageDimensionsAndQuantification->GetNbRespGates(); rg++) 00957 { 00958 // Get resp_gate/basis coefficient and continue if null 00959 FLTNB resp_basis_coef = mp_ImageDimensionsAndQuantification->GetRespBasisCoefficient(a_respBasisFunction,rg); 00960 if (resp_basis_coef==0.) continue; 00961 // Loop over cardiac gates 00962 for (int cg=0; cg<mp_ImageDimensionsAndQuantification->GetNbCardGates(); cg++) 00963 { 00964 // Get card_gate_basis coefficient and continue if null 00965 FLTNB card_basis_coef = mp_ImageDimensionsAndQuantification->GetCardBasisCoefficient(a_cardBasisFunction,cg); 00966 if (card_basis_coef==0.) continue; 00967 // Add actual weight contribution 00968 sensitivity += a4p_sensitivityMatrix[fr][rg][cg][a_voxel] * 00969 time_basis_coef * resp_basis_coef * card_basis_coef; 00970 } 00971 } 00972 } 00973 // If listmode, then divide by the number of subsets 00974 if (m_dataMode==MODE_LIST) sensitivity /= ((FLTNB)a_nbSubsets); 00975 // Return sensitivity 00976 return sensitivity; 00977 } 00978 00979 // ===================================================================== 00980 // --------------------------------------------------------------------- 00981 // --------------------------------------------------------------------- 00982 // =====================================================================