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