brainrat-private 6.0.4
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
28#include <aims/interpolation/interpolatedvolume.h>
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
42namespace 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="")
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)
virtual int32_t learnClustering(std::list< double > &inputListOfPrior, std::vector< carto::Object > &classDesc, std::vector< std::vector< std::vector< double > > > &classVectors)
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