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