Tomato
OxSignCalculatorShmolli.h
Go to the documentation of this file.
1 
7 #ifndef Tomato_OXSIGNCALCULATORSHMOLLI_H
8 #define Tomato_OXSIGNCALCULATORSHMOLLI_H
9 
10 #include "OxSignCalculator.h"
11 #include "KWUtil.h"
12 
13 namespace Ox {
14 
21  template< typename MeasureType >
22  class SignCalculatorShmolli : public SignCalculator<MeasureType> {
23 
24  public:
25  virtual int calculateSign(){
26  int IsPhaseOK = SKPPhase2Signs(
27  this->getNSamples(),
28  this->getInvTimes(),
29  this->getSigMag(),
30  this->getSigPha(),
31  this->getSignal(),
32  this->getSigns(),
33  this->getPhaMin(),
34  this->getPhaMax());
35  for (int i = 0; i < this->getNSamples(); ++i) {
36  if (this->getSigns()[i] != 0) {
37  this->getSignal()[i] = this->getSigns()[i] * (this->getSigMag()[i]);
38  }
39  }
40  return IsPhaseOK;
41  };
42 
43  static int SKPPhase2Signs(
44  int nSamples,
45  const MeasureType* invTimes,
46  const MeasureType* sigMag,
47  const MeasureType* sigPha,
48  MeasureType* signal,
49  MeasureType* signs,
50  MeasureType phaMin,
51  MeasureType phaMax
52  );
53 
54  virtual double getPhaMin() { return _phaMin; }
55  virtual double getPhaMax() { return _phaMax; }
56 
57  virtual void setPhaMin(int _phaMin) { SignCalculatorShmolli::_phaMin = _phaMin; }
58  virtual void setPhaMax(int _phaMax) { SignCalculatorShmolli::_phaMax = _phaMax; }
59 
64  this->setAllPointersToNull();
65  this->_nSamples = 0;
66  this->_phaMin = -4096;
67  this->_phaMax = 4096;
68  };
69 
74  this->setAllPointersToNull();
75  this->_nSamples = old._nSamples;
76  this->_phaMin = old._phaMin;
77  this->_phaMax = old._phaMax;
78  };
79 
85 
86 
87  protected:
88  double _phaMin;
89  double _phaMax;
90  const static int MAX_MOLLI_TI_SAMPLES = 128;
91  const static int MAX_T1_TRESHOLD = 4000;
92 
93 // /**
94 // * \brief do not forget about the virtual destructor, see
95 // * https://stackoverflow.com/questions/461203/when-to-use-virtual-destructors
96 // */
97 // virtual ~SignCalculatorShmolli(){};
98  };
99 
100  template<typename MeasureType>
101  int
104  int nSamples,
105  const MeasureType* invTimes,
106  const MeasureType* sigMag,
107  const MeasureType* sigPha,
108  MeasureType* signal,
109  MeasureType* signs,
110  MeasureType phaMin,
111  MeasureType phaMax) {
112  // takes all samples sorted from shortest to longest TI, returns 0 if clear problems identified to allow rejection of data based on incosistent signs.
113  // note: logic for correction of signs works for ShMOLLI, should work for most basic T1_MOLLI variants too. but not fully tested.
114  //std::cout << "a" << std::endl;
115 
116  KWUtil::copyArrayToArray(nSamples, signal, sigMag);
117 
118  double MaxTIForSignInvert = (MAX_T1_TRESHOLD * 0.67);
119 
120  //double _phaMin = -4096;
121  //double _phaMax = 4096;
122  double zeroRangeFraction = 0.3; // marks size of uncertaintey of corossover between signs. The signs in this zone will be decided by brute force. 0.1 (few doubts) 1 - all phase info doubtful ,0.3 is about right.
123  double PIrange = (phaMax - phaMin) / 2; // scale to make one pi=~3.14 phase rotation // KW on dicoms *2
124  double PI05 = PIrange * 0.5;
125  double PIx2 = PIrange * 2;
126  int IsPhaseErrorFound = 0;
127 
128  double upmap[MAX_MOLLI_TI_SAMPLES]; // phase normalised
129  double PhaseAway[MAX_MOLLI_TI_SAMPLES]; // phase normalised
130  //int asign[MAX_MOLLI_TI_SAMPLES] ; // signs estimate
131  int nsignspositive = 0;
132  int nsignsnegative = 0;
133 
134  for (int i = 0; i < nSamples; i++) {
135  upmap[i] = fmod(PIx2 + sigPha[i] - sigPha[0], PIx2); // make sure within 2*pi
136  PhaseAway[i] = fabs(upmap[i] - PIrange); // away from positive signs of first smaple+PI
137  PhaseAway[i] = ((PI05 - PhaseAway[i]) /
138  (zeroRangeFraction * PI05)); // =How many times outsede midzone grey area around PI/2
139  if (PhaseAway[i] < -1) {
140  signs[i] = -1;
141  nsignsnegative++;
142  }
143  else if (PhaseAway[i] > 1) {
144  signs[i] = 1;
145  nsignspositive++;
146  }
147  else signs[i] = 0;
148  if ((signs[i] < 0) && (invTimes[i] > MaxTIForSignInvert)) // detect obvious pahse problems
149  {
150  IsPhaseErrorFound = 1;// wrong- found clear engative sign for for long TI
151  signs[i] = 1; // corect problem in case recon is atempted, // depends on IsAbortreconOnPhaseErrors
152  }
153  }
154  if ((nsignspositive == 0) || (nsignsnegative == 0)) // suspicious, no positive signs were found
155  {
156  // basic solution for (i = 0;i < n;i++)signs[i]=0; // dont bother guessing, leave to brute force...
158  // sceanrios
165 
168  if (invTimes[nSamples - 1] > MaxTIForSignInvert) {
169  for (int i = 0; i < nSamples; i++) signs[i] = 1;
170  return (1); // loks like conssitent all positive signs
171  }
174  double y1andlast4[MAX_MOLLI_TI_SAMPLES];
175  double x1andlast4[MAX_MOLLI_TI_SAMPLES];
176  double R1andlast4 = 0;
177  double dummySl, dummyOff;
178  y1andlast4[0] = sigMag[0];
179  x1andlast4[0] = invTimes[0];
180  for (int i = 0; i < 4; i++)
181  y1andlast4[i + 1] = sigMag[nSamples - 1 - i]; // order reversed, does not amtter for regression
182  for (int i = 0; i < 4; i++)
183  x1andlast4[i + 1] = invTimes[nSamples - 1 - i]; // order reversed, does not matter for regression
184  //double MOLLI_LinReg(double *x,double *y, int n, double &rslope, double &roffset)
185  R1andlast4 = KWUtil::SKPLinReg(x1andlast4, y1andlast4, 5, dummySl, dummyOff);
186  if (R1andlast4 <
187  (-0.2)) // !!!note arbitrary threshold below zero toa void noise but not too far to account for curvature. !!!!Not validated but this is digging into noise/saving few pixels, should carry no impact.
188  {
189  for (int i = 0; i < nSamples; i++)signs[i] = -1;
190  return (1); // loks like conssitent all negative signs, with high heart rate
191  }
193  double Rfirst4 = KWUtil::SKPLinReg(invTimes, sigMag, 4, dummySl, dummyOff);
194  double Rlast4 = KWUtil::SKPLinReg(invTimes + nSamples - 4,
195  sigMag + nSamples - 4, 4, dummySl, dummyOff);
196  if ((Rfirst4 > Rlast4) && (Rfirst4 > R1andlast4)) {
197  for (int i = 0; i < nSamples; i++) signs[i] = 1;
198  return (1); // loks like conssitent all positive signs, with high heart rate
199  }
200 
202  for (int i = 0; i < nSamples; i++) signs[i] = 1;
203  return (0);
204  }
205  return (!IsPhaseErrorFound);
206  }
207 
208 } //namespace Ox
209 
210 #endif //Tomato_OXSIGNCALCULATOR_H
SignCalculatorShmolli(const SignCalculatorShmolli &old)
copy constructor
Definition: OxSignCalculatorShmolli.h:73
virtual int calculateSign()
Definition: OxSignCalculatorShmolli.h:25
virtual SignCalculator< MeasureType > * newByCloning()
Definition: OxSignCalculatorShmolli.h:84
static int SKPPhase2Signs(int nSamples, const MeasureType *invTimes, const MeasureType *sigMag, const MeasureType *sigPha, MeasureType *signal, MeasureType *signs, MeasureType phaMin, MeasureType phaMax)
Definition: OxSignCalculatorShmolli.h:103
void setAllPointersToNull()
set all the pointers to zero
Definition: OxSignCalculator.h:84
Definition: OxSignCalculator.h:21
Definition: OxCalculator.h:19
SignCalculatorShmolli()
constructor
Definition: OxSignCalculatorShmolli.h:63
Definition: OxSignCalculatorShmolli.h:22