aimsdata  5.0.5
Neuroimaging data handling
component_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  * Connected components
36  */
37 #ifndef AIMS_CONNECTIVITY_COMPONENT_D_H
38 #define AIMS_CONNECTIVITY_COMPONENT_D_H
39 
41 #include <aims/data/data.h>
42 #include <aims/utility/threshold.h>
43 #include <aims/bucket/bucket.h>
44 #include <map>
45 #include <queue>
46 #include <iostream>
47 #include <iomanip>
48 
49 namespace aims
50 {
51 
52 
53 // template<typename T, typename O>
54 // std::map<O, size_t> ConnectedComponentEngine<AimsData<T>, AimsData<O> >::sizes( AimsData<T>& data, bool verbose )
55 // {
56 // }
57  template<typename T, typename O>
59  const AimsData<T>& cc,
60  AimsData<O>& out,
61  std::map<O, size_t>& valids,
62  int t,
63  bool verbose )
64  {
65  int x = 0, y = 0, z = 0;
66 
67  if( verbose )
68  std::cout << "filtering...\n";
69 
70  ForEach3d( out, x, y, z )
71  out(x, y, z, t) = 0 ;
72 
73  typename std::map<O, size_t>::iterator is, es = valids.end();
74 
75  ForEach3d( cc, x, y, z )
76  {
77  is = valids.find( (O) cc( x, y, z ) );
78  if( is != es )
79  out( x, y, z, t ) = (O) is->second; // RISK OF OVERFLOW on char types
80  }
81  }
82 
83  template<typename T, typename O>
84  void ConnectedComponentEngine<AimsData<T>, AimsData<O> >::connectedInFrame(
85  const AimsData<T>& data,
86  AimsData<O>& out,
87  Connectivity::Type connectivity,
88  std::multimap<size_t, O>& compSizes,
89  int t,
90  const T & backg,
91  bool bin,
92  bool verbose )
93  {
94  int x = 0, y = 0, z = 0, n = 0;
95  int dimX = data.dimX();
96  int dimY = data.dimY();
97  int dimZ = data.dimZ();
98 
99  out = 0;
100 
101  //
102  // boolean volume to say if a voxel is already used
103  //
104 
105  AimsData<byte> flag( dimX, dimY, dimZ );
106 
107  flag = false;
108  ForEach3d( flag, x, y, z )
109  if ( data( x, y, z, t ) == backg )
110  flag( x, y, z ) = true;
111 
112  Connectivity cd( data.oLine(), data.oSlice(), connectivity );
113  //Connectivity cf( flag.oLine(), flag.oSlice(), connectivity );
114 
115 
116  O label = 1;
117  Point3dl pos, newpos;
118  std::queue<Point3dl> que;
119  T val;
120  size_t sz;
121 
122  //
123  // track connected components
124  //
125  for ( z = 0; z < dimZ; ++z )
126  {
127  if( verbose )
128  std::cout << "\rz: " << z << std::flush;
129 
130  for ( y = 0; y < dimY; ++y )
131  for ( x = 0; x < dimX; ++x )
132  if( !flag( x, y, z ) )
133  {
134  val = data( x, y, z, t );
135  que.push( Point3dl( x, y, z ) );
136  flag( x, y, z ) = true;
137  sz = 0;
138  while ( !que.empty() )
139  {
140  pos = que.front();
141  que.pop();
142  out( pos ) = label; // RISK of overflow in char types
143  ++sz;
144  for ( n = 0; n < cd.nbNeighbors(); n++ )
145  {
146  newpos = pos + Point3dl(cd.xyzOffset( n )[0],
147  cd.xyzOffset( n )[1],
148  cd.xyzOffset( n )[2]);
149 
150  if ( newpos[0] >= 0 &&
151  newpos[0] < dimX &&
152  newpos[1] >= 0 &&
153  newpos[1] < dimY &&
154  newpos[2] >= 0 &&
155  newpos[2] < dimZ )
156 
157  if ( !flag( newpos )
158  && ( bin || data( newpos[0], newpos[1], newpos[2], t ) == val ) )
159  {
160  flag( newpos ) = true;
161  que.push( newpos );
162  }
163  }
164  }
165  /*std::cout << "comp. " << label << ", val: " << val << " ("
166  << sz << " voxels)\n";*/
167 
168  compSizes.insert( std::pair<size_t, O>( sz, label ) );
169  ++label;
170  }
171  }
172 
173  if( verbose )
174  {
175  std::cout << std::endl;
176  std::cout << label << " components" << std::endl;
177  }
178  }
179 
180 
181  template<typename T, typename O>
182  void ConnectedComponentEngine<AimsData<T>, AimsData<O> >::connected(
183  const AimsData<T>& data,
184  AimsData<O>& out,
185  Connectivity::Type connectivity,
186  std::map<O, size_t>& valids,
187  const T & backg, bool bin,
188  size_t minSize, size_t maxSize,
189  size_t numMax, bool verbose )
190  {
191  std::multimap<size_t, size_t> compSizes;
192  int t=0;
193  int dimX = data.dimX();
194  int dimY = data.dimY();
195  int dimZ = data.dimZ();
196  int dimT = data.dimT() ;
197 
198  for( t = 0 ; t < dimT ; ++t )
199  {
200  // Get AimsData of size_t to avoid risk of overflow in char types
201  // before filtering
202  AimsData<size_t> cc( dimX, dimY, dimZ );
203 
204  ConnectedComponentEngine<AimsData<T>, AimsData<size_t> >
205  ::connectedInFrame( data,
206  cc,
207  connectivity,
208  compSizes,
209  t,
210  backg,
211  bin,
212  verbose );
213 
214  // Filter small comps
215  std::multimap<size_t, size_t>::reverse_iterator
216  im, em = compSizes.rend();
217 
218  O label = 1;
219 
220  for( im = compSizes.rbegin();
221  im != em && ( numMax == 0 || static_cast<size_t>(label) <= numMax ); ++im )
222  {
223  if ((minSize ==0 || im->first >= minSize) && (maxSize == 0 || im->first <= maxSize))
224  {
225  if( verbose )
226  std::cout << "component " << std::setw( 4 ) << im->second
227  << " : " << std::setw( 8 ) << im->first
228  << " points" << std::endl;
229  valids[ im->second ] = static_cast<size_t>( label++ );
230  }
231  }
232 
234  ::filterInFrame( cc, out, valids, t, verbose );
235 
236  if( verbose )
237  std::cout << "after filtering: " << valids.size() << " components\n";
238 
239  }
240  }
241 
242  template <typename T>
244  const AimsData<T>& data,
245  Connectivity::Type connectivity,
246  const T & backgrnd, bool bin,
247  size_t minsize, size_t maxsize,
248  size_t maxcomp, bool verbose )
249  {
250  AimsBucket<Void> *cbk;
251  std::unique_ptr<AimsBucket<Void> > abk;
252  if( minsize == 0 && maxsize == 0 && maxcomp == 0 )
253  cbk = &components;
254  else
255 
256  {
257 
258  abk.reset( new AimsBucket<Void> );
259  cbk = abk.get();
260  }
261  AimsBucket<Void> & component = *cbk;
262 
263  int x=0, y=0, z=0, t=0, n=0;
264 
265  int dimX = data.dimX();
266  int dimY = data.dimY();
267  int dimZ = data.dimZ();
268  int dimT = data.dimT() ;
269 
270 
271 
272  //
273  // boolean volume to say if a voxel is already used
274  //
275 
276  for( t = 0 ; t < dimT ; ++t ){
277  AimsData<byte> flag( dimX, dimY, dimZ );
278  flag = false;
279  ForEach3d( flag, x, y, z )
280  if ( data( x, y, z, t ) == backgrnd )
281  flag( x, y, z ) = true;
282 
283  Connectivity cd( data.oLine(), data.oSlice(), connectivity );
284  //Connectivity cf( flag.oLine(), flag.oSlice(), connectivity );
285  size_t label = 1;
286  AimsBucketItem<Void> item,newItem;
287  std::queue< AimsBucketItem< Void > > que;
288  T val;
289 
290 
291 
292  //
293  // track connected components
294  //
295  for ( z = 0; z < dimZ; ++z )
296  {
297  if( verbose )
298  std::cout << "\rz: " << z << std::flush;
299  for ( y = 0; y < dimY; ++y )
300  for ( x = 0; x < dimX; ++x )
301  {
302  if( !flag( x, y, z ) )
303  {
304 
305  val = data( x, y, z );
306  item.location() = Point3d( x, y, z );
307  que.push( item );
308  flag( x, y, z ) = true;
309  std::list<AimsBucketItem<Void> > & bk = component[ label ];
310  while ( !que.empty() )
311  {
312  item.location() = que.front().location();
313  que.pop();
314  bk.push_back( item );
315  for ( n = 0; n < cd.nbNeighbors(); n++ )
316  {
317  newItem.location() = item.location()
318  + cd.xyzOffset( n );
319  if ( newItem.location().item( 0 ) >= 0 &&
320  newItem.location().item( 0 ) < dimX &&
321  newItem.location().item( 1 ) >= 0 &&
322  newItem.location().item( 1 ) < dimY &&
323  newItem.location().item( 2 ) >= 0 &&
324  newItem.location().item( 2 ) < dimZ )
325 
326  if ( flag( newItem.location() ) == false
327  && ( bin || data( newItem.location() )
328  == val ) )
329  {
330  flag( newItem.location() ) = true;
331  que.push( newItem );
332  }
333  }
334  }
335  ++label;
336  }
337  }
338  }
339  if( verbose )
340  std::cout << std::endl;
341 
342  // filtering
343  if( minsize == 0 && maxsize == 0 && maxcomp == 0 )
344  return;
345 
346  AimsBucket<Void>::iterator i, e = component.end();
347  std::multimap<unsigned, std::list<AimsBucketItem<Void> > *> comps;
348  for( i=component.begin(); i!=e; ++i )
349  if(( minsize == 0 || i->second.size() >= minsize ) && ( maxsize == 0 || i->second.size() <= maxsize ))
350  comps.insert( std::pair<unsigned, std::list<AimsBucketItem<Void> > *>
351  ( i->second.size(),&i->second ) );
352  std::multimap<unsigned,
353  std::list<AimsBucketItem<Void> > *>::reverse_iterator
354  im, em = comps.rend();
355  label = 0;
356  for( im=comps.rbegin(); im!=em && label < maxcomp; ++im )
357  components[ label++ ] = *im->second;
358  }
359  }
360 
361  namespace internal
362  {
363 
364  template <typename T> inline
365  bool _nulltesttemplate_iseq( const T & x, const T & val )
366  {
367  return x == val;
368  }
369 
370  template<> inline
371  bool _nulltesttemplate_iseq( const Void &, const Void & )
372  {
373  return false;
374  }
375 
376  }
377 
378 
379  template <typename T>
381  const BucketMap<T>& data,
382  Connectivity::Type connectivity,
383  const T & backg, bool bin,
384  size_t minsize, size_t maxsize,
385  size_t maxcomp, bool )
386  {
387  AimsBucket<Void> *cbk;
388  std::unique_ptr<AimsBucket<Void> > abk;
389  if( minsize == 0 && maxsize == 0 && maxcomp == 0 )
390  cbk = &components;
391  else
392  {
393  abk.reset( new AimsBucket<Void> );
394  cbk = abk.get();
395  }
396  AimsBucket<Void> & component = *cbk;
397 
398 
399  //
400  // boolean bucket to say if a voxel is already used
401  //
402  BucketMap<byte> flags;
403  BucketMap<byte>::Bucket & flag = flags[0];
404  BucketMap<byte>::Bucket::iterator ifl, efl = flag.end();
405  const typename BucketMap<T>::Bucket & b = data.begin()->second;
406  typename BucketMap<T>::Bucket::const_iterator ib, eb = b.end();
407  int n;
408 
409  for( ib=b.begin(); ib!=eb; ++ib )
410  flag[ ib->first ]
411  = internal::_nulltesttemplate_iseq( ib->second, backg );
412 
413  Connectivity cd( 0, 0, connectivity );
414  //Connectivity cf( flag.oLine(), flag.oSlice(), connectivity );
415  size_t label = 1;
416  AimsBucketItem<Void> item,newItem;
417  std::queue< AimsBucketItem< Void > > que;
418  T val;
419 
420  //
421  // track connected components
422  //
423  for( ib=b.begin(); ib!=eb; ++ib )
424  {
425  ifl = flag.find( ib->first );
426  if( !ifl->second )
427  {
428  val = ib->second;
429  item.location() = ib->first;
430  que.push( item );
431  ifl->second = true;
432 // cout << "comp. " << label << ", val: " << val << std::endl;
433  std::list<AimsBucketItem<Void> > & bk = component[ label ];
434  while ( !que.empty() )
435  {
436  item.location() = que.front().location();
437  que.pop();
438  bk.push_back( item );
439  for ( n = 0; n < cd.nbNeighbors(); n++ )
440  {
441  newItem.location() = item.location() + cd.xyzOffset( n );
442  ifl = flag.find( newItem.location() );
443  if( ifl != efl && ifl->second == false
444  && ( bin
445  || b.find( newItem.location() )->second == val ) )
446  {
447  ifl->second = true;
448  que.push( newItem );
449  }
450  }
451  }
452  //std::cout << "(" << bk.size() << " voxels)\n";
453  ++label;
454  }
455  }
456 
457  // filtering
458  if( minsize == 0 && maxcomp == 0 )
459  return;
460 
461  AimsBucket<Void>::iterator i, e = component.end();
462  std::multimap<unsigned, std::list<AimsBucketItem<Void> > *> comps;
463  for( i=component.begin(); i!=e; ++i )
464  if(( minsize == 0 || i->second.size() >= minsize ) && ( maxsize == 0 || i->second.size() <= maxsize ))
465  comps.insert( std::pair<unsigned, std::list<AimsBucketItem<Void> > *>
466  ( i->second.size(),&i->second ) );
467  std::multimap<unsigned,
468  std::list<AimsBucketItem<Void> > *>::reverse_iterator
469  im, em = comps.rend();
470  label = 0;
471  for( im=comps.rbegin(); im!=em && label<maxcomp; ++im )
472  components[ label++ ] = *im->second;
473  }
474 
475 
476  template <typename T>
478  Connectivity::Type connectivity,
479  const T & backgrnd, bool bin,
480  size_t minsize, size_t maxsize,
481  size_t maxcomp,
482  bool verbose )
483  {
484  AimsBucket<Void> comps;
485  AimsConnectedComponent( comps, data, connectivity, backgrnd, bin, minsize, maxsize,
486  maxcomp, verbose );
487  AimsBucket<Void>::iterator i, e = comps.end();
488  std::list<AimsBucketItem<Void> >::iterator ic, ec;
489  typename BucketMap<T>::iterator ib, eb = data.end();
490  typename BucketMap<T>::Bucket::iterator ibb, ebb;
491 
492  // clear input bucket
493  for( ib=data.begin(); ib!=eb; ++ib )
494  for( ibb=ib->second.begin(), ebb=ib->second.end(); ibb!=ebb; ++ibb )
495  ibb->second = 0;
496  // fill it
497  typename BucketMap<T>::Bucket & bk = data.begin()->second;
498  for( i=comps.begin(); i!=e; ++i )
499  for( ic=i->second.begin(), ec=i->second.end(); ic!=ec; ++ic )
500  bk[ ic->location() ] = i->first + 1;
501  }
502 
503 
504  template <typename T>
506  const AimsData<T>& data,
507  Connectivity::Type connectivity,
508  const T & backgrnd, bool bin,
509  size_t minsize, size_t maxsize,
510  size_t maxcomp, bool verbose )
511  {
512  AimsBucket<Void> *cbk;
513 // ajout pour retourner l'image de labels des composantes
514  AimsData<int16_t> labelImage (data.dimX(), data.dimY(), data.dimZ());
515  labelImage = 0;
516  std::unique_ptr<AimsBucket<Void> > abk;
517  if( minsize == 0 && maxsize == 0 && maxcomp == 0 )
518  cbk = &components;
519  else
520 
521  {
522 
523  abk.reset( new AimsBucket<Void> );
524  cbk = abk.get();
525  }
526  AimsBucket<Void> & component = *cbk;
527 
528  int x=0, y=0, z=0, t=0, n=0;
529 
530  int dimX = data.dimX();
531  int dimY = data.dimY();
532  int dimZ = data.dimZ();
533  int dimT = data.dimT() ;
534 
535 
536 
537 
538 // boolean volume to say if a voxel is already used
539 
540 
541  for( t = 0 ; t < dimT ; ++t ){
542  AimsData<byte> flag( dimX, dimY, dimZ );
543  flag = false;
544  ForEach3d( flag, x, y, z )
545  if ( data( x, y, z, t ) == backgrnd )
546  flag( x, y, z ) = true;
547 
548  Connectivity cd( data.oLine(), data.oSlice(), connectivity );
549  Connectivity cf( flag.oLine(), flag.oSlice(), connectivity );
550  size_t label = 1;
551  AimsBucketItem<Void> item,newItem;
552  std::queue< AimsBucketItem< Void > > que;
553  T val;
554 
555 
556 // track connected components
557 
558  for ( z = 0; z < dimZ; ++z )
559  {
560  if( verbose )
561  std::cout << "\rz: " << z << std::flush;
562  for ( y = 0; y < dimY; ++y )
563  for ( x = 0; x < dimX; ++x )
564  {
565 
566  if( !flag( x, y, z ) )
567  {
568 
569  val = data( x, y, z );
570  item.location() = Point3d( x, y, z );
571 
572  labelImage (x, y, z) = label;
573  que.push( item );
574  flag( x, y, z ) = true;
575 // std::cout << "comp. " << lcbkabel << ", val: " << val
576 // << std::endl;
577  std::list<AimsBucketItem<Void> > & bk = component[ label ];
578  while ( !que.empty() )
579  {
580  item.location() = que.front().location();
581  que.pop();
582  bk.push_back( item );
583  labelImage (item.location()) =label;
584  for ( n = 0; n < cd.nbNeighbors(); n++ )
585  {
586  newItem.location() = item.location()
587  + cd.xyzOffset( n );
588  if ( newItem.location().item( 0 ) >= 0 &&
589  newItem.location().item( 0 ) < dimX &&
590  newItem.location().item( 1 ) >= 0 &&
591  newItem.location().item( 1 ) < dimY &&
592  newItem.location().item( 2 ) >= 0 &&
593  newItem.location().item( 2 ) < dimZ )
594 
595  if ( flag( newItem.location() ) == false
596  && ( bin || data( newItem.location() )
597  == val ) )
598  {
599  flag( newItem.location() ) = true;
600  que.push( newItem );
601  labelImage (newItem.location()) = label;
602  }
603  }
604  }
605 // std::cout << "(" << bk.size() << " voxels)\n";
606  ++label;
607  }
608  }
609  }
610  if( verbose )
611  std::cout << std::endl;
612 
613 // filtering probleme filtrage
614  if( minsize == 0 && maxsize == 0 && maxcomp == 0 )
615  return labelImage;
616 
617  AimsBucket<Void>::iterator i, e = component.end();
618  std::multimap<unsigned, std::list<AimsBucketItem<Void> > *> comps;
619  for( i=component.begin(); i!=e; ++i )
620  if(( minsize == 0 || i->second.size() >= minsize ) && (maxsize == 0 || i->second.size() <= maxsize ))
621  comps.insert( std::pair<unsigned, std::list<AimsBucketItem<Void> > *>
622  ( i->second.size(),&i->second ) );
623 
624  std::multimap<unsigned,
625  std::list<AimsBucketItem<Void> > *>::reverse_iterator
626  im, em = comps.rend();
627  label = 0;
628  labelImage = 0;
629  for( im=comps.rbegin(); im!=em && (label < maxcomp || maxcomp == 0); ++im ){
630  std::list<AimsBucketItem<Void> > bucket = *im->second;
631  std::list<AimsBucketItem<Void> >::iterator ite, iteend = bucket.end();
632  for (ite = bucket.begin(); ite != iteend ; ite ++ ) {
633  labelImage ((*ite).location()) = label;
634  }
635  components[ label++ ] = *im->second;
636  }
637  }
638  return labelImage;
639  }
640 
641 }
642 
643 #endif
644 
const Point3d & xyzOffset(int n) const
Get the X/Y/Z offsets of the nth element.
Definition: connectivity.h:104
int dimZ() const
int oLine() const
Offset between 2 consecutive lines.
Definition: border.h:229
#define ForEach3d(thing, x, y, z)
Type
The different kinds of connectivity.
Definition: connectivity.h:54
int dimY() const
bool _nulltesttemplate_iseq(const T &x, const T &val)
Definition: component_d.h:365
The class for EcatSino data write operation.
Definition: border.h:44
int nbNeighbors() const
Get the number of neighbors for that connectivity.
Definition: connectivity.h:100
int oSlice() const
Offset between 2 consecutive slices.
Definition: border.h:243
const AimsVector< short, 3 > & location() const
Get a const reference to the location of the bucket item.
Definition: item.h:92
An alternate, ordered, representation for buckets (voxels lists).
Definition: bucket.h:57
std::map< Point3d, T, BucketMapLess > Bucket
Definition: bucketMap.h:102
Topology of a data container.
Definition: connectivity.h:50
std::map< int, std::list< AimsBucketItem< T > > >::iterator iterator
Definition: bucket.h:73
The bucket base class to manage packages of points associated to their value during time...
Definition: bucket.h:48
void AimsConnectedComponent(AimsData< T > &data, aims::Connectivity::Type connectivity, std::map< T, size_t > &valids, const T &backgrnd=0, bool bin=true, size_t minSize=0, size_t maxSize=0, size_t numMax=0, bool verbose=true)
Definition: component.h:116
The template base class for all types of bucket items.
Definition: item.h:47
std::map< int, Bucket >::iterator iterator
Definition: bucketMap.h:103
AimsData< int16_t > AimsLabeledConnectedComponent(AimsBucket< Void > &component, const AimsData< T > &data, aims::Connectivity::Type connectivity, const T &backgrnd=0, bool bin=true, size_t minsize=0, size_t maxSize=0, size_t maxcomp=0, bool verbose=true)
Definition: component_d.h:505
int dimT() const
const T & item(int d) const
int dimX() const