ANIMA  4.0
animaPatientToGroupComparisonImageFilter.hxx
Go to the documentation of this file.
1 #pragma once
3 
4 #include <itkImageRegionIterator.h>
5 #include <itkImageRegionIteratorWithIndex.h>
6 #include <itkImageRegionConstIterator.h>
7 #include <itkImageRegionConstIteratorWithIndex.h>
8 #include <itkSymmetricEigenAnalysis.h>
9 
10 #include <boost/math/distributions/fisher_f.hpp>
11 #include <boost/math/distributions/chi_squared.hpp>
12 
13 #include <itkTimeProbe.h>
14 
15 namespace anima
16 {
17 
18 template <class PixelScalarType>
19 void
22 {
23  Superclass::BeforeThreadedGenerateData();
24  // Checking consistency of the data and parameters
25 
26  unsigned int nbInputs = this->GetNumberOfIndexedInputs();
27 
28  if (nbInputs <= 0)
29  itkExceptionMacro("Error: No inputs available...");
30 
31  unsigned int ndim = this->GetInput(0)->GetNumberOfComponentsPerPixel();
32 
33  if (m_NumEigenValuesPCA > ndim)
34  m_NumEigenValuesPCA = ndim;
35 
36  if (m_DatabaseImages.size() <= this->GetInput(0)->GetNumberOfComponentsPerPixel())
37  itkExceptionMacro("Error: Not enough inputs available...");
38 }
39 
40 template <class PixelScalarType>
41 void
44 {
45  typedef itk::ImageRegionConstIteratorWithIndex< InputImageType > InIteratorType;
46 
47  typedef itk::ImageRegionIteratorWithIndex< OutputImageType > OutRegionIteratorType;
48  typedef itk::ImageRegionConstIteratorWithIndex < MaskImageType > MaskRegionIteratorType;
49 
50  OutRegionIteratorType outIterator(this->GetOutput(0), outputRegionForThread);
51  OutRegionIteratorType outPValIterator(this->GetOutput(1), outputRegionForThread);
52  MaskRegionIteratorType maskIterator (this->GetComputationMask(), outputRegionForThread);
53 
54  unsigned int numSamplesDatabase = m_DatabaseImages.size();
55  std::vector < InIteratorType > databaseIterators;
56  InIteratorType patientIterator(this->GetInput(0), outputRegionForThread);
57 
58  for (unsigned int i = 0;i < numSamplesDatabase;++i)
59  databaseIterators.push_back(InIteratorType(m_DatabaseImages[i],outputRegionForThread));
60 
61  unsigned int ndim = this->GetInput(0)->GetNumberOfComponentsPerPixel();
62  CovMatrixType tmpCovMatrix(ndim,ndim), tmpCovMatrixInv;
63  VectorType tmpMean(ndim);
64 
65  std::vector < VectorType > databaseValues(numSamplesDatabase);
66  VectorType patientVectorValue;
67 
68  while (!outIterator.IsAtEnd())
69  {
70  patientVectorValue = patientIterator.Get();
71  ndim = patientVectorValue.GetSize();
72 
73  if ((maskIterator.Get() == 0)||(this->isZero(patientVectorValue)))
74  {
75  outIterator.Set(0.0);
76  outPValIterator.Set(0.0);
77  ++outIterator;
78  ++outPValIterator;
79  ++maskIterator;
80  ++patientIterator;
81 
82  for (unsigned int i = 0;i < numSamplesDatabase;++i)
83  ++databaseIterators[i];
84 
85  continue;
86  }
87 
88  databaseValues.resize(numSamplesDatabase);
89 
90  unsigned int numEffectiveSamples = 0;
91  for (unsigned int i = 0;i < numSamplesDatabase;++i)
92  {
93  databaseValues[numEffectiveSamples] = databaseIterators[i].Get();
94  if (!this->isZero(databaseValues[numEffectiveSamples]))
95  numEffectiveSamples++;
96  }
97 
98  databaseValues.resize(numEffectiveSamples);
99 
100  ndim = this->SampleFromDiffusionModels(databaseValues,patientVectorValue);
101  unsigned int ndim_afterpca = ndim;
102 
103  if ((m_NumEigenValuesPCA < ndim)||(m_ExplainedRatio < 1))
104  ndim_afterpca = this->GetPCAVectorsFromData(databaseValues,patientVectorValue);
105 
106  if (numEffectiveSamples <= ndim_afterpca)
107  {
108  outIterator.Set(0.0);
109  outPValIterator.Set(0.0);
110  ++outIterator;
111  ++outPValIterator;
112  ++maskIterator;
113  ++patientIterator;
114 
115  for (unsigned int i = 0;i < numSamplesDatabase;++i)
116  ++databaseIterators[i];
117 
118  continue;
119  }
120 
121  tmpCovMatrix.set_size(ndim_afterpca,ndim_afterpca);
122  tmpCovMatrix.fill(0);
123  tmpMean.SetSize(ndim_afterpca);
124  tmpMean.Fill(0);
125 
126  for (unsigned int i = 0;i < numEffectiveSamples;++i)
127  {
128  for (unsigned int j = 0;j < ndim_afterpca;++j)
129  tmpMean[j] += databaseValues[i][j];
130  }
131 
132  tmpMean /= numEffectiveSamples;
133 
134  for (unsigned int i = 0;i < numEffectiveSamples;++i)
135  {
136  for (unsigned int j = 0;j < ndim_afterpca;++j)
137  for (unsigned int k = j;k < ndim_afterpca;++k)
138  tmpCovMatrix(j,k) += (databaseValues[i][j] - tmpMean[j])*(databaseValues[i][k] - tmpMean[k]);
139  }
140 
141  for (unsigned int j = 0;j < ndim_afterpca;++j)
142  for (unsigned int k = j;k < ndim_afterpca;++k)
143  {
144  tmpCovMatrix(j,k) /= (numEffectiveSamples - 1.0);
145  if (j != k)
146  tmpCovMatrix(k,j) = tmpCovMatrix(j,k);
147  }
148 
149  vnl_matrix_inverse <double> matrixInverter(tmpCovMatrix);
150  tmpCovMatrixInv = matrixInverter.inverse();
151 
152  double resValue = 0;
153 
154  for (unsigned int i = 0;i < ndim_afterpca;++i)
155  for (unsigned int j = i;j < ndim_afterpca;++j)
156  {
157  // This is because we are working only on triangular superior for being faster
158  // The input data has to be in the right log-vector form
159  double factor = 2.0;
160  if (i == j)
161  factor = 1;
162 
163  resValue += factor*tmpCovMatrixInv(i,j)*(patientVectorValue[i] - tmpMean[i])*(patientVectorValue[j] - tmpMean[j]);
164  }
165 
166  switch (m_StatisticalTestType)
167  {
168  case FISHER:
169  {
170  double testScore = numEffectiveSamples * (numEffectiveSamples - ndim_afterpca) * resValue / ((numEffectiveSamples * numEffectiveSamples - 1) * ndim_afterpca);
171  boost::math::fisher_f_distribution <double> fisherDist(ndim_afterpca,numEffectiveSamples - ndim_afterpca);
172  outPValIterator.Set (1.0 - boost::math::cdf(fisherDist, testScore));
173  break;
174  }
175 
176  case CHI_SQUARE:
177  default:
178  {
179  boost::math::chi_squared_distribution <double> chiDist(ndim_afterpca);
180  outPValIterator.Set (1.0 - boost::math::cdf(chiDist, resValue));
181  break;
182  }
183  }
184 
185  resValue = sqrt(resValue);
186  // If scalar values, put a sign on out z-score
187  if (ndim == 1)
188  {
189  if (tmpMean[0] > patientVectorValue[0])
190  resValue *= -1;
191  }
192 
193  this->IncrementNumberOfProcessedPoints();
194  outIterator.Set(resValue);
195  ++outIterator;
196  ++outPValIterator;
197  ++maskIterator;
198  ++patientIterator;
199 
200  for (unsigned int i = 0;i < numSamplesDatabase;++i)
201  ++databaseIterators[i];
202  }
203 }
204 
205 
206 template <class PixelScalarType>
207 unsigned int
209 ::GetPCAVectorsFromData(std::vector < itk::VariableLengthVector <double> > &databaseVectors,
210  itk::VariableLengthVector <double> &patientVectorValue)
211 {
212  unsigned int refNDim = patientVectorValue.GetSize();
213  vnl_matrix <double> allCovarianceMatrix(refNDim,refNDim);
214 
215  for (unsigned int i = 0;i < refNDim;++i)
216  for (unsigned int j = 0;j < refNDim;++j)
217  allCovarianceMatrix(i,j) = 0;
218 
219  unsigned int numData = databaseVectors.size();
220  std::vector <double> dataMean(refNDim,0);
221 
222  for (unsigned int i = 0;i < numData;++i)
223  for (unsigned int j = 0;j < refNDim;++j)
224  dataMean[j] += databaseVectors[i][j];
225 
226  for (unsigned int j = 0;j < refNDim;++j)
227  dataMean[j] /= numData;
228 
229  for (unsigned int i = 0;i < numData;++i)
230  for (unsigned int j = 0;j < refNDim;++j)
231  for (unsigned int k = j;k < refNDim;++k)
232  allCovarianceMatrix(j,k) += (databaseVectors[i][j] - dataMean[j])*(databaseVectors[i][k] - dataMean[k]);
233 
234  for (unsigned int j = 0;j < refNDim;++j)
235  for (unsigned int k = j;k < refNDim;++k)
236  {
237  allCovarianceMatrix(j,k) /= (numData - 1.0);
238  if (j != k)
239  allCovarianceMatrix(k,j) = allCovarianceMatrix(j,k);
240  }
241 
242  vnl_matrix <double> eigenVectors(refNDim,refNDim);
243  vnl_diag_matrix <double> eigenValues(refNDim);
244 
245  itk::SymmetricEigenAnalysis <vnl_matrix <double>, vnl_diag_matrix <double>, vnl_matrix <double> > EigenAnalysis(refNDim);
246  EigenAnalysis.SetOrderEigenValues(true);
247  EigenAnalysis.ComputeEigenValuesAndVectors(allCovarianceMatrix,eigenValues,eigenVectors);
248 
249  double sumEigVal = 0;
250  for (unsigned int i = 0;i < refNDim;++i)
251  sumEigVal += eigenValues[i];
252 
253  unsigned int outNDim = 0;
254  double cumulEigs = 0;
255  while (cumulEigs/sumEigVal < m_ExplainedRatio)
256  {
257  cumulEigs += eigenValues[refNDim - 1 - outNDim];
258  ++outNDim;
259  }
260 
261  if (outNDim < m_NumEigenValuesPCA)
262  outNDim = m_NumEigenValuesPCA;
263 
264  vnl_matrix <double> basisMatrix(outNDim,refNDim);
265  for (unsigned int i = 0;i < outNDim;++i)
266  for (unsigned int j = 0;j < refNDim;++j)
267  basisMatrix(i,j) = eigenVectors(refNDim - 1 - i,j);
268 
269  itk::VariableLengthVector <double> tmpVec, resData(outNDim);
270  for (unsigned int i = 0;i < numData;++i)
271  {
272  tmpVec = databaseVectors[i];
273  for (unsigned int j = 0;j < outNDim;++j)
274  {
275  resData[j] = 0;
276  for (unsigned int k = 0;k < refNDim;++k)
277  resData[j] += basisMatrix(j,k)*(tmpVec[k] - dataMean[k]);
278  }
279 
280  databaseVectors[i] = resData;
281  }
282 
283  for (unsigned int j = 0;j < outNDim;++j)
284  {
285  resData[j] = 0;
286  for (unsigned int k = 0;k < refNDim;++k)
287  resData[j] += basisMatrix(j,k)*(patientVectorValue[k] - dataMean[k]);
288  }
289 
290  patientVectorValue = resData;
291 
292  return outNDim;
293 }
294 
295 template <class PixelScalarType>
296 bool
298 ::isZero(const VectorType &vec)
299 {
300  unsigned int ndim = vec.Size();
301 
302  for (unsigned int i = 0;i < ndim;++i)
303  {
304  if (vec[i] != 0)
305  return false;
306  }
307 
308  return true;
309 }
310 
311 } //end namespace anima
void DynamicThreadedGenerateData(const OutputImageRegionType &outputRegionForThread) ITK_OVERRIDE
Implements patient to group comparison as in http://dx.doi.org/10.1007/978-3-540-85988-8_116.