aimsalgo  5.1.2
Neuroimaging image processing
discriminantanalysis_d.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
34 
35 #include <aims/math/svd.h>
36 #include <aims/math/mathelem.h>
37 #include <aims/math/random.h>
38 #include <aims/math/gausslu.h>
40 #include <aims/io/writer.h>
41 
42 namespace aims
43 {
44 
46  _significantEV(significantEV), _computed(false), _dataScaleFactor(1.),
47  _probaScaleFactor(1.), _PIj(PIj), _detVarCov(1.),
48  _normFactor(1.), _lnAddFactor(0.)
49 {
50 
51 }
52 
53 template <typename T>
54 void
56  const std::list< Point3d >& selectedPoints,
57  const carto::rc_ptr<carto::Volume<T> >& data )
58 {
59  carto::VolumeRef<T> individuals( std::max(int(selectedPoints.size()), 1),
60  data->getSizeT(), 1, 1,
61  carto::AllocatorContext::fast() );
62  int i = 0 ;
63  std::list< Point3d >::const_iterator iter( selectedPoints.begin() ), last( selectedPoints.end() ) ;
64  Point3df mean ;
65 
66  _indivPosition = std::vector<Point3d>( selectedPoints.size() ) ;
67  while( iter != last ){
68  _indivPosition[ i ] = *iter ;
69  for(int t = 0 ; t < data->getSizeT() ; ++t )
70  individuals( i, t ) = T(data->at( (*iter)[0], (*iter)[1], (*iter)[2], t ) ) ;
71  ++i ; ++iter ;
72  //cout << "Indiv " << i << " = " << *iter << endl ;
73  mean += Point3df( (*iter)[0], (*iter)[1], (*iter)[2] ) ;
74  }
75  //cout << "Center = " << mean / float( individuals->getSizeX() ) << endl ;
76  doIt( individuals ) ;
77 }
78 
79 template <typename T>
80 void
82  const carto::rc_ptr<carto::Volume<T> >& individuals )
83 {
84  _computed = true ;
85  int nbFrame = individuals->getSizeY() ;
86 
87  carto::VolumeRef<double> centeredIndivMatrix(
88  individuals->getSizeX(), individuals->getSizeY(), 1, 1,
89  carto::AllocatorContext::fast() );
90  _mean = carto::VolumeRef<double>( individuals->getSizeY(), 1, 1, 1,
91  carto::AllocatorContext::fast() );
92  _mean = 0 ;
93  T val ;
94  for( int ind = 0 ; ind < individuals->getSizeX() ; ++ind )
95  for( int t = 0 ; t < individuals->getSizeY() ; ++t ){
96  val = individuals->at( ind, t ) ;
97  _mean(t) += val ;
98  }
99 
100  //TEMP
101  double meanMean = 0. ;
102  //END TEMP
103 
104  for( int t = 0 ; t < nbFrame ; ++t )
105  {
106  _mean(t) = _mean(t) / centeredIndivMatrix->getSizeX() ;
107  for( int ind = 0 ; ind < centeredIndivMatrix->getSizeX() ; ++ind )
108  {
109  centeredIndivMatrix( ind, t ) = individuals->at( ind, t ) - _mean(t) ;
110  meanMean += centeredIndivMatrix( ind, t ) ;
111  }
112  }
113 
114  // Matrice des correlations
115  carto::VolumeRef<double> matVarCov(centeredIndivMatrix->getSizeY(), centeredIndivMatrix->getSizeY() ) ;
116  int x1, y1, dx1 = matVarCov->getSizeX(), dy1 = matVarCov->getSizeY();
117 
118  for( y1=0; y1<dy1; ++y1 )
119  for( x1=0; x1<dx1; ++x1 )
120  {
121  for(int k=0; k < centeredIndivMatrix->getSizeX() ;++k)
122  matVarCov(x1, y1) += centeredIndivMatrix(k, x1) * centeredIndivMatrix(k, y1);
123  matVarCov(x1, y1) /= centeredIndivMatrix->getSizeX() - 1 ;
124  }
125 
126  //Writer< carto::rc_ptr<carto::Volume<double> > > wriMatVarCov("matVarCov.ima") ;
127  //wriMatVarCov.write( matVarCov ) ;
128 
129  carto::VolumeRef< double > u = matVarCov.deepcopy(); // because it is replaced on SVD output
131  matVarCov->getSizeY(), matVarCov->getSizeY(), 1, 1,
132  carto::AllocatorContext::fast() );
133 
134  AimsSVD< double > svd2;
135  carto::VolumeRef< double > w = svd2.doit( u, &v );
136  //svd2.sort(u, w, &v) ;
137 
138  carto::VolumeRef<double> invW( w.getSizeX(), w.getSizeY(), 1, 1,
139  carto::AllocatorContext::fast() ) ;
140 
141  // JUST FOR SOCIETY FOR MOLECULAR IMAGING
142 // int indMax = 0 ;
143  double sig2 = 0. ;
144 // for( int i = 1 ; i < w->getSizeX() ; ++i )
145 // if( w(i, i) > w(indMax, indMax) )
146 // indMax = i ;
147  for( int i = _significantEV ; i < w.getSizeX() ; ++i ){
148  sig2 += w(i, i) ;
149  }
150  sig2 /= w.getSizeX() - _significantEV ;
151 
152  std::cout << "signif EV = " << _significantEV << " sig2 = " << sig2 << std::endl ;
153 
154  double lnSig2 = log(sig2) ;
155  double sqrtSig2 = sqrt(sig2) ;
156  int i, n = w.getSizeX();
157  double lnDetVarCov = 0 ;
158  _detVarCov = 1. ;
159  for ( i = 0; i < _significantEV ; i++ )
160  {
161  lnDetVarCov += 0.5 * log( w( i, i ) ) ;
162  _detVarCov *= sqrt(w( i, i )) ;
163  invW( i, i ) = 1.0f / w( i, i );
164  }
165  for ( i = _significantEV ; i<n; i++ )
166  {
167  lnDetVarCov += 0.5 * lnSig2 ;
168  _detVarCov *= sqrtSig2 ;
169  w( i, i ) = sig2 ;
170  invW( i, i ) = 1.0f / sig2 ;
171  }
172 
173  // JUST FOR SOCIETY FOR MOLECULAR IMAGING END
174 
175  // Set the singular values lower than threshold to zero
176 // double ts = s * w.maximum();
177 // int i, n = w->getSizeX();
178 // _detVarCov = 1. ;
179 // for ( i=0; i<n; i++ )
180 // {
181 // _detVarCov *= w( i, i ) ;
182 // if ( w( i, i ) > ts ) w( i, i ) = 1.0f / w( i, i );
183 // else w( i, i ) = 0.0f;
184 // }
185 
186 
187  //cout << "Det Var Cov = " << _detVarCov << endl ;
188  if( _detVarCov != 0. )
189  {
191  carto::matrix_product( invW, u ) );
192  _normFactor = 1. / _detVarCov ;
193  _lnAddFactor = -lnDetVarCov + log( _PIj * _PIj ) ;
194 
195  std::cout << "normFactor = " << _normFactor << "\t_lnAddFactor = " << _lnAddFactor << std::endl ;
196 
197  for( y1=0; y1<dy1; ++y1 )
198  for( x1=0; x1<dx1; ++x1 )
199  if( x1 < y1 )
200  {
201  double val = 0.5 * ( _invVarCov(x1, y1) + _invVarCov(y1, x1) ) ;
202  _invVarCov(x1, y1) = _invVarCov(y1, x1) = val ;
203  }
204  }
205  else
206  {
207  std::cerr << "Bad var cov matrix !" << std::endl ;
208  throw std::runtime_error( "Bad var cov matrix !") ;
209  }
210 }
211 
212 double
214  const carto::rc_ptr<carto::Volume<double> >& x, double ) const
215 {
216  if( ! _computed ){
217  std::cerr << "You must doIt first, parameter not yet computed !"
218  << std::endl ;
219 
220  throw std::runtime_error( "You must doIt first, parameter not yet computed !") ;
221  }
222 // carto::VolumeRef<double> xCentered(x->getSizeX()) ;
223 // for( int t = 0 ; t < x->getSizeX() ; ++t )
224 // xCentered(t) = ( x(t) - _mean(t) ) * _dataScaleFactor ;
225 
226 
227  double distance = 0. ;
228  for(int i = 0 ; i < x->getSizeX() ; ++i ){
229  double sum = 0. ;
230  for( int j = 0 ; j < x->getSizeX() ; ++j )
231  sum += _invVarCov(i, j) * ( x->at(j) - _mean(j) ) ;
232  //double term = ( x->at(i) - _mean(i) ) * sum ;
233  distance += ( x->at(i) - _mean(i) ) * sum ;
234  }
235 
236  return _normFactor * exp( -distance ) ;
237 }
238 
239 double
241  const carto::rc_ptr<carto::Volume<double> >& x ) const
242 {
243  if( ! _computed ){
244  std::cerr <<"You must doIt first, parameter not yet computed !"
245  << std::endl ;
246  throw std::runtime_error( "You must doIt first, parameter not yet computed !") ;
247  }
248 // cout << "DiscriminantAnalysisElement::distance " << endl ;
249 // cout << "inv var cov size = " << _invVarCov->getSizeX() << " , " << _invVarCov->getSizeY() << endl ;
250  double distance = 0. ;
251  for(int i = 0 ; i < x->getSizeX() ; ++i ){
252 // cout << "i = " << i << endl ;
253  double sum = 0. ;
254  for( int j = 0 ; j < x->getSizeX() ; ++j ){
255 // cout << "\tj = " << j << endl ;
256  sum += _invVarCov(i, j) * ( x->at(j) - _mean(j) ) ;
257  }
258  //double term = ( x->at(i) - _mean(i) ) * sum ;
259  distance += ( x->at(i) - _mean(i) ) * sum ;
260  }
261 // cout << "DiscriminantAnalysisElement::distance end " << endl ;
262 
263  return distance ;
264 }
265 
266 double
268  const carto::rc_ptr<carto::Volume<double> >& x ) const
269 {
270  if( ! _computed ){
271  std::cerr << "You must doIt first, parameter not yet computed !"
272  << std::endl ;
273  throw std::runtime_error( "You must doIt first, parameter not yet computed !") ;
274  }
275  double distance = 0. ;
276  for(int i = 0 ; i < x->getSizeX() ; ++i ){
277  double sum = 0. ;
278  for( int j = 0 ; j < x->getSizeX() ; ++j )
279  sum += _invVarCov(i, j) * ( x->at(j) - _mean(j) ) ;
280  //double term = ( x->at(i) - _mean(i) ) * sum ;
281  distance += ( x->at(i) - _mean(i) ) * sum ;
282  }
283 
284 // double distanceTest = 0. ;
285 // carto::VolumeRef<double> Ux( x->getSizeX() ) ;
286 // for(int i = 0 ; i < _U->getSizeX() ; ++i )
287 // for( int j = 0 ; j < _U->getSizeY() ; ++j )
288 // Ux(i) += _U(j, i) * (x->at(j) - _mean(i) ) ;
289 
290 // for( int i = 0 ; i < Ux->getSizeX() ; ++i )
291 // distanceTest += Ux(i) * Ux(i) * _invEigenValues[i] ;
292 
293 // double distance = 0. ;
294 // for(int i = 0 ; i < x->getSizeX() ; ++i ){
295 // double sum = 0. ;
296 // for( int j = 0 ; j < x->getSizeX() ; ++j )
297 // sum += _invVarCov(i, j) * ( x->at(j) - _mean(j) ) ;
298 // distance += ( x->at(i) - _mean(i) ) * sum ;
299 // cout << i << "\txi = " << x->at(i) << "\tmean i = " << _mean(i) <<
300 // " diff = " << x->at(i) - _mean(i) << " dist = " << distance << endl ;
301 // }
302 
303  return -distance + _lnAddFactor ;
304 }
305 
306 
309 {
310  if( ! _computed ){
311  std::cerr <<"You must doIt first, parameter not yet computed !"
312  << std::endl ;
313  throw std::runtime_error( "You must doIt first, parameter not yet computed !") ;
314  }
315  return _mean ;
316 }
317 
318 template <class T>
320  const carto::rc_ptr<carto::Volume<T> >& data,
321  const std::vector< std::list< Point3d > >& classes,
322  int significantEV, const std::vector<double>& PIj )
323  : _significantEV(significantEV <= 0 ? data->getSizeT() : significantEV),
324  _classes(classes), _data(data), _PIj(PIj)
325 {
326  if( PIj.size() != 0 )
327  if( PIj.size() == classes.size() )
328  _PIj = PIj ;
329  else{
330  std::cerr << "Inconsistant data : number of classes and number of classes prior probabilities are different !" << std::endl ;
331 
332  throw std::runtime_error("Inconsistant data : number of classes and number of classes prior probabilities are different !") ;
333  }
334  else{
335  _PIj.reserve( _classes.size() ) ;
336  for( unsigned int c = 0 ; c < _classes.size() ; ++c )
337  _PIj.push_back( 1./_classes.size() ) ;
338  }
339  //--------------------------------TEMP---------------------------------------------
340 /* carto::VolumeRef<double> indiv(12000, 3) ; */
341 /* Point3dd mean( 56., 32., 100.) ; */
342 /* Point3dd sigma( 20., 2., 10.) ; */
343 
344 /* for( int ind = 0 ; ind < indiv->getSizeX() ; ++ind ) */
345 /* for( int t = 0 ; t < indiv->getSizeY() ; ++t ) */
346 /* indiv(ind, t) = GaussianRandom ( mean[t], sigma[t] ) ; */
347 
348  //--------------------------------TEMP---------------------------------------------
349  _discrElements.reserve( _classes.size() ) ;
350  for( unsigned int c = 0 ; c < _classes.size() ; ++c ){
351  DiscriminantAnalysisElement el( significantEV, _PIj[c] ) ;
352  el.doIt( _classes[c], _data ) ;
353 /* el.doIt( indiv ) ; */
354 
355  std::cout << "Class " << c << " done !" << std::endl ;
356 
357  _discrElements.push_back( el ) ;
358  }
359  std::cout << "Discriminant analysis initization completed" << std::endl ;
360 }
361 
362 template <class T>
363 std::vector<double>
365  const carto::rc_ptr<carto::Volume<double> >& x, double pX )
366 {
367  std::vector<double> res( _classes.size() ) ;
368  for( unsigned int c = 0 ; c < _classes.size() ; ++c )
369  res[c] = _discrElements[c].posteriorProbability( x, pX ) ;
370  return res ;
371 }
372 
373 template <class T>
374 std::vector<double>
377 {
378  std::vector<double> res( _classes.size() ) ;
379  double sum = 0. ;
380  for( unsigned int c = 0 ; c < _classes.size() ; ++c ){
381  res[c] = _discrElements[c].posteriorProbability( x, 1. ) ;
382  sum += res[c] ;
383  }
384 
385  for( unsigned int c = 0 ; c < _classes.size() ; ++c )
386  res[c] /= sum ;
387 
388  return res ;
389 }
390 
391 template <class T>
392 int
395 {
396  double lnP ;
397  double lnPMax = _discrElements[0].lnPosteriorProbability( x ) ;
398  int indMax = 0 ;
399  for( unsigned int c = 0 ; c < _classes.size() ; ++c )
400  {
401  lnP = _discrElements[c].lnPosteriorProbability( x ) ;
402  if( lnP > lnPMax ){
403  lnPMax = lnP ;
404  indMax = c ;
405  }
406  }
407 
408  return indMax ;
409 }
410 
411 
412 template <class T>
413 bool
415  const carto::rc_ptr<carto::Volume<T> >& dynamicImage,
417  carto::rc_ptr<carto::Volume<short> >& segmented )
418 {
419  int x, y, z ;
420  if( dynamicImage->getSizeT() != _data->getSizeT() )
421  return false ;
422  if( segmented->getSizeX() != _data->getSizeX() && segmented->getSizeY() != _data->getSizeY()
423  && segmented->getSizeZ() != _data->getSizeZ() )
424  {
425  segmented = carto::VolumeRef<short> ( _data->getSizeX(), _data->getSizeY(), _data->getSizeZ() );
426  segmented->setVoxelSize( _data->getVoxelSize() );
427  }
428 
429  carto::VolumeRef<double> indiv( dynamicImage->getSizeT(), 1, 1, 1,
430  carto::AllocatorContext::fast() ) ;
431 
432  int dx = dynamicImage->getSizeX(), dy = dynamicImage->getSizeY(),
433  dz = dynamicImage->getSizeZ();
434 
435  for( z=0; z<dz; ++z )
436  for( y=0; y<dy; ++y )
437  for( x=0; x<dx; ++x )
438  {
439  if( mask->at(x, y, z) )
440  {
441  std::cout << "x : " << x << ", y : " << y << ", z : " << z << std::endl ;
442  for( int t = 0 ; t < _data->getSizeT() ; ++t )
443  indiv(t) = dynamicImage->at(x, y, z, t ) ;
444  segmented->at(x, y, z) = affectedTo( indiv ) ;
445  }
446  }
447 
448  std::cout << "Discriminant analysis classification completed" << std::endl ;
449 
450  return true ;
451 }
452 
453 template <class T>
454 bool
456  const carto::rc_ptr<carto::Volume<T> >& dynamicImage,
458  carto::rc_ptr<carto::Volume<float> >& fuzzySegmented,
459  const carto::rc_ptr<carto::Volume<double> > & indivPriorProbabilities )
460 {
461  bool noPriorProba
462  = ( indivPriorProbabilities->getSizeX() == 1
463  && indivPriorProbabilities->getSizeY() == 1
464  && indivPriorProbabilities->getSizeZ() == 1 );
465  int count = 0 ;
466  //double uniformPriorProba ;
467 
468  int x, y, z ;
469  if( noPriorProba )
470  {
471  int dx = mask->getSizeX(), dy = mask->getSizeY(), dz = mask->getSizeZ();
472 
473  for( z=0; z<dz; ++z )
474  for( y=0; y<dy; ++y )
475  for( x=0; x<dx; ++x )
476  if( mask->at( x, y, z ) )
477  ++count ;
478  //uniformPriorProba = 1. / count ;
479  }
480  if( dynamicImage->getSizeT() != _data->getSizeT() )
481  return false ;
482  if( fuzzySegmented->getSizeX() != _data->getSizeX()
483  && fuzzySegmented->getSizeY() != _data->getSizeY()
484  && fuzzySegmented->getSizeZ() != _data->getSizeZ() &&
485  fuzzySegmented->getSizeT() != int(_classes.size() ) )
486  {
487  fuzzySegmented = carto::VolumeRef<float> ( _data->getSizeX(), _data->getSizeY(),
488  _data->getSizeZ(), _classes.size() ) ;
489  fuzzySegmented->setVoxelSize( _data->getVoxelSize() ) ;
490  }
491 
492  std::vector<double> probabilityRepartition ;
493  carto::VolumeRef<double> indiv( dynamicImage->getSizeT(), 1, 1, 1,
494  carto::AllocatorContext::fast() ) ;
495 
496  int dx = dynamicImage->getSizeX(), dy = dynamicImage->getSizeY(),
497  dz = dynamicImage->getSizeZ();
498 
499  for( z=0; z<dz; ++z )
500  for( y=0; y<dy; ++y )
501  for( x=0; x<dx; ++x )
502  {
503  if( mask->at(x, y, z) )
504  {
505  //cout << "x : " << x << ", y : " << y << ", z : " << z << endl ;
506  for( int t = 0 ; t < _data->getSizeT() ; ++t )
507  indiv(t) = dynamicImage->at(x, y, z, t ) ;
508  /* probabilityRepartition = andersonScores( indiv ) ; */
509  probabilityRepartition = posteriorProbabilities( indiv, 1. ) ;
510 
511  for( int c = 0 ; c < fuzzySegmented->getSizeT() ; ++c )
512  fuzzySegmented->at(x, y, z, c) = probabilityRepartition[c] ;
513  }
514  }
515 
516  std::cout << "Discriminant analysis : fuzzy classification completed"
517  << std::endl ;
518 
519  return true ;
520 }
521 
522 }
Definition: svd.h:59
carto::VolumeRef< T > doit(carto::VolumeRef< T > &, carto::VolumeRef< T > *v=NULL)
Singular Value Decomposition.
const carto::VolumeRef< double > & mean() const
double posteriorProbability(const carto::rc_ptr< carto::Volume< double > > &individual, double pX) const
double lnPosteriorProbability(const carto::rc_ptr< carto::Volume< double > > &individual) const
carto::VolumeRef< double > _mean
void doIt(const carto::rc_ptr< carto::Volume< T > > &individuals)
DiscriminantAnalysisElement(int significantEV=-1, double PIj=1.)
double distance(const carto::rc_ptr< carto::Volume< double > > &x) const
carto::VolumeRef< double > _invVarCov
bool classification(const carto::rc_ptr< carto::Volume< T > > &dynamicImage, const carto::rc_ptr< carto::Volume< byte > > &mask, carto::rc_ptr< carto::Volume< short > > &segmented)
DiscriminantAnalysis(const carto::rc_ptr< carto::Volume< T > > &data, const std::vector< std::list< Point3d > > &classes, int significantEV=-1, const std::vector< double > &PIj=std::vector< double >())
int affectedTo(const carto::rc_ptr< carto::Volume< double > > &x)
std::vector< double > andersonScores(const carto::rc_ptr< carto::Volume< double > > &x)
std::vector< double > posteriorProbabilities(const carto::rc_ptr< carto::Volume< double > > &x, double px)
bool fuzzyClassification(const carto::rc_ptr< carto::Volume< T > > &dynamicImage, const carto::rc_ptr< carto::Volume< byte > > &mask, carto::rc_ptr< carto::Volume< float > > &fuzzySegmented, const carto::rc_ptr< carto::Volume< double > > &indivPriorProbabilities=carto::rc_ptr< carto::Volume< double > >())
VolumeRef< T > deepcopy() const
const T & at(long x, long y=0, long z=0, long t=0) const
int getSizeY() const
int getSizeX() const
float max(float x, float y)
Definition: thickness.h:98
BucketMap< Void > * mask(const BucketMap< Void > &src, const BucketMap< Void > &m, bool intersect=true)
DataTypeTraits< T >::LongType sum(const Volume< T > &vol)
VolumeRef< T > matrix_product(const Volume< T > &v1, const Volume< T > &v2)
VolumeRef< T > transpose(const Volume< T > &v)