aimsalgo  5.1.2
Neuroimaging image processing
meshcc_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 
36 #ifndef AIMS_MESH_CONNECTIVITY_MESHCC_D_H
37 #define AIMS_MESH_CONNECTIVITY_MESHCC_D_H
38 
41 #include <cstdlib>
42 #include <map>
43 #include <set>
44 #include <stack>
45 #include <cstdlib>
46 //#include <stdio.h>
47 
48 
49 template<class T>
51  const Texture<T> & inittex, T threshold, int mode )
52 {
53  Texture<T> tex;
54  const std::vector<Point3df> & vert = mesh.vertex();
55  const std::vector< AimsVector<uint,3> > & poly = mesh.polygon();
56  unsigned i, n = vert.size();
57 
58  ASSERT( inittex.nItem() == n );
59  tex.reserve( n );
60 
61  // neighbours map
62 
63  std::map<unsigned, std::set<unsigned> > neighbours;
64  unsigned v1, v2, v3;
65  int nnode = 0;
66 
67  // init texture
68  std::cout << "Thresholding: " << threshold << std::endl;
69  if (mode==1)
70  {
71  for( i=0; i<n; ++i )
72  {
73  if(inittex.item(i)>=threshold) tex.push_back( FORBIDDEN );
74  else
75  {
76  tex.push_back( 0 );
77  nnode++;
78  }
79  }
80  }
81  else if (mode==0)
82  {
83  for( i=0; i<n; ++i )
84  {
85  if(inittex.item(i)<=threshold) tex.push_back( FORBIDDEN );
86  else
87  {
88  tex.push_back( 0 );
89  nnode++;
90  }
91  }
92  }
93  else
94  {
95  std::cerr << "AimsMeshLabelConnectedComponent : thresholding mode unknown" << std::endl;
96  exit(1);
97  }
98  std::cout << nnode << "/" << n << std::endl;
99 
100  //Detect connectivity
101  for( i=0; i<poly.size(); ++i )
102  {
103  v1 = poly[i][0];
104  v2 = poly[i][1];
105  v3 = poly[i][2];
106  if(tex.item(v1)!=FORBIDDEN
107  && tex.item(v2)!=FORBIDDEN)
108  {
109  neighbours[v1].insert( v2 );
110  neighbours[v2].insert( v1 );
111  }
112  if(tex.item(v1)!=FORBIDDEN
113  && tex.item(v3)!=FORBIDDEN)
114  {
115  neighbours[v1].insert( v3 );
116  neighbours[v3].insert( v1 );
117  }
118  if(tex.item(v2)!=FORBIDDEN
119  && tex.item(v3)!=FORBIDDEN)
120  {
121  neighbours[v2].insert( v3 );
122  neighbours[v3].insert( v2 );
123  }
124  }
125 
126  T label = 0;
127  unsigned point;
128  std::stack<unsigned> current;
129  std::set<unsigned>::iterator in, fn;
130 
131 
132  printf("Computing connected component\n");
133  fflush(stdout);
134  for( i=0; i<n; ++i )
135  {
136  if(tex.item(i)==0)
137  {
138  label++;
139  current.push(i);
140  fflush(stdout);
141  while(!current.empty())
142  {
143  point = current.top();
144  current.pop();
145  tex.item(point)=label;
146  for( in=neighbours[point].begin(), fn=neighbours[point].end(); in!=fn; ++in )
147  {
148  if(tex.item(*in)==0) current.push(*in);
149  }
150  }
151  }
152  }
153  std::cout << "nb cc: " << label << std::endl;
154 
155  return tex;
156 }
157 
158 
159 template<class T>
161  const Texture<T> & inittex, const T lab )
162 {
163  Texture<T> tex;
164  const std::vector<Point3df> & vert = mesh.vertex();
165  const std::vector< AimsVector<uint,3> > & poly = mesh.polygon();
166  unsigned i, n = vert.size();
167 
168  ASSERT( inittex.nItem() == n );
169  tex.reserve( n );
170 
171  // init texture
172  for (i=0; i<n; ++i)
173  if (inittex.item(i) == lab)
174  tex.push_back(0);
175  else
176  tex.push_back(FORBIDDEN);
177 
178  //Detect connectivity
179  std::map<unsigned, std::set<unsigned> > neighbours;
180  unsigned v1, v2, v3;
181  for( i=0; i<poly.size(); ++i )
182  {
183  v1 = poly[i][0];
184  v2 = poly[i][1];
185  v3 = poly[i][2];
186  if(tex.item(v1)!=FORBIDDEN
187  && tex.item(v2)!=FORBIDDEN
188  && inittex.item(v1) == inittex.item(v2) )
189 
190  {
191  neighbours[v1].insert( v2 );
192  neighbours[v2].insert( v1 );
193  }
194  if(tex.item(v1)!=FORBIDDEN
195  && tex.item(v3)!=FORBIDDEN
196  && inittex.item(v1) == inittex.item(v3) )
197  {
198  neighbours[v1].insert( v3 );
199  neighbours[v3].insert( v1 );
200  }
201  if(tex.item(v2)!=FORBIDDEN
202  && tex.item(v3)!=FORBIDDEN
203  && inittex.item(v2) == inittex.item(v3) )
204  {
205  neighbours[v2].insert( v3 );
206  neighbours[v3].insert( v2 );
207  }
208  }
209 
210  T label = 0;
211  unsigned inc =0;
212  unsigned point;
213  std::stack<unsigned> current;
214  std::set<unsigned>::iterator in, fn;
215 
216 
217  for( i=0; i<n; ++i )
218  {
219  if(tex.item(i)==0)
220  {
221  label++;
222  ++inc;
223  current.push(i);
224  while(!current.empty())
225  {
226  point = current.top();
227  current.pop();
228  tex.item(point)=label;
229  for( in=neighbours[point].begin(), fn=neighbours[point].end(); in!=fn; ++in )
230  {
231  if(tex.item(*in)==0) current.push(*in);
232  }
233  }
234  }
235  }
236 
237  return inc;
238 }
239 
240 
241 // Give a connected map of inittex.
242 // An initial connex area composed of different labels
243 // is splitted in sub-area of same labels
244 template<class T>
246  const Texture<T> & inittex, T threshold )
247 {
248  Texture<T> tex;
249  const std::vector<Point3df> & vert = mesh.vertex();
250  const std::vector< AimsVector<uint,3> > & poly = mesh.polygon();
251  unsigned i, n = vert.size();
252 
253  Texture<T> tex_ord;
254  std::map<T,std::set<unsigned> > labels;
255  std::multimap<unsigned, T> nbLabels;
256 
257  ASSERT( inittex.nItem() == n );
258  tex.reserve( n );
259  tex_ord.reserve( n );
260 
261  // neighbours map
262 
263  std::map<unsigned, std::set<unsigned> > neighbours;
264  unsigned v1, v2, v3;
265 
266 
267  // init texture
268  for( i=0; i<n; ++i )
269  {
270  if(inittex.item(i) < threshold)
271  {
272  tex.push_back( FORBIDDEN );
273  tex_ord.push_back( FORBIDDEN );
274  }
275  else
276  {
277  tex.push_back( 0 );
278  tex_ord.push_back( 0 );
279  }
280  }
281 
282  //Detect connectivity
283  for( i=0; i<poly.size(); ++i )
284  {
285  v1 = poly[i][0];
286  v2 = poly[i][1];
287  v3 = poly[i][2];
288  if(tex.item(v1)!=FORBIDDEN
289  && tex.item(v2)!=FORBIDDEN
290  && inittex.item(v1) == inittex.item(v2) )
291 
292  {
293  neighbours[v1].insert( v2 );
294  neighbours[v2].insert( v1 );
295  }
296  if(tex.item(v1)!=FORBIDDEN
297  && tex.item(v3)!=FORBIDDEN
298  && inittex.item(v1) == inittex.item(v3) )
299  {
300  neighbours[v1].insert( v3 );
301  neighbours[v3].insert( v1 );
302  }
303  if(tex.item(v2)!=FORBIDDEN
304  && tex.item(v3)!=FORBIDDEN
305  && inittex.item(v2) == inittex.item(v3) )
306  {
307  neighbours[v2].insert( v3 );
308  neighbours[v3].insert( v2 );
309  }
310  }
311 
312  T label = 0;
313  unsigned point;
314  std::stack<unsigned> current;
315  std::set<unsigned>::iterator in, fn;
316 
317  for( i=0; i<n; ++i )
318  if(tex.item(i) == 0)
319  {
320  label++;
321  current.push(i);
322  while(!current.empty())
323  {
324  point = current.top();
325  current.pop();
326  tex.item(point)=label;
327  labels[label].insert(point);
328  for( in=neighbours[point].begin(), fn=neighbours[point].end(); in!=fn; ++in )
329  {
330  if(tex.item(*in)==0) current.push(*in);
331  }
332  }
333  nbLabels.insert( std::pair<unsigned, T> ( labels[label].size(), label ) );
334  }
335 
336  std::cout << "Nb of cc : "<< label << std::endl;
337 
338  typename std::multimap<unsigned,T>::reverse_iterator rit;
339  std::map<T, T> nbLabels_ord;
340  T lab = 0;
341  for (rit=nbLabels.rbegin(); rit!=nbLabels.rend(); ++rit)
342  {
343  nbLabels_ord[rit->second] = ++lab;
344  std::cout << "The " << lab << "th cc has " << rit->first << " points" << std::endl;
345  }
346 
347  typename std::map<T, T>::iterator it;
348  for (i=0;i<n;++i)
349  if (tex_ord.item(i) == FORBIDDEN)
350  tex_ord.item(i) = 0;
351  else
352  {
353  for (it=nbLabels_ord.begin(); it!=nbLabels_ord.end(); ++it)
354  {
355  if (tex.item(i) == it->first)
356  {
357  tex_ord.item(i) = it->second;
358  break;
359  }
360  }
361  }
362 
363  return tex_ord;
364 }
365 
366 template<class T>
368  const AimsSurface<3,Void> & mesh, const Texture<T> & inittex, T cc_label,
369  const T & background, unsigned long ncomp, unsigned long min_npts,
370  float min_surf )
371 {
372  Texture<long> tex;
373  Texture<T> out_tex;
374  const std::vector<Point3df> & vert = mesh.vertex();
375  const std::vector< AimsVector<uint,3> > & poly = mesh.polygon();
376  unsigned i, n = vert.size();
377 
378  std::map<long, std::set<unsigned> > labels;
379  std::multimap<unsigned, long> nbLabels;
380  std::map<long, float> areaLabels;
381 
382  ASSERT( inittex.nItem() == n );
383  tex.reserve( n );
384  out_tex.reserve( n );
385 
386  // neighbours map
387 
388  std::map<unsigned, std::set<unsigned> > neighbours;
389  unsigned v1, v2, v3;
390  std::vector<float> areas( inittex.nItem(), 0. );
391  float surf;
392 
393 
394  // init texture
395  for( i=0; i<n; ++i )
396  {
397  if( inittex.item(i) != cc_label )
398  tex.push_back( FORBIDDEN );
399  else
400  tex.push_back( 0 );
401  }
402 
403  // Detect connectivity
404  for( i=0; i<poly.size(); ++i )
405  {
406  v1 = poly[i][0];
407  v2 = poly[i][1];
408  v3 = poly[i][2];
409 
410  // triangle area / 3 (1/3 assigned to each vertex)
411  surf = ( vert[v2] - vert[v1] ).dot( vert[v3] - vert[v1] ) / 6;
412  areas[v1] += surf;
413  areas[v2] += surf;
414  areas[v3] += surf;
415 
416  if( tex.item(v1)!=FORBIDDEN
417  && tex.item(v2)!=FORBIDDEN )
418 
419  {
420  neighbours[v1].insert( v2 );
421  neighbours[v2].insert( v1 );
422  }
423  if(tex.item(v1)!=FORBIDDEN
424  && tex.item(v3)!=FORBIDDEN )
425  {
426  neighbours[v1].insert( v3 );
427  neighbours[v3].insert( v1 );
428  }
429  if(tex.item(v2)!=FORBIDDEN
430  && tex.item(v3)!=FORBIDDEN )
431  {
432  neighbours[v2].insert( v3 );
433  neighbours[v3].insert( v2 );
434  }
435  }
436 
437  T label = 0;
438  unsigned point;
439  std::stack<unsigned> current;
440  std::set<unsigned>::iterator in, fn;
441 
442 
443  for( i=0; i<n; ++i )
444  if(tex.item(i) == 0)
445  {
446  label++;
447  current.push(i);
448  while(!current.empty())
449  {
450  point = current.top();
451  current.pop();
452  tex.item(point)=label;
453  labels[label].insert(point);
454  areaLabels[label] += areas[point];
455  for( in=neighbours[point].begin(), fn=neighbours[point].end(); in!=fn;
456  ++in )
457  {
458  if(tex.item(*in)==0)
459  current.push(*in);
460  }
461  }
462  nbLabels.insert( std::make_pair( labels[label].size(), label) );
463  std::cout << "The " << label << " th cc (" << cc_label << ") has "
464  << labels[label].size() << " points, area: " << areaLabels[label]
465  << " mm2" << std::endl;
466  }
467 
468  std::cout << "Nb of cc : "<< label << std::endl;
469 
470  std::multimap<unsigned, long>::reverse_iterator il, el=nbLabels.rend();
471  std::set<long> allowed_labels;
472  unsigned long c;
473 
474  // filter out labels
475  for( il=nbLabels.rbegin(), c=0; il!=el; ++il, ++c )
476  {
477  if( ncomp != 0 && c >= ncomp )
478  break;
479  if( min_npts != 0 && il->first < min_npts )
480  continue;
481  if( min_surf != 0. && areaLabels[il->second] < min_surf )
482  continue;
483  allowed_labels.insert( il->second );
484  }
485  std::cout << "keeping " << allowed_labels.size() << " components"
486  << std::endl;
487 
488  for( i=0; i<n; ++i )
489  {
490  if( tex.item(i) == FORBIDDEN )
491  out_tex.push_back( inittex.item(i) );
492  else
493  if( allowed_labels.find( tex.item(i) ) != allowed_labels.end() )
494  out_tex.push_back( cc_label );
495  else
496  out_tex.push_back( background );
497  }
498 
499  return out_tex;
500 }
501 
502 
503 #endif
#define ASSERT(EX)
const std::vector< Point3df > & vertex() const
const std::vector< AimsVector< uint, D > > & polygon() const
void reserve(size_t size)
size_t nItem() const
const T & item(int n) const
void push_back(const T &item)
const int FORBIDDEN
hum, should not be there as a global, non-namespaced variable...
Definition: meshcc.h:78
Texture< T > AimsMeshLabelConnectedComponent2Texture(const AimsSurface< 3, Void > &mesh, const Texture< T > &inittex, T threshold)
Definition: meshcc_d.h:245
unsigned AimsMeshLabelNbConnectedComponent(const AimsSurface< 3, Void > &mesh, const Texture< T > &inittex, const T lab)
Definition: meshcc_d.h:160
Texture< T > AimsMeshFilterConnectedComponent(const AimsSurface< 3, Void > &mesh, const Texture< T > &inittex, T cc_label, const T &background, unsigned long ncomp, unsigned long min_npts, float min_surf)
Split label "label" into connected components, then filter smaller ones out.
Definition: meshcc_d.h:367
Texture< T > AimsMeshLabelConnectedComponent(const AimsSurface< 3, Void > &mesh, const Texture< T > &inittex, T threshold, int mode)
Definition: meshcc_d.h:50