brainrat-private  5.1.2
biovision_d.h
Go to the documentation of this file.
1 /* Copyright (C) 2000-2016 CEA
2  *
3  * This software and supporting documentation were developed by
4  * bioPICSEL
5  * CEA/DSV/I²BM/MIRCen/LMN, Batiment 61,
6  * 18, route du Panorama
7  * 92265 Fontenay-aux-Roses
8  * France
9  */
10 
11 #ifndef BRAINRAT_CLASSIFICATION_BIOVISION_D_H
12 #define BRAINRAT_CLASSIFICATION_BIOVISION_D_H
13 
14 //--- brainrat ----------------------------------------------------------
15 #include <brainrat/classification/biovision.h> // class declaration
16 #include <brainrat/data/classes.h> // bio::BVclasses
17 //--- aims -------------------------------------------------------------------
18 #include <aims/data/data_g.h> // AimsData
19 #include <aims/io/writer.h> // aims::Writer
20 #include <aims/io/reader.h> // aims::Reader
21 #include <aims/utility/converter_g.h>
22 #include <aims/utility/progress.h> // aims::ProgressInfo
23 #include <aims/threshold/emthreshold.h> // AimsEMThreshold
24 #include <aims/roi/roiIterator.h> // aims::RoiIterator
25 #include <aims/roi/maskIterator.h> // aims::MaskIterator
26 #include <aims/connectivity/connectivity.h> // aims::Connectivity
27 #include <aims/connectivity/component.h>// aims::AimsLabeledConnectedComponent
29 //--- cartodata --------------------------------------------------------------
30 #include <cartodata/volume/volume.h>
31 //--- soma-io ----------------------------------------------------------------
32 #include <soma-io/allocator/allocator.h>
33 //--- cartobase --------------------------------------------------------------
34 #include <cartobase/stream/fileutil.h>
35 #include <cartobase/smart/rcptr.h>
36 #include <cartobase/type/string_conversion.h>
37 //--- system -----------------------------------------------------------------
38 #include <vector>
39 //----------------------------------------------------------------------------
40 
41 
42 namespace biovision {
43 
44 //============================================================================
45 // L E A R N I N G
46 //============================================================================
47 
48  template <typename T> int32_t
49  LearningAlgorithm::processOneImage( carto::VolumeRef<T> & image,
50  const std::string & inputGraph,
51  const std::string & fileOutMeasure,
52  std::vector<carto::Object > & classDesc,
53  std::vector<std::vector<std::vector<double> > > & classVectors )
54  {
55  // Get image processor instance
56  carto::rc_ptr<aims::MaskIterator> mask = aims::getMaskIterator( inputGraph );
57 
58  // Get interpolator instances
59  std::vector< aims::InterpolatedVolume > interpolators;
60  interpolators.reserve(_measuresize);
61 
62  for( int j=0; j<_measuresize; ++j) {
63  carto::VolumeRef<T> view = image.view( Point4di( 0, 0, 0, j), Point4di(image.getSizeX(), image.getSizeY(), image.getSizeZ(), 1) );
64  aims::InterpolatedVolume interpolated;
65  interpolated.setVolume( view.copy(), 1 );
66  interpolators.push_back( interpolated );
67  }
68 
69  // Read ROI graph
70  const carto::rc_ptr<aims::RoiIterator> roiIterator = aims::getRoiIterator( inputGraph );
71 
72  while( roiIterator->isValid() ) { // Classes
73  int k = 0;
74  bool newregion = true;
75 
76  // Test if ROI already exists
77  for( k=0; k<classDesc.size(); ++k )
78  {
79  // macos 10.4 copmiler needs this carto::GenericObject:: thing
80  const std::string & s = classDesc[k]->getProperty("n")->carto::GenericObject::value<std::string>();
81  if( s == roiIterator->regionName() ) {
82  // Add measure vectors to existing region
83  if( carto::verbose )
84  std::cout << "Add measure vectors to existing region "
85  << roiIterator->regionName() << std::endl;
86  newregion = false;
87  break;
88  }
89  }
90 
91  if( newregion ) {
92  // Create a new region
93  if( carto::verbose )
94  std::cout << "Create new region " << roiIterator->regionName()
95  << std::endl;
96 
97  carto::Object c = carto::Object::value(carto::PropertySet());
98  c->setProperty("n", roiIterator->regionName() ); // Set region prior
99  c->setProperty("p", 0.);
100  classDesc.push_back(c);
101 
102  std::vector<std::vector<double> > cv; // Add vector entry for the class vectors
103  classVectors.push_back( cv );
104  }
105 
106  carto::rc_ptr<aims::MaskIterator> roiMaskIterator = roiIterator->maskIterator();
107  size_t point_count = 0;
108 
109  // Process each pixel contained in the mask
110  while( roiMaskIterator->isValid() ) {
111  // Create measure vector v and set values
112  std::vector<double> v(_measuresize);
113  Point3df coord_f = roiMaskIterator->valueMillimeters();
114 
115  for( int32_t j=0; j<_measuresize; ++j )
116  v[j] = interpolators[j].atMm( coord_f[0], coord_f[1], coord_f[2] );
117 
118  classVectors[k].push_back(v); // add to existing measure vector
119  ++point_count;
120 
121  roiMaskIterator->next();
122  }
123 
124  if( carto::verbose )
125  std::cout << carto::toString(point_count)
126  << " measure vectors added to "
127  << roiIterator->regionName()
128  << std::endl;
129 
130  roiIterator->next();
131  }
132 
133  return EXIT_SUCCESS;
134  }
135 
136  int32_t LearningAlgorithm::learnClustering( std::list<double> & inputListOfPrior,
137  std::vector<carto::Object > & classDesc,
138  std::vector<std::vector<std::vector<double> > > & classVectors )
139  {
140  // Clustering
141  if (carto::verbose)
142  std::cout << "Clustering measure vectors ..." << std::endl
143  << "Clustering parameters [ threshold = " << _threshold
144  << ", cluster number maximum = " << _nbclustermax
145  << ", sigma minimum = " << _sigmamin
146  << ", sigma ratio = " << _sigmaratio << " ]" << std::endl;
147 
148  if( !inputListOfPrior.empty() && inputListOfPrior.size() != classDesc.size() )
149  throw ( "number of priors and classes must match! " ) ;
150 
151  std::list<double>::iterator itp = inputListOfPrior.begin(); // prior iterator
152 
153  int nbtotal = 0; // Information only : number of pixels in learning set
154  std::vector<carto::Array<carto::Array<carto::Array<int> > > > histo(classDesc.size());
155 
156  /* Compute Density Parameters :
157  * For each class (contained in classDesc) is given a set
158  * Q=classVectors.at( p ) of vectors. We want to find the number of
159  * gaussians in the mixture and thus clusterize the set Q.
160  */
161  for( int p = 0; p < classDesc.size(); ++p )
162  {
163  // We get all measures of given class p
164  std::vector<std::vector<double> > & mv = classVectors[p];
165  std::vector<double> d; // Clusters density parameters
166 
167  int nbvectors = mv.size(); // Number of measures in class
168  nbtotal += nbvectors;
169 
170  if( carto::verbose ) {
171  std::cout << "Clustering " << carto::toString(nbvectors)
172  << " measure vectors of " << classDesc[p]->getProperty("n")->value<std::string>()
173  << "..." << std::endl;
174  }
175 
176  carto::VolumeRef<int> C( nbvectors ); // Cluster labeling
177  C = 0;
178  std::vector<std::vector<double> > centroids
179  = Clustering( mv, _threshold, _sigmamin, _sigmaratio,
180  _nbclustermax, _newclusterpolicy, _clustersizemin, C ) ; // Centroids of each cluster
181 
182  // For each cluster, compute cluster probability and covariance matrix
183  int nbclusters = centroids.size(); // Named 'nq' in Biovision article
184  d.push_back(nbclusters);
185 
186  if (carto::verbose)
187  std::cout << "Processing density parameters for "
188  << carto::toString(nbclusters)
189  << " clusters..." << std::endl;
190 
191  // ro probability of each cluster
192  carto::VolumeRef<double> ro( nbclusters );
193  ro = 0;
194  for( int i = 0 ; i < nbvectors; ++i ) {
195  if( C(i) >= 0 )
196  ro( C(i) )++;
197  }
198 
199  // For each cluster Qi
200  for( int k = 0 ; k < nbclusters ; ++k ) {
201 
202  // Cluster probability
203  ro(k) /= nbvectors;
204  d.push_back(ro(k));
205 
206  if (carto::verbose)
207  std::cout << "ro(" << carto::toString(k) << ") : "
208  << carto::toString(ro(k)) << std::endl;
209 
210  // Centroid
211  std::vector<double> mu = centroids[k];
212 
213  for (int i = 0; i < _measuresize; ++i) {
214  d.push_back(mu[i]);
215  }
216 
217  // All the measure vectors in cluster
218  std::vector<std::vector<double> > M;
219  std::vector<std::vector<double> > qk;
220  for (int i = 0 ; i < nbvectors; ++i) {
221  if (C(i) == k)
222  qk.push_back(mv[i]);
223  }
224 
225  // Compute cluster histograms
227  for (int i = 0; i < _measuresize; ++i) {
229 
230  // Convert measure vectors to VolumeRef
231  carto::VolumeRef<double> hdata(qk.size());
232  for(int32_t j = 0; j < hdata.getSizeX(); ++j) {
233  hdata(j) = ((std::vector<double>)qk[j])[i];
234  }
235 
236  h.doit(hdata, 0, 255);
237 
238  // Convert histogram to array
240  for (int32_t j = 0; j < h.data().getSizeX(); ++j) {
241  v.push_back(h.data()(j));
242  }
243  mh.push_back(v);
244  }
245  histo[p].push_back(mh);
246 
247  int nvcluster = qk.size(); // Number of measure vectors in cluster
248  d.push_back(nvcluster);
249 
250  // Compute covariance matrix : cov = 1/n ( M*M' )
251  for (int i = 0 ; i < nvcluster; ++i) {
252  std::vector<double> diff(qk[i].size());
253  for(int j = 0;j<qk[i].size(); ++j){
254  diff[j] = qk[i][j] - mu[j];
255  }
256  M.push_back(diff);
257  }
258 
259  carto::VolumeRef<double> cov(_measuresize, _measuresize), I(_measuresize, _measuresize);
260  I = 0, cov = 0;
261  for (int i = 0; (i< _measuresize); ++i) {
262  I(i,i) = 1.0;
263  for (int j = 0 ; (j < _measuresize); ++j) {
264  for (int k = 0 ; k < nvcluster; ++k) {
265  cov (i,j) += M[k][i] * M[k][j] ; // M(i,k) * M'(k,j)
266  }
267  cov(i,j) /= nvcluster; // Normalize covariance matrix
268  }
269  }
270 
271  // Inverse of covariance matrix and determinant
272  double detcov = det(cov, I);
273  d.push_back(detcov);
274  for (int i = 0; i < _measuresize; ++i) {
275  for (int j = 0 ; j < _measuresize; ++j) {
276  d.push_back(I(i,j));
277  }
278  }
279  }
280 
281  classDesc[p]->setProperty("d", d);
282  classDesc[p]->setProperty("h", histo[p]);
283 
284  // Change a priori probability of each class
285  if (inputListOfPrior.empty ())
286  classDesc[p]->getProperty("p")->value<double>() = 1.0 / ((double)classDesc.size()); // Uniform
287  else
288  classDesc[p]->getProperty("p")->value<double>() = (*itp) ; // Input proba
289 
290  itp++;
291 
292  if (carto::verbose){
293  std::cout << "prior : " << classDesc[p]->getProperty("p")->value<double>() << std::endl;
294  std::cout << "density : [" << d[0];
295  for(int i=1; i<d.size(); ++i)
296  std::cout << "," << d[i];
297  std::cout << "]" << std::endl;
298  }
299  }
300 
301  std::cout << carto::toString(nbtotal) << " pixels clustered." << std::endl;
302 
303  _learningmodel = carto::Object::value(carto::PropertySet());
304  _learningmodel->setProperty( "data", classDesc );
305 
306  return EXIT_SUCCESS;
307  }
308 
309 //============================================================================
310 // C L A S S I F I C A T I O N
311 //============================================================================
312 
313  template <typename T>
314  int32_t ClassificationAlgorithm::classify( const Point3dl &t,
315  carto::VolumeRef<T> &image )
316  {
317  std::vector<double> w(_measuresize);
318  for ( int32_t j = 0; j < _measuresize; ++j) {
319  w[j] = image(t[0],t[1],t[2],j);
320  }
321 
322  return Classifier(w, t, false, false, true);
323  }
324 
325  template <typename T> int32_t
326  ClassificationAlgorithm::classify( carto::VolumeRef<T> &image,
327  const std::vector<int32_t> &labels,
328  const std::vector<std::string> &classesorder,
329  const std::string &maskFile,
330  const bool keepClasses,
331  const bool keepProba,
332  const bool keepDensity)
333  {
334  // Read or Generate labels from class indexes
335  std::vector<int32_t> l = labels;
336  if (l.empty()) {
337  // Generate labels using class indexes
338  for (int32_t i = 0; i < _nbclasses; ++i)
339  l.push_back(i + 1);
340  }
341  else if (l.size() != _nbclasses) {
342  throw std::runtime_error( "Number of labels specified does not match the number of classes in model." );
343  }
344 
345  std::map<std::string, int32_t> orders;
346  if (classesorder.empty()) {
347  // Generate classes order dictionary using class indexes
348  for (int32_t i = 0; i < _nbclasses; ++i)
349  orders[_classdesc[i]->getProperty("n")->carto::GenericObject::value<std::string>()] = i;
350  }
351  else if (classesorder.size() != _nbclasses) {
352  throw std::runtime_error( "Number of classes specified in classes order does not match the number of classes in model." );
353  }
354  else {
355  // Generate classes order dictionary using specified classesorder
356  int32_t i = 0;
357  bool found;
358  std::vector<std::string>::const_iterator k, ek = classesorder.end();
359  for ( k = classesorder.begin(); k != ek; ++k, ++i) {
360  // Checks that k exists in model
361  found = false;
362  for (int32_t j = 0; j < _classdesc.size(); ++j) {
363  if (_classdesc[j]->getProperty("n")->carto::GenericObject::value<std::string>() == *k) {
364  found = true;
365  break;
366  }
367  }
368 
369  if (found) {
370  // Sets order for class
371  orders[*k] = i;
372  }
373  else
374  throw std::runtime_error( "Class " + *k + " specified in classes order was not found in model." );
375  }
376  }
377 
378  // Image dimensions
379  int dx = image.getSizeX(), dy = image.getSizeY(), dz = image.getSizeZ();
380 
381  // Mask image
382  carto::rc_ptr<aims::MaskIterator> mask;
383 
384  // Read mask
385  if (!maskFile.empty()) {
386  if (carto::verbose)
387  std::cout << "Reading mask image ..." << std::endl;
388  mask = aims::getMaskIterator( maskFile );
389  }
390 
391  // Classes label image
392  if( keepClasses ) {
393  if (carto::verbose)
394  std::cout << "Allocating classification image ..." << std::endl;
395  _Cimage = carto::VolumeRef<int16_t>(dx, dy, dz);
396  _Cimage.copyHeaderFrom(image.header());
397  _Cimage.fill(0);
398  }
399 
400  // Probabilities image
401  if( keepProba ) {
402  if (carto::verbose)
403  std::cout << "Allocating probability image ..." << std::endl;
404  _Pimage = carto::VolumeRef<double>( dx, dy, dz, _nbclasses );
405  _Pimage.copyHeaderFrom(image.header());
406  _Pimage.fill(0.);
407  }
408 
409  // Density image
410  if( keepDensity ) {
411  if (carto::verbose)
412  std::cout << "Allocating density image ..." << std::endl;
413  _Dimage = carto::VolumeRef<double>( dx, dy, dz, _nbclasses );
414  _Dimage.copyHeaderFrom(image.header());
415  _Dimage.fill(0.);
416  }
417 
418  // Classify
419  if (carto::verbose) {
420  std::cout << "Starting segmentation ..." << std::endl;
421  for (int32_t i = 0; i < _nbclasses; ++i)
422  {
423  const std::string & s = _classdesc[i]->getProperty("n")->carto::GenericObject::value<std::string>();
424  std::cout << "Class " << s
425  << " label " << carto::toString(l[i]) << std::endl;
426  }
427  }
428 
429  std::vector<double> w(_measuresize);
430  int ic;
431  Point3dl c;
432 
433  if (!mask.isNull())
434  mask->restart();
435 
436 
437  // Progression tracking tool
438  aims::Progression progress(dz - 1);
439  if (dz > 1)
440  std::cout << "Progress: ";
441 
442  for( int32_t z = 0; z < dz; ++z, ++progress ) {
443  if(dz>1) std::cout << progress << std::flush;
444  for( int32_t y = 0; y < dy; ++y )
445  for( int32_t x = 0; x < dx; ++x )
446  if( mask.isNull() || mask->contains( Point3df(
447  image.getVoxelSize()[0] * x, image.getVoxelSize()[1] * y, image.getVoxelSize()[2] * z ) ) )
448  {
449  c = Point3dl( x, y, z );
450  for ( int32_t j = 0; j < _measuresize; j++)
451  w[j] = image(x,y,z,j);
452  ic = Classifier( w, c, keepProba, keepDensity );
453  // Classify only if the voxel has a probability to belong
454  // to a class of the model
455  if( (ic > -1) && keepClasses ) {
456  // Get the class order for the found class
457  int32_t o = orders[_classdesc[ic]->getProperty("n")->carto::GenericObject::value<std::string>()];
458  _Cimage(x,y,z) = l[ o ];
459  }
460  }
461  }
462 
463  return EXIT_SUCCESS;
464  }
465 
466  int ClassificationAlgorithm::writeResults( const std::string &outputFile,
467  const std::string &outputProbaFile,
468  const std::string &outputDensityFile )
469  {
470  int out = EXIT_SUCCESS;
471 
472  // Write proba file
473  if( !outputProbaFile.empty() && !_Pimage.get() )
474  {
475  std::cout << "Proba image was not saved ! "
476  << std::endl
477  << "Run classification again with keepProba parameter "
478  << "set at true."
479  << std::endl;
480  out = EXIT_FAILURE;
481  }
482  else if( !outputProbaFile.empty() )
483  {
484  if( carto::verbose )
485  std::cout << "Writing proba image : " << outputProbaFile << std::endl;
486 
487  aims::Writer<carto::Volume<double> > outputProbaWriter( outputProbaFile );
488  outputProbaWriter << *(_Pimage);
489  }
490 
491  // Write density file
492  if( !outputDensityFile.empty() && !_Dimage.get() )
493  {
494  std::cout << "Density image was not saved ! "
495  << std::endl
496  << "Run classification again with keepDensity parameter "
497  << "set at true."
498  << std::endl;
499  out = EXIT_FAILURE;
500  }
501  else if( !outputDensityFile.empty() )
502  {
503  if( carto::verbose )
504  std::cout << "Writing density image : " << outputDensityFile << std::endl;
505 
506  aims::Writer<carto::Volume<double> > outputDensityWriter( outputDensityFile );
507  outputDensityWriter << *(_Dimage);
508  }
509 
510  // Write image file
511  if( !outputFile.empty() && !_Cimage.get() )
512  {
513  std::cout << "Classification image was not saved ! "
514  << std::endl
515  << "Run classification again with keepClasses parameter "
516  << "set at true."
517  << std::endl;
518  out = EXIT_FAILURE;
519  }
520  else if( !outputFile.empty() )
521  {
522  if (carto::verbose)
523  std::cout << "Writing output image : " << outputFile << std::endl;
524 
525  aims::Writer<carto::Volume<int16_t> > outputWriter(outputFile);
526  outputWriter << *(_Cimage);
527  }
528 
529  return out;
530  }
531 
532 }// namespace biovision
533 
534 #endif // BRAINRAT_CLASSIFICATION_BIOVISION_D_H
carto::VolumeRef< int32_t > & data()
void setVolume(const carto::Volume< T > &vol, int order=-1)
void doit(const carto::rc_ptr< carto::Volume< T > > &thing)
int32_t writeResults(const std::string &outputFile="", const std::string &outputProbaFile="", const std::string &outputDensityFile="")
Definition: biovision_d.h:466
int32_t classify(carto::VolumeRef< T > &image, const std::vector< int32_t > &labels, const std::vector< std::string > &classesorder, const std::string &maskFile="", const bool keepClasses=true, const bool keepProba=false, const bool keepDensity=false)
Definition: biovision_d.h:326
virtual int32_t learnClustering(std::list< double > &inputListOfPrior, std::vector< carto::Object > &classDesc, std::vector< std::vector< std::vector< double > > > &classVectors)
Definition: biovision_d.h:136
int32_t processOneImage(carto::VolumeRef< T > &inputImage, const std::string &inputGraph, const std::string &fileOutMeasure, std::vector< carto::Object > &classDesc, std::vector< std::vector< std::vector< double > > > &classVectors)
Definition: biovision_d.h:49
virtual size_t size() const
Definition: array.h:55