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