CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
code/src/dynamic/vDynamicModel.cc
Go to the documentation of this file.
1 
8 #include "vDynamicModel.hh"
9 
10 // =====================================================================
11 // ---------------------------------------------------------------------
12 // ---------------------------------------------------------------------
13 // =====================================================================
14 /*
15  \fn vDynamicModel
16  \brief Constructor of vDynamicModel. Simply set all data members to default values.
17 */
19 {
20  mp_ID = NULL;
21  m_nbTimeBF = -1;
22  m_nbModelParam = -1;
23  m_nbRGModelParam = -1 ;
24  m_nbCGModelParam = -1;
25 
26  m2p_parametricImages = NULL;
31  m2p_outputParImages = NULL;
32  m_verbose = -1;
33 
34  m_checked = false;
35  m_initialized = false;
36  m_saveParImageFlag = true;
38  m_AICfileProvided = false;
40  m_noImageUpdateFlag = false;
43  mp_maskModel = NULL;
44  m_nbVoxelsMask = 0;
45 
46  // NNLS variable to be allocated in child function if needed
47  mp_w = NULL;
48  m3p_nnlsA = NULL;
49  m2p_nnlsB = NULL;
50  m2p_nnlsMat = NULL;
51  m2p_nnlsX = NULL;
52  m2p_nnlsWp = NULL;
53  m2p_nnlsIdx = NULL;
54 }
55 
56 
57 
58 
59 // =====================================================================
60 // ---------------------------------------------------------------------
61 // ---------------------------------------------------------------------
62 // =====================================================================
68 {
69  if(m_initialized)
70  {
71  for(int b=0 ; b<m_nbTimeBF ; b++)
72  {
74  if (m2p_parametricImages[b]) delete[] m2p_parametricImages[b];
75  if (m2p_outputParImages[b]) delete[] m2p_outputParImages[b];
76  }
77 
82  }
83 }
84 
85 // =====================================================================
86 // ---------------------------------------------------------------------
87 // ---------------------------------------------------------------------
88 // =====================================================================
89 /*
90  \fn ShowHelp
91  \brief Print out general help about dynamic models
92  model and its initialization
93 */
94 
96 {
97  cout << " The following keywords are common to all dynamic models :" << endl;
98  cout << " 'Number_of_iterations_before_image_update: x' Set a number 'x' of iteration to reach before using the model to generate the images at each frames/gates" << endl;
99  cout << " (Default x == 0) " << endl;
100  cout << " 'No_image_update: x' If set to 1, the reconstructed images for the next iteration/subset are not reestimated using the model" << endl;
101  cout << " (Default x == 0) (the code just performs standard independent reconstruction of each frames/gates) " << endl;
102  cout << " 'No_parameters_update: x' If set to 1, the parameters / functions of the model are not estimated with the image" << endl;
103  cout << " (Default x == 0) (this could be used to test The EstimateImageWithModel() function with specific user-provided parametric images) " << endl;
104  cout << " 'Save_parametric_images : x' Enable (1)/Disable(0) saving parametric images on disk" << endl;
105  cout << " (Default x == 1) " << endl;
106  cout << " 'Save_blacklisted_voxels_images : x' Enable (1)/Disable(0) saving blacklisted voxels images on disk" << endl;
107  cout << " (Default x == 0) " << endl;
108  cout << " 'Mask:' Path to an interfile image containing a mask indicating if the model must be applied (1) or not (0) in each voxel" << endl;
109  cout << " (Default: model applies everywhere) " << endl;
110 }
111 
112 
113 
114 
115 // =====================================================================
116 // ---------------------------------------------------------------------
117 // ---------------------------------------------------------------------
118 // =====================================================================
119 
120 /*
121  \fn CheckParameters
122  \brief This function is used to check parameters after the latter
123  have been all set using Set functions.
124  \return 0 if success, positive value otherwise.
125 */
127 {
128 
129  if(m_verbose>=2) Cout("vDynamicModel::CheckParameters ..."<< endl);
130 
131  // Check image dimensions
132  if (mp_ID==NULL)
133  {
134  Cerr("***** vDynamicModel::CheckParameters() -> No image dimensions provided !" << endl);
135  return 1;
136  }
137 
138  // Check verbosity
139  if (m_verbose<0)
140  {
141  Cerr("***** vDynamicModel::CheckParameters() -> Wrong verbosity level provided !" << endl);
142  return 1;
143  }
144 
145  // Check number of basis functions
146  if (m_nbTimeBF <0)
147  {
148  Cerr("***** vDynamicModel::CheckParameters() -> Basis functions number has not been initialized !" << endl);
149  return 1;
150  }
151 
152  // Check number of parameters in the model
153  if (m_nbModelParam <0)
154  {
155  Cerr("***** vDynamicModel::CheckParameters() -> Number of model parameter has not been initialized !" << endl);
156  return 1;
157  }
158 
159  // Check number of parameters in the model
160  if (m_nbModelParam <0)
161  {
162  Cerr("***** vDynamicModel::CheckParameters() -> Number of model parameter has not been initialized !" << endl);
163  return 1;
164  }
165 
166  // Check parameters of the child class (if this function is overloaded)
168  {
169  Cerr("***** vDynamicModel::CheckParameters() -> An error occurred while checking parameters of the child dynamic class !" << endl);
170  return 1;
171  }
172 
173  // Normal end
174  m_checked = true;
175  return 0;
176 }
177 
178 
179 
180 
181 // =====================================================================
182 // ---------------------------------------------------------------------
183 // ---------------------------------------------------------------------
184 // =====================================================================
185 /*
186  \fn vDynamicModel::Initialize()
187  \brief A public function used to initialize the dynamic model
188  \details This function does not take any parameter and is used to initialize everything that
189  should be initialized. At the end, it calls the pure virtual InitializeSpecific()
190  function implemented by children.
191  \return An integer reflecting the initialization status; 0 if no problem, another value otherwise.
192 */
194 {
195  if(m_verbose >=2) Cout("vDynamicModel::Initialize ..."<< endl);
196 
197  // Forbid initialization without check
198  if (!m_checked)
199  {
200  Cerr("***** vDynamicModel::Initialize() -> Must call CheckParameters functions before Initialize() !" << endl);
201  return 1;
202  }
203 
204  // If AIC file has been provided - initialise the curve - Can have applications in many models
206  {
207  if(m_verbose >=2) Cout("vDynamicModel::Initialize Arterial Input Curve"<< endl);
211  // Seting Framing using the first bed frame information - assuming that at the moment all beds have the same framing
214  // Initialise parameters
216  {
217  Cerr("***** vDynamicModel::Initialize() -> Error while initializing Arterial Input Curve " << endl);
218  return 1;
219  }
220  // parameter checks
222  {
223  Cerr("***** vDynamicModel::Initialize() -> Error while checking Arterial Input Curve parameters " << endl);
224  return 1;
225  }
226  if(m_verbose >=3) Cout("vDynamicModel::Interpolating Arterial Input Curve ..."<< endl);
227  // Interpolate within AIC datapoints
229  }
230 
231  // Get the number of available voxels in Mask
232  // and check for wrong values (no 1 or 0)
233  if( mp_maskModel != NULL )
234  {
235  m_nbVoxelsMask = 0;
236  for (int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
237  {
238  if(mp_maskModel[ v ] != 0
239  && mp_maskModel[ v ] != 1 )
240  {
241  Cerr("***** vDynamicModel::Initialize() -> Wrong initial values in mask (must be either 0 or 1) !" << endl);
242  return 1;
243  }
244 
246  }
247  }
248  else
250 
251  // Call the specific initialization function of the child
252  if (InitializeSpecific())
253  {
254  Cerr("***** vDynamicModel::Initialize() -> A problem occurred while initializing stuff specific to the dynamic model !" << endl);
255  return 1;
256  }
257 
258  // Normal end
259  return 0;
260 }
261 
262 
263 // =====================================================================
264 // ---------------------------------------------------------------------
265 // ---------------------------------------------------------------------
266 // =====================================================================
267 /*
268  \fn vDynamicModel::ComputeOutputParImage
269  \brief Compute output image using the m2p_parametricImages matrix Store the result in the m2p_outputParImages matrix
270 */
272 {
273  if(m_verbose >=2) Cout("vDynamicModel::ComputeOutputParImage ..." <<endl);
274 
275  if(m_verbose >=3) Cout(" Save ParametricImage Flag is " << m_saveParImageFlag << endl);
276  // If we save parametric image
278  {
279  if(m_verbose >=3) Cout(" Number of model parameters " << m_nbModelParam << endl );
280  for (int p = 0; p < m_nbModelParam; p++) {
281  // If output image matrix is allocated, then copy the current parametric images
282  if (m2p_outputParImages != NULL
284  {
285  if(m_verbose >=3) Cout(" Setting parametric image #: " << p+1 << endl );
286  for (int v = 0; v < mp_ID->GetNbVoxXYZ(); v++)
288  }
289  // Point to parametric images otherwise
290  else
292  }
293  }
294 }
295 
296 
297 // =====================================================================
298 // ---------------------------------------------------------------------
299 // ---------------------------------------------------------------------
300 // =====================================================================
301 /*
302  \fn vDynamicModel::ApplyOutputFOVMaskingOnParametricImages
303  \brief Mask the outside of the transaxial FOV based on the m_fovOutPercent
304  \details Similar to the eponym function in ImageSpace, but on parametric images
305 */
307 {
308  // If the output FOV percent is under 0 (the default value) and number of axial slices to be removed is 0, we do not mask anything
309  if ( mp_ID->GetFOVOutPercent()<=0. &&
310  mp_ID->GetNbSliceOutMask()==0 ) return 0;
311 
312  // Verbose
313  if (m_verbose>=2)
314  {
315  Cout("vDynamicModel::ApplyOutputFOVMaskingOnParametricImages() -> Mask output image" << endl);
316  if (mp_ID->GetFOVOutPercent()>0.) Cout(" --> Mask transaxial FOV outside " << mp_ID->GetFOVOutPercent() << " %" << endl);
317  if (mp_ID->GetNbSliceOutMask()>0) Cout(" --> Mask " << mp_ID->GetNbSliceOutMask() << " slices from both axial FOV limits" << endl);
318  }
319  // -----------------------------------------------
320  // Transaxial FOV masking
321  // -----------------------------------------------
322  if (mp_ID->GetFOVOutPercent()>0.)
323  {
324  // Precast half the number of voxels over X and Y minus 1 (for efficiency)
325  FLTNB flt_base_x = 0.5*((FLTNB)(mp_ID->GetNbVoxX()-1));
326  FLTNB flt_base_y = 0.5*((FLTNB)(mp_ID->GetNbVoxY()-1));
327 
328  // Compute FOV elipse radius over X and Y, then squared
329  FLTNB squared_radius_x = 0.5 * ((FLTNB)(mp_ID->GetNbVoxX())) * mp_ID->GetVoxSizeX()
330  * mp_ID->GetFOVOutPercent() / 100.;
331  squared_radius_x *= squared_radius_x;
332  FLTNB squared_radius_y = 0.5 * ((FLTNB)(mp_ID->GetNbVoxY())) * mp_ID->GetVoxSizeY()
333  * mp_ID->GetFOVOutPercent() / 100.;
334  squared_radius_y *= squared_radius_y;
335 
336  // We assume that the computation of the distance from the center for a given
337  // voxel and comparing it with the output FOV percentage costs more than performing
338  // the loops in an inverse order compared to how the image is stored in memory.
339  // Thus we begin the loops over X, then Y, then we test and if test passes, we
340  // do the remaining loop over Z and over all dynamic dimensions.
341  int x;
342  #pragma omp parallel for private(x) schedule(guided)
343  for (x=0; x<mp_ID->GetNbVoxX(); x++)
344  {
345  // Compute X distance from image center, then squared
346  FLTNB squared_distance_x = (((FLTNB)x)-flt_base_x) * mp_ID->GetVoxSizeX();
347  squared_distance_x *= squared_distance_x;
348  // Loop over Y
349  for (int y=0; y<mp_ID->GetNbVoxY(); y++)
350  {
351  // Compute Y distance from image center, then squared
352  FLTNB squared_distance_y = (((FLTNB)y)-flt_base_y) * mp_ID->GetVoxSizeY();
353  squared_distance_y *= squared_distance_y;
354  // Test if the voxel is inside the FOV elipse, then we skip this voxel
355  if ( squared_distance_x/squared_radius_x + squared_distance_y/squared_radius_y <= 1. ) continue;
356  // Loop over Z
357  for (int z=0; z<mp_ID->GetNbVoxZ(); z++)
358  {
359  // Compute global voxel index
360  INTNB index = z*mp_ID->GetNbVoxXY() + y*mp_ID->GetNbVoxX() + x;
361 
362  for (int b=0 ; b<m_nbTimeBF ; b++)
363  m2p_outputParImages[b][index] = 0.;
364 
365  }
366  }
367  }
368  }
369 
370  // -----------------------------------------------
371  // Axial FOV masking
372  // -----------------------------------------------
373  if (mp_ID->GetNbSliceOutMask()>0)
374  {
375  INTNB removed_slices = mp_ID->GetNbSliceOutMask();
376 
377  // Mask slices
378  for (int b=0 ; b<m_nbTimeBF ; b++)
379  for (int z=0; z<removed_slices; z++)
380  {
381  // First slices
382  INTNB base_z_first = z*mp_ID->GetNbVoxXY();
383  // Loop over Y and X
384  for (int i=0; i<mp_ID->GetNbVoxXY(); i++)
385  {
386  INTNB index = base_z_first + i;
387  m2p_outputParImages[b][index] = 0.;
388  }
389  // Last slices
390  INTNB base_z_last = (mp_ID->GetNbVoxZ()-1-z)*mp_ID->GetNbVoxXY();
391  // Loop over Y and X
392  for (int i=0; i<mp_ID->GetNbVoxXY(); i++)
393  {
394  INTNB index = base_z_last + i;
395  m2p_outputParImages[b][index] = 0.;
396  }
397  }
398  }
399 
400  // End
401  return 0;
402 }
403 
404 
405 
406 
407 // =====================================================================
408 // ---------------------------------------------------------------------
409 // ---------------------------------------------------------------------
410 // =====================================================================
411 /*
412  \fn vDynamicModel::EstimateModel
413  \param ap_ImageS : pointer to the ImageSpace
414  \param a_ite : index of the actual iteration
415  \param a_sset : index of the actual subset
416  \brief This function checks if the EstimateModelParameters() function (specific to each model)
417  must be called at this stage of the reconstruction depending on the m_xxxUpdateflags.
418  \return 0 if success, other value otherwise.
419 */
420 int vDynamicModel::EstimateModel(oImageSpace* ap_ImageS, int a_ite, int a_sset)
421 {
422  if(m_verbose >= 2) Cout("vDynamicModel::EstimateModel ... " <<endl);
423 
424  #ifdef CASTOR_DEBUG
425  if (!m_initialized)
426  {
427  Cerr("***** vDynamicModel::EstimateModel() -> Called while not initialized !" << endl);
428  Exit(EXIT_DEBUG);
429  }
430  #endif
431 
433  if( EstimateModelParameters(ap_ImageS, a_ite, a_sset) )
434  {
435  Cerr("***** vDynamicModel::EstimateModel() -> A problem occurred while estimating dynamic image series with model parameters !" << endl);
436  return 1;
437  }
438 
439  return 0;
440 }
441 
442 
443 
444 
445 // =====================================================================
446 // ---------------------------------------------------------------------
447 // ---------------------------------------------------------------------
448 // =====================================================================
449 /*
450  \fn vDynamicModel::EstimateImageWithModel
451  \param ap_ImageS : pointer to the ImageSpace
452  \param a_ite : index of the actual iteration
453  \param a_sset : index of the actual subset
454  \brief This function checks if the EstimateImageWithModel() function (specific to each model)
455  must be called at this stage of the reconstruction depending on the m_xxxUpdateflags.
456  \return 0 if success, other value otherwise.
457 */
458 int vDynamicModel::EstimateImage(oImageSpace* ap_ImageS, int a_ite, int a_sset)
459 {
460  if(m_verbose >= 2) Cout("vDynamicModel::EstimateImage ... " <<endl);
461 
462  #ifdef CASTOR_DEBUG
463  if (!m_initialized)
464  {
465  Cerr("***** vDynamicModel::EstimateImage() -> Called while not initialized !" << endl);
466  Exit(EXIT_DEBUG);
467  }
468  #endif
469 
471  if( EstimateImageWithModel(ap_ImageS, a_ite, a_sset) )
472  {
473  Cerr("***** vDynamicModel::EstimateImage() -> A problem occurred while applying dynamic model to current estimate images !" << endl);
474  return 1;
475  }
476 
477  return 0;
478 }
479 
480 
481 
482 
483 // =====================================================================
484 // ---------------------------------------------------------------------
485 // ---------------------------------------------------------------------
486 // =====================================================================
487 /*
488  \fn ReadAndCheckConfigurationFile
489  \param const string& a_configurationFile : ASCII file containing informations about a dynamic model
490  \brief This function is used to read options from a configuration file. \n
491  It looks for the parameters implemented by the mother class,
492  such as 'No_image_update', 'No_parameters_update', or 'Save_parametric_images'.
493  Call 'ReadAndCheckConfigurationFileSpecific()' function of child class
494  \return 0 if success, other value otherwise.
495 */
497 {
498  if(m_verbose >=3) Cout("vDynamicModel::ReadAndCheckConfigurationFile ..."<< endl);
499 
500  ifstream in_file(a_fileOptions.c_str(), ios::in);
501 
502  if(in_file)
503  {
504  // Disable estimation of images from parametric images ?
505  string dtag = "No_image_update";
506 
507  if( ReadDataASCIIFile(a_fileOptions,
508  dtag,
510  1,
511  KEYWORD_OPTIONAL) == 1)
512  {
513  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << a_fileOptions << endl);
514  return 1;
515  }
516 
517 
518  // Disable estimation of parameters from dynamic images ?
519  dtag = "No_parameters_update";
520 
521  if( ReadDataASCIIFile(a_fileOptions,
522  dtag,
524  1,
525  KEYWORD_OPTIONAL) == 1)
526  {
527  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << a_fileOptions << endl);
528  return 1;
529  }
530 
531 
532  // Update images from parametric images after a certain number of iterations ?
533  dtag = "Number_of_iterations_before_image_update";
534 
535  if( ReadDataASCIIFile(a_fileOptions,
536  dtag,
538  1,
539  KEYWORD_OPTIONAL) == 1)
540  {
541  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << a_fileOptions << endl);
542  return 1;
543  }
544 
545 
546  // Save_parametric_images on disk ?
547  dtag = "Save_parametric_images";
548 
549  if( ReadDataASCIIFile(a_fileOptions,
550  dtag,
552  1,
553  KEYWORD_OPTIONAL) == 1)
554  {
555  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << a_fileOptions << endl);
556  return 1;
557  }
558 
559 
560  // Save blacklisted voxels images on disk ?
561  dtag = "Save_blacklisted_voxels_images";
562 
563  if( ReadDataASCIIFile(a_fileOptions,
564  dtag,
566  1,
567  KEYWORD_OPTIONAL) == 1)
568  {
569  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << a_fileOptions << endl);
570  return 1;
571  }
572 
573  // Check if a mask has been provided for the model
574  string path_to_mask = "";
575  dtag = "Mask";
576 
577  if( ReadDataASCIIFile(a_fileOptions, dtag, &path_to_mask, 1, KEYWORD_OPTIONAL) == 1)
578  {
579  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '"<< dtag <<"' flag in " << m_fileOptions << endl);
580  return 1;
581  }
582 
583  if(!path_to_mask.empty())
584  {
585  mp_maskModel = new FLTNB[ mp_ID->GetNbVoxXYZ() ];
586 
587  for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
588  mp_maskModel[v] = 1.;
589 
590 
592  {
593  Cerr("***** ivDynamicModel::ReadAndCheckConfigurationFile()-> Error reading Interfile : " << path_to_mask << " !" << endl);
594  return 1;
595  }
596 
597  if(m_verbose >=2)
598  Cout("vDynamicModel::ReadAndCheckConfigurationFile() -> The following mask will be used for the 2nd model parameters estimation: " << path_to_mask << endl);
599  }
600  // In case that no Mask option has been provided - use DynamiModel for all voxels by default
601  else
602  {
603  // Initialise and set all values to 1
604  mp_maskModel = new FLTNB[ mp_ID->GetNbVoxXYZ() ];
605  for(int v=0 ; v<mp_ID->GetNbVoxXYZ() ; v++)
606  mp_maskModel[v] = 1.;
607  }
608 
609  // Case of AIC file option provided - read file path
610  dtag = "AIC_input_file";
611 
612  if (ReadDataASCIIFile(a_fileOptions,
613  dtag,
614  &m_AICfile,
615  1,
616  KEYWORD_OPTIONAL) == 1)
617  {
618  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error while trying to read '" << dtag<< "' flag in " << a_fileOptions << endl);
619  return 1;
620  }
621 
622  // Set the AICfileProvided boolean
623  if( !m_AICfile.empty() ) m_AICfileProvided = true;
624 
625  // Recover the file path here
626  m_fileOptions = a_fileOptions;
627 
628 
629  // Call the specific function of the child dynamic model class
631  {
632  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile() -> Error occurred when trying to process the configuration file from a dynamic model child class " << endl);
633  return 1;
634  }
635  }
636  else
637  {
638  Cerr("***** vDynamicModel::ReadAndCheckConfigurationFile -> Error while trying to read configuration file at: " << a_fileOptions << endl);
639  return 1;
640  }
641 
642 
643  return 0;
644 }
645 
646 
647 
648 // =====================================================================
649 // ---------------------------------------------------------------------
650 // ---------------------------------------------------------------------
651 // =====================================================================
652 /*
653  \fn SaveParametricImages
654  \param a_iteration : current iteration index
655  \param a_subset : current number of subsets (or -1 by default)
656  \brief This function is virtual it can be overloaded by children
657  if required
658  \return 0 if success, positive value otherwise
659 */
660 int vDynamicModel::SaveParametricImages(int a_iteration, int a_subset)
661 {
662  if(m_verbose >=3) Cout("vDynamicModel::SaveParametricImages ..." <<endl);
663 
664 
666  {
667  // Get the output manager
668  sOutputManager* p_output_manager = sOutputManager::GetInstance();
669 
670  // Recover path to output interfile
671  string path_to_image = p_output_manager->GetPathName() + p_output_manager->GetBaseName();
672 
673  // Write interfile frame parametric image if required
674  if( m_nbModelParam>1 ) // Frame linear model enabled
675  {
676  // Add a suffix for iteration
677  if (a_iteration >= 0)
678  {
679  stringstream ss; ss << a_iteration + 1;
680  path_to_image.append("_it").append(ss.str());
681  }
682 
683  // Add a suffix for subset (if not negative by default), this means that we save a 'subset' image
684  if (a_subset >= 0)
685  {
686  stringstream ss; ss << a_subset + 1;
687  path_to_image.append("_ss").append(ss.str());
688  }
689 
690  if(IntfWriteImgDynCoeffFile(path_to_image,
692  mp_ID,
694  m_verbose) )
695  {
696  Cerr("***** iLinearModel::SaveParametricImages()-> Error writing Interfile of output image !" << endl);
697  return 1;
698  }
699 
700  if(m_verbose >=3) Cout("vDynamicModel::SaveBlackListedVoxelsMask ..." <<endl);
702  {
703  path_to_image = p_output_manager->GetPathName() + p_output_manager->GetBaseName() + "_blacklisted" ;
704  // Add a suffix for iteration
705  if (a_iteration >= 0)
706  {
707  stringstream ss;
708  ss << a_iteration + 1;
709  path_to_image.append("_it").append(ss.str());
710  }
711  if (a_subset >= 0)
712  {
713  stringstream ss;
714  ss << a_subset + 1;
715  path_to_image.append("_ss").append(ss.str());
716  }
717  if (IntfWriteImgFile(path_to_image,
719  mp_ID,
720  m_verbose) )
721  {
722  Cerr("***** iLinearModel::SaveParametricImages()-> Error writing image of blacklisted voxels !"
723  << endl);
724  return 1;
725  }
726 
727  }
728 
729  }
730 
731  // Write interfile respiratory gating parametric image if required
732  if( m_nbRGModelParam>1 ) // Respiratory gate linear model enabled
733  {
734  // Recover path to output interfile
735  path_to_image = p_output_manager->GetPathName() + p_output_manager->GetBaseName();
736 
737  // Add a suffix for iteration
738  if (a_iteration >= 0)
739  {
740  stringstream ss; ss << a_iteration + 1;
741  path_to_image.append("parRGmodel_it").append(ss.str());
742  }
743 
744  // Add a suffix for subset (if not negative by default), this means that we save a 'subset' image
745  if (a_subset >= 0)
746  {
747  stringstream ss; ss << a_subset + 1;
748  path_to_image.append("_ss").append(ss.str());
749  }
750 
751  if(IntfWriteImgDynCoeffFile(path_to_image,
753  mp_ID,
755  m_verbose) )
756  {
757  Cerr("***** iLinearModel::SaveParametricImages()-> Error writing Interfile of output image !" << endl);
758  return 1;
759  }
760  }
761 
762  // Write interfile cardiac gating parametric image if required
763  if( m_nbCGModelParam>1 ) // Cardiac gate linear model enabled
764  {
765  // Recover path to output interfile
766  path_to_image = p_output_manager->GetPathName() + p_output_manager->GetBaseName();
767 
768  // Add a suffix for iteration
769  if (a_iteration >= 0)
770  {
771  stringstream ss; ss << a_iteration + 1;
772  path_to_image.append("parCGmodel_it").append(ss.str());
773  }
774 
775  // Add a suffix for subset (if not negative by default), this means that we save a 'subset' image
776  if (a_subset >= 0)
777  {
778  stringstream ss; ss << a_subset + 1;
779  path_to_image.append("_ss").append(ss.str());
780  }
781 
782  if(IntfWriteImgDynCoeffFile(path_to_image,
784  mp_ID,
786  m_verbose) )
787  {
788  Cerr("***** iLinearModel::SaveParametricImages()-> Error writing Interfile of output image !" << endl);
789  return 1;
790  }
791  }
792 
793  }
794 
795  return 0;
796 }
797 
798 
799 
800 
801 
802 
803 
804 // =====================================================================
805 // ---------------------------------------------------------------------
806 // ---------------------------------------------------------------------
807 // =====================================================================
808 /*
809  \fn NNLS
810  \param a : On entry, a[ 0... N ][ 0 ... M ] contains the M by N matrix A.\n
811  On exit, a[][] contains the product matrix Q*A, where Q is an m by n \n
812  orthogonal matrix generated implicitly by this function.
813  \param m : Matrix dimension m
814  \param n : Matrix dimension n
815  \param b : On entry, b[] must contain the m-vector B. \n
816  On exit, b[] contains Q*B
817  \param x : On exit, x[] will contain the solution vector
818  \param rnorm : On exit, rnorm contains the Euclidean norm of the residual vector. \n
819  If NULL is given, no rnorm is calculated
820  \param wp: An n-array of working space, wp[]. \n
821  On exit, wp[] will contain the dual solution vector. \n
822  wp[i]=0.0 for all i in set p and wp[i]<=0.0 for all i in set z. \n
823  Can be NULL, which causes this algorithm to allocate memory for it.
824  \param zzp : An m-array of working space, zz[]. \n
825  Can be NULL, which causes this algorithm to allocate memory for it.
826  \param indexp : An n-array of working space, index[]. \n
827  Can be NULL, which causes this algorithm to allocate memory for it. *
828  \brief Implementation of NNLS (non-negative least squares) algorithm
829  Derived from Turku PET center libraries (authors: Vesa Oikonen and Kaisa Sederholm)
830  This routine is based on the text and fortran code in
831  C.L. Lawson and R.J. Hanson, Solving Least Squares Problems,
832  Prentice-Hall, Englewood Cliffs, New Jersey, 1974.
833  \details Given an m by n matrix A, and an m-vector B, computes an n-vector X,
834  that solves the least squares problem
835  A * X = B , subject to X>=0
836 
837  Instead of pointers for working space, NULL can be given to let this
838  function to allocate and free the required memory.
839 
840  \return 0 if success, positive value otherwise
841 */
843  int m,
844  int n,
845  FLTNB *B,
846  FLTNB *X,
847  FLTNB *rnorm,
848  FLTNB *wp,
849  FLTNB *zzp,
850  int *indexp )
851 {
852  int pfeas, iz, jz, iz1, iz2, npp1, *index;
853  FLTNB d1, d2, sm, up, ss, *w, *zz;
854  int iter, k, j=0, l, itmax, izmax=0, nsetp, ii, jj=0, ip;
855  FLTNB temp, wmax, t, alpha, asave, dummy, unorm, ztest, cc;
856 
857  // Check the parameters and data */
858  if(m<=0 || n<=0 || A==NULL || B==NULL || X==NULL)
859  {
860  Cerr("***** vDynamicModel::NNLS()-> Incorrect input parameters !" << endl);
861  return 1;
862  }
863 
864  // Allocate memory for working space, if required
865  if(wp!=NULL) w=wp; else w=(FLTNB*)calloc(n, sizeof(FLTNB));
866  if(zzp!=NULL) zz=zzp; else zz=(FLTNB*)calloc(m, sizeof(FLTNB));
867  if(indexp!=NULL) index=indexp; else index=(int*)calloc(n, sizeof(int));
868 
869  if(w==NULL || zz==NULL || index==NULL)
870  {
871  Cerr("***** vDynamicModel::NNLS()-> Incorrect memory allocation on working space !" << endl);
872  return 1;
873  }
874 
875  // Initialize the arrays INDEX[] and X[]
876  for(k=0; k<n; k++)
877  {
878  X[k] = 0.;
879  index[k] = k;
880  }
881 
882  iz2=n-1; iz1=0; nsetp=0; npp1=0;
883 
884  // Main loop; quit if all coeffs are already in the solution or
885  // if M cols of A have been triangularized
886  iter=0;
887 
888  if(n<3)
889  itmax=n*3;
890  else
891  itmax=n*n;
892 
893  while(iz1<=iz2 && nsetp<m)
894  {
895  // Compute components of the dual (negative gradient) vector W[]
896  for(iz=iz1; iz<=iz2; iz++)
897  {
898  j=index[iz]; sm=0.;
899  for(l=npp1; l<m; l++)
900  sm+=A[j][l]*B[l];
901 
902  w[j]=sm;
903  }
904 
905  while(1)
906  {
907  // Find largest positive W[j] */
908  for(wmax=0., iz=iz1; iz<=iz2; iz++)
909  {
910  j=index[iz];
911  if(w[j]>wmax)
912  {
913  wmax=w[j];
914  izmax=iz;
915  }
916  }
917 
918  // Terminate if wmax<=0.;
919  // it indicates satisfaction of the Kuhn-Tucker conditions
920  if(wmax<=0.0) break;
921 
922  iz=izmax; j=index[iz];
923 
924  // The sign of W[j] is ok for j to be moved to set P.
925  // Begin the transformation and check new diagonal element to avoid
926  // near linear dependence.
927  asave=A[j][npp1]; up=0.0;
928 
929  NNLS_LSS_H12(1, npp1, npp1+1, m, &A[j][0], 1, &up, &dummy, 1, 1, 0);
930 
931  unorm=0.;
932  if(nsetp!=0)
933  for(l=0; l<nsetp; l++)
934  {
935  d1 = A[j][l];
936  unorm+=d1*d1;
937  }
938  unorm=sqrt(unorm);
939  d2 = unorm + (d1=A[j][npp1], fabs(d1)) * 0.01;
940  if( (d2-unorm)>0. )
941  {
942  // Col j is sufficiently independent. Copy B into ZZ, update ZZ
943  // and solve for ztest ( = proposed new value for X[j] )
944  for(l=0; l<m; l++)
945  zz[l]=B[l];
946 
947  NNLS_LSS_H12(2, npp1, npp1+1, m, &A[j][0], 1, &up, zz, 1, 1, 1);
948 
949  ztest = zz[npp1]/A[j][npp1];
950  // See if ztest is positive */
951  if(ztest>0.) break;
952  }
953 
954  // Reject j as a candidate to be moved from set Z to set P.
955  // Restore A[npp1,j], set W[j]=0., and loop back to test dual coeffs again
956  A[j][npp1]=asave;
957  w[j]=0.;
958  } // while(1) */
959 
960  if(wmax<=0.0) break;
961 
962  // Index j=INDEX[iz] has been selected to be moved from set Z to set P.
963  // Update B and indices, apply householder transformations to cols in
964  // new set Z, zero subdiagonal elts in col j, set W[j]=0.
965  for(l=0; l<m; ++l)
966  B[l]=zz[l];
967 
968  index[iz]=index[iz1]; index[iz1]=j; iz1++; nsetp=npp1+1; npp1++;
969 
970  if(iz1<=iz2) for(jz=iz1; jz<=iz2; jz++)
971  {
972  jj=index[jz];
973  NNLS_LSS_H12(2, nsetp-1, npp1, m, &A[j][0], 1, &up, &A[jj][0], 1, m, 1);
974  }
975 
976  if(nsetp!=m) for(l=npp1; l<m; l++) A[j][l]=0.;
977  w[j]=0.;
978 
979  // Solve the triangular system; store the solution temporarily in Z[]
980  for(l=0; l<nsetp; l++)
981  {
982  ip=nsetp-(l+1);
983  if(l!=0)
984  for(ii=0; ii<=ip; ii++)
985  zz[ii] -= A[jj][ii] * zz[ip+1];
986  jj = index[ip];
987  zz[ip] /= A[jj][ip];
988  }
989 
990  // Secondary loop begins here
991  while( ++iter<itmax )
992  {
993  // See if all new constrained coeffs are feasible; if not, compute alpha
994  for(alpha=2.0, ip=0; ip<nsetp; ip++)
995  {
996  l=index[ip];
997  if(zz[ip]<=0.)
998  {
999  t = -X[l] / (zz[ip]-X[l]);
1000  if(alpha>t)
1001  {
1002  alpha=t;
1003  jj=ip-1;
1004  }
1005  }
1006  }
1007 
1008  // If all new constrained coeffs are feasible then still alpha==2.
1009  // If so, then exit from the secondary loop to main loop
1010  if(alpha==2.0) break;
1011 
1012  // Use alpha (0.<alpha<1.) to interpolate between old X and new ZZ
1013  for(ip=0; ip<nsetp; ip++)
1014  {
1015  l = index[ip];
1016  X[l] += alpha*(zz[ip]-X[l]);
1017  }
1018 
1019  // Modify A and B and the INDEX arrays to move coefficient i
1020  // from set P to set Z.
1021  k=index[jj+1]; pfeas=1;
1022  do
1023  {
1024  X[k]=0.;
1025  if(jj!=(nsetp-1))
1026  {
1027  jj++;
1028  for(j=jj+1; j<nsetp; j++)
1029  {
1030  ii=index[j]; index[j-1]=ii;
1031 
1032  NNLS_LSS_G1(A[ii][j-1], A[ii][j], &cc, &ss, &A[ii][j-1]);
1033 
1034  for(A[ii][j]=0., l=0; l<n; l++) if(l!=ii)
1035  {
1036  // Apply procedure G2 (CC,SS,A(J-1,L),A(J,L)) */
1037  temp = A[l][j-1];
1038  A[l][j-1] = cc*temp+ss*A[l][j];
1039  A[l][j] = -ss*temp+cc*A[l][j];
1040  }
1041  // Apply procedure G2 (CC,SS,B(J-1),B(J))
1042  temp=B[j-1]; B[j-1]=cc*temp+ss*B[j]; B[j]=-ss*temp+cc*B[j];
1043  }
1044  }
1045  npp1=nsetp-1; nsetp--; iz1--; index[iz1]=k;
1046 
1047  // See if the remaining coeffs in set P are feasible;
1048  // they should be because of the way alpha was determined.
1049  // If any are infeasible it is due to round-off error.
1050  // Any that are nonpositive will be set to zero and moved from set P to set Z
1051  for(jj=0, pfeas=1; jj<nsetp; jj++)
1052  {
1053  k=index[jj];
1054  if(X[k]<=0.)
1055  {
1056  pfeas=0;
1057  break;
1058  }
1059  }
1060  } while(pfeas==0);
1061 
1062  // Copy B[] into zz[], then solve again and loop back
1063  for(k=0; k<m; k++)
1064  zz[k]=B[k];
1065 
1066  for(l=0; l<nsetp; l++)
1067  {
1068  ip = nsetp-(l+1);
1069  if(l!=0)
1070  for(ii=0; ii<=ip; ii++)
1071  zz[ii] -= A[jj][ii]*zz[ip+1];
1072  jj = index[ip];
1073  zz[ip] /= A[jj][ip];
1074  }
1075  } // end of secondary loop
1076 
1077  // Normal return if we reach max number of iteration.
1078  // Maybe throw warning here
1079  if(iter>=itmax)
1080  return 0;
1081 
1082  for(ip=0; ip<nsetp; ip++)
1083  {
1084  k=index[ip];
1085  X[k]=zz[ip];
1086  }
1087 
1088  } // end of main loop
1089 
1090  // Compute the norm of the final residual vector
1091  sm=0.;
1092 
1093  if(rnorm != NULL)
1094  {
1095  if(npp1<m)
1096  {
1097  for(k=npp1; k<m; k++)
1098  sm+=(B[k]*B[k]);
1099  }
1100  else
1101  {
1102  for(j=0; j<n; j++)
1103  w[j]=0.;
1104  }
1105 
1106  *rnorm=sqrt(sm);
1107  }
1108 
1109  // Free working space, if it was allocated here
1110  if(wp==NULL) free(w);
1111  if(zzp==NULL) free(zz);
1112  if(indexp==NULL) free(index);
1113 
1114  return 0;
1115 }
1116 
1117 
1118 
1119 
1120 
1121 
1122 
1123 
1124 // =====================================================================
1125 // ---------------------------------------------------------------------
1126 // ---------------------------------------------------------------------
1127 // =====================================================================
1128 /*
1129  \fn NNLS_LSS_G1
1130  \param mode : mode=1 to construct and apply a Householder transformation, or \n
1131  mode=2 to apply a previously constructed transformation
1132  \param lpivot: Index of the pivot element, on pivot vector
1133  \param l1: Transformation is constructed to zero elements indexed from l1 to M
1134  \param m: Transformation is constructed to zero elements indexed from l1 to M
1135  \param u: With mode=1: On entry, u[] must contain the pivot vector.
1136  On exit, u[] and up contain quantities defining
1137  the vector u[] of the Householder transformation.
1138  With mode=2: On entry, u[] and up should contain quantities previously
1139  computed with mode=1. These will not be modified
1140  \param u_dim1: u_dim1 is the storage increment between elements
1141  \param up: with mode=1, here is stored an element defining housholder vector scalar,
1142  on mode=2 it's only used, and is not modified
1143  \param cm: On entry, cm[] must contain the matrix (set of vectors) to which the
1144  Householder transformation is to be applied.
1145  On exit, cm[] will contain the set of transformed vectors
1146  \param ice: Storage increment between elements of vectors in cm[]
1147  \param icv: Storage increment between vectors in cm[]
1148  \param nvc: Nr of vectors in cm[] to be transformed;
1149  if ncv<=0, then no operations will be done on cm[]
1150  \brief Construction and/or application of a single Householder transformation:
1151  Q = I + U*(U**T)/B
1152  Derived from Turku PET center libraries (authors: Vesa Oikonen and Kaisa Sederholm)
1153  This routine is based on the text and fortran code in
1154  C.L. Lawson and R.J. Hanson, Solving Least Squares Problems,
1155  Prentice-Hall, Englewood Cliffs, New Jersey, 1974.
1156  \return 0 if success, positive value otherwise (erroneous parameters)
1157 */
1159  int lpivot,
1160  int l1,
1161  int m,
1162  FLTNB *u,
1163  int u_dim1,
1164  FLTNB *up,
1165  FLTNB *cm,
1166  int ice,
1167  int icv,
1168  int ncv
1169 )
1170 {
1171  FLTNB d1, b, clinv, cl, sm;
1172  int k, j;
1173 
1174  /* Check parameters */
1175  if(mode!=1 && mode!=2) return(1);
1176  if(m<1 || u==NULL || u_dim1<1 || cm==NULL) return(1);
1177  if(lpivot<0 || lpivot>=l1 || l1>m) return(1);
1178 
1179  /* Function Body */
1180  cl = fabs(u[lpivot*u_dim1]);
1181  // cl= (d1 = u[lpivot*u_dim1], fabs(d1));
1182 
1183  if(mode==2) { /* Apply transformation I+U*(U**T)/B to cm[] */
1184  if(cl<=0.) return(0);
1185  } else { /* Construct the transformation */
1186 
1187  /* trying to compensate overflow */
1188  for(j=l1; j<m; j++) { // Computing MAX
1189  cl = fmax(fabs(u[j*u_dim1]), cl);
1190  }
1191  // zero vector?
1192  if(cl<=0.) return(0);
1193 
1194  clinv=1.0/cl;
1195 
1196  // Computing 2nd power
1197  d1=u[lpivot*u_dim1]*clinv;
1198  sm=d1*d1;
1199  for(j=l1; j<m; j++) {
1200  d1=u[j*u_dim1]*clinv;
1201  sm+=d1*d1;
1202  }
1203  cl*=sqrt(sm);
1204  // cl = sqrt( (u[pivot]*clinv)^2 + sigma(i=l1..m)( (u[i]*clinv)^2 ) )
1205  if(u[lpivot*u_dim1] > 0.) cl=-cl;
1206  *up = u[lpivot*u_dim1] - cl;
1207  u[lpivot*u_dim1]=cl;
1208  }
1209 
1210  // no vectors where to apply? only change pivot vector!
1211  b=(*up)*u[lpivot*u_dim1];
1212 
1213  /* b must be nonpositive here; if b>=0., then return */
1214  if(b>=0.0) return(0); // was if(b==0) before 2013-06-22
1215 
1216  // ok, for all vectors we want to apply
1217  for(j=0; j<ncv; j++) {
1218  // take s = c[p,j]*h + sigma(i=l..m){ c[i,j] *v [ i ] }
1219  sm = cm[ lpivot*ice + j*icv ] * (*up);
1220  for(k=l1; k<m; k++) sm += cm[ k * ice + j*icv ] * u[ k*u_dim1 ];
1221  if(sm!=0.0) {
1222  sm *= (1.0/b); // was (1/b) before 2013-06-22
1223  // cm[lpivot, j] = ..
1224  cm[ lpivot * ice + j*icv] += sm*(*up);
1225  // for i = l1...m , set c[i,j] = c[i,j] + s*v[i]
1226  for(k=l1; k<m; k++) cm[ k*ice + j*icv] += u[k * u_dim1]*sm;
1227  }
1228  }
1229 
1230  return(0);
1231 }
1232 
1233 
1234 
1235 
1236 // =====================================================================
1237 // ---------------------------------------------------------------------
1238 // ---------------------------------------------------------------------
1239 // =====================================================================
1240 /*
1241  \fn NNLS_LSS_G1
1242  \param a
1243  \param b
1244  \param cterm
1245  \param sterm
1246  \param sig: sig = sqrt(A**2+B**2)
1247  \brief Compute orthogonal rotation matrix:
1248  (C, S) so that (C, S)(A) = (sqrt(A**2+B**2))
1249  (-S,C) (-S,C)(B) ( 0 )
1250  sig is computed last to allow for the possibility that sig may be in
1251  the same location as A or B.
1252  Derived from Turku PET center libraries (authors: Vesa Oikonen and Kaisa Sederholm)
1253  This routine is based on the text and fortran code in
1254  C.L. Lawson and R.J. Hanson, Solving Least Squares Problems,
1255  Prentice-Hall, Englewood Cliffs, New Jersey, 1974.
1256 */
1257 void vDynamicModel::NNLS_LSS_G1(FLTNB a, FLTNB b, FLTNB *cterm, FLTNB *sterm, FLTNB *sig)
1258 {
1259  FLTNB d1, xr, yr;
1260 
1261  if(fabs(a)>fabs(b))
1262  {
1263  xr=b/a; d1=xr; yr=sqrt(d1*d1 + 1.); d1=1./yr;
1264  *cterm=(a>=0.0 ? fabs(d1) : -fabs(d1));
1265  *sterm=(*cterm)*xr; *sig=fabs(a)*yr;
1266  }
1267  else if(b!=0.)
1268  {
1269  xr=a/b; d1=xr; yr=sqrt(d1*d1 + 1.); d1=1./yr;
1270  *sterm=(b>=0.0 ? fabs(d1) : -fabs(d1));
1271  *cterm=(*sterm)*xr; *sig=fabs(b)*yr;
1272  }
1273  else
1274  {
1275  *sig=0.; *cterm=0.; *sterm=1.;
1276  }
1277 }
virtual int CheckSpecificParameters()=0
This function is used to check the parameters of the child functions before initialization if require...
#define INTF_LERP_DISABLED
void NNLS_LSS_G1(FLTNB a, FLTNB b, FLTNB *cterm, FLTNB *sterm, FLTNB *sig)
int NNLS(FLTNB **A, int m, int n, FLTNB *B, FLTNB *X, FLTNB *rnorm, FLTNB *wp, FLTNB *zzp, int *indexp)
virtual int CheckParameters()
This function is used to check parameters after the latter have been all set using Set functions...
int IntfWriteImgDynCoeffFile(const string &a_pathToImg, FLTNB **a2p_ImgMatrix, oImageDimensionsAndQuantification *ap_ID, int a_nbParImgs, int vb, bool a_mergeDynImgFlag=false)
virtual int EstimateImageWithModel(oImageSpace *ap_Image, int a_ite, int a_sset)=0
virtual int InitializeSpecific()=0
A private function used to initialize everything specific to the child model.
FLTNB GetVoxSizeX()
Get the voxel&#39;s size along the X axis, in mm.
#define Cerr(MESSAGE)
FLTNB GetFOVOutPercent()
Get the percentage of transaxial unmasked FOV.
oImageDimensionsAndQuantification * mp_ID
void ShowHelp()
This function is used to print out general help about dynamic models.
int ReadAndCheckConfigurationFile(string a_fileOptions)
int NNLS_LSS_H12(int mode, int lpivot, int l1, int m, FLTNB *u, int u_dim1, FLTNB *up, FLTNB *cm, int ice, int icv, int ncv)
int InterpolateAIC()
This function performs a linear interpolation within the provided AIC range for every discrete unit o...
virtual int ApplyOutputFOVMaskingOnParametricImages()
Mask the outside of the transaxial FOV based on the m_fovOutPercent.
void Exit(int code)
static sOutputManager * GetInstance()
Instanciate the singleton object and Initialize member variables if not already done, return a pointer to this object otherwise.
int IntfWriteImgFile(const string &a_pathToImg, FLTNB *ap_ImgMatrix, const Intf_fields &ap_IntfF, int vb)
Main function dedicated to Interfile 3D image writing. Recover image information from a provided In...
virtual int EstimateImage(oImageSpace *ap_Image, int a_ite, int a_sset)
FLTNB GetVoxSizeY()
Get the voxel&#39;s size along the Y axis, in mm.
int IntfReadImage(const string &a_pathToHeaderFile, FLTNB *ap_ImgMatrix, oImageDimensionsAndQuantification *ap_ID, int vb, bool a_lerpFlag)
Main function dedicated to Interfile 3D image loading.
virtual int EstimateModel(oImageSpace *ap_Image, int a_ite, int a_sset)
void SetInputFilePath(const string &a_pathToAICfile)
Singleton class that manages output writing on disk (images, sinograms, etc). It also manages loggi...
virtual int ReadAndCheckConfigurationFileSpecific()=0
This function is used to read options from a configuration file. It is pure virtual so must be impl...
int InitializeInputData()
This function is used to initialize the input arterial curve samples from the file provided by the us...
int Initialize()
A public function used to initialize the dynamic model.
#define KEYWORD_OPTIONAL
virtual ~vDynamicModel()
Destructor of vDynamicModel.
vDynamicModel()
Constructor of vDynamicModel. Simply set all data members to default values.
virtual int EstimateModelParameters(oImageSpace *ap_Image, int a_ite, int a_sset)=0
oArterialInputCurve * mp_ArterialInputCurve
This class holds all the matrices in the image domain that can be used in the algorithm: image...
void SetFrames(int a_nbTimeFrames, uint32_t *a_frameTimeStartInMs, uint32_t *a_frameTimeStopInMs)
int CheckParameters()
This function is used to check that the required input parameters are provided from the file provided...
INTNB GetNbVoxX()
Get the number of voxels along the X axis.
INTNB GetNbVoxZ()
Get the number of voxels along the Z axis.
virtual void ComputeOutputParImage()
Compute output image using the m2p_parametricImages matrix Store the result in the m2p_outputParImage...
int ReadDataASCIIFile(const string &a_file, const string &a_keyword, T *ap_return, int a_nbElts, bool a_mandatoryFlag)
Look for "a_nbElts" elts in the "a_file" file matching the "a_keyword" string passed as parameter a...
#define Cout(MESSAGE)
int SaveParametricImages(int a_iteration, int a_subset=-1)
This class is designed to manage the Arterial Input Curve provided by the user.
INTNB GetNbSliceOutMask()
Get the number of extrem slices that will be masked at each side.
INTNB GetNbVoxY()
Get the number of voxels along the Y axis.