aimsalgo  5.1.2
Neuroimaging image processing
clusterArg_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 #ifndef AIMS_ROI_CLUSTERARG_D_H
36 #define AIMS_ROI_CLUSTERARG_D_H
37 
38 #include <aims/roi/clusterArg.h>
39 #include <aims/utility/threshold.h>
43 #include <aims/resampling/motion.h>
44 #include <aims/graph/graphmanip.h>
45 #include <aims/bucket/bucket.h>
46 #include <aims/mesh/surface.h>
48 #include <aims/mesh/mesher.h>
49 #include <graph/graph/graph.h>
50 #include <cartobase/smart/rcptr.h>
52 
53 namespace aims
54 {
55 
56  template<typename T>
58  const carto::rc_ptr<carto::Volume<T> > & data )
59  {
60  // graph and global attributes
61 
62  std::string graphsyntax = gr.getSyntax();
63  std::string vertexsyntax = "cluster";
64  GraphElementCode bec, mec;
65 
66  enum GraphType
67  {
68  Cluster,
69  Fold
70  };
71 
72  GraphType gtype = Cluster;
73 
74  // bucket element code
75  bec.objectType = "Bucket";
76  bec.dataType = "VOID";
78 
79  // mesh element code
80  mec.objectType = "Mesh";
81  mec.dataType = "VOID";
83 
84  if( graphsyntax == "CorticalFoldArg" )
85  {
86  gtype = Fold;
87  vertexsyntax = "fold";
88 
89  bec.attribute = "aims_ss";
90  bec.global_index_attribute = "ss_label";
91  bec.local_file_attribute = "ss_filename";
92  bec.global_filename = "ss.bck";
93  bec.id = "ss";
94 
95  mec.attribute = "aims_Tmtktri";
96  mec.global_index_attribute = "Tmtktri_label";
97  mec.local_file_attribute = "Tmtktri_filename";
98  mec.global_filename = "tmtktri.mesh";
99  mec.id = "Tmtktri";
100  }
101  else
102  {
103  bec.attribute = "aims_bucket";
104  bec.global_index_attribute = "bucket_label";
105  bec.local_file_attribute = "bucket_filename";
106  bec.global_filename = "cluster.bck";
107  bec.id = "cluster";
108 
109  mec.attribute = "aims_Tmtktri";
110  mec.global_index_attribute = "Tmtktri_label";
111  mec.local_file_attribute = "Tmtktri_filename";
112  mec.global_filename = "Tmtktri.mesh";
113  mec.id = "Tmtktri";
114  }
115  bec.syntax = vertexsyntax;
116  mec.syntax = vertexsyntax;
117 
118  Vertex *v;
119 
120  gr.setProperty( graphsyntax + "_VERSION", std::string( "1.0" ) );
121  std::vector<float> vs = data->getVoxelSize();
122  gr.setProperty( "voxel_size", vs );
123  std::vector<int> bb;
124  bb.push_back( 0 );
125  bb.push_back( 0 );
126  bb.push_back( 0 );
127  gr.setProperty( "boundingbox_min", bb );
128  bb[0] = data->getSizeX() - 1;
129  bb[1] = data->getSizeY() - 1;
130  bb[2] = data->getSizeZ() - 1;
131  gr.setProperty( "boundingbox_max", bb );
132  std::string outdir = _fileout;
133  std::string::size_type pos = outdir.rfind( '.' );
134  if( pos != std::string::npos )
135  outdir.erase( pos, outdir.length() - pos );
136  pos = outdir.rfind( '/' );
137  if( pos != std::string::npos )
138  outdir.erase( 0, pos + 1 );
139  outdir += ".data";
140  gr.setProperty( "filename_base", outdir );
141  std::vector<int> colors;
142  colors.push_back( 0 );
143  colors.push_back( 255 );
144  colors.push_back( 0 );
145  gr.setProperty( bec.local_file_attribute, colors );
146  gr.setProperty( bec.global_index_attribute, colors );
147 
149  objtable( new GraphElementTable );
150  std::map<std::string,GraphElementCode>
151  & cltab = (*objtable)[ vertexsyntax ];
152  cltab[ bec.id ] = bec;
153  if( _domesh )
154  {
155  cltab[ mec.id ] = mec;
156  gr.setProperty( mec.local_file_attribute, colors );
157  gr.setProperty( mec.global_index_attribute, colors );
158  }
159  gr.setProperty( "aims_objects_table", objtable );
160 
161  // thresholding
162 
163  bool thresh = false;
165 
166  if( _upth != FLT_MAX )
167  {
168  thresh = true;
169  if( _lowth != -FLT_MAX )
170  thtype = AIMS_BETWEEN;
171  else
172  {
173  thtype = AIMS_LOWER_OR_EQUAL_TO;
174  _lowth = _upth;
175  _upth = 0;
176  }
177  }
178  else if( _lowth != -FLT_MAX )
179  {
180  thresh = true;
181  thtype = AIMS_GREATER_OR_EQUAL_TO;
182  _upth = 0;
183  }
184  else if( _binarize )
185  {
186  thresh = true;
187  if( _lowth == -FLT_MAX )
188  {
189  _lowth = 0;
190  thtype = AIMS_GREATER_THAN;
191  }
192  // _upth = 0;
193  }
194 
195  carto::VolumeRef<T> datat;
196 
197  if( thresh )
198  {
199  AimsThreshold<T, T> th( thtype, (T) _lowth,
200  (T) _upth );
201  std::cout << "threshold: " << _lowth << ", bin: " << _binarize
202  << std::endl;
203  if( _binarize )
204  datat = th.bin( data );
205  else
206  datat = th( data );
207  }
208  else
209  datat = data;
210 
211  // connected components
212 
213  std::cout << "extracting connected components...\n";
214 
215  carto::VolumeRef<short> datac( datat.getSize(), 1 );
217  conv2( true );
218  conv2.convert( datat, datac );
219  datac.fillBorder( -1 );
220 
221  // find background level
222  short bg = 0;
223  bool bgfound = false;
224  int x, y, z;
225  std::vector<int> dim = datat->getSize();
226 
227  for( z=0; z<dim[2] && !bgfound; ++z )
228  for( y=0; y<dim[1] && !bgfound; ++y )
229  for( x=0; x<dim[0]; ++x )
230  if( datat( x, y, z ) == 0 )
231  {
232  bg = datac( x, y, z );
233  bgfound = true;
234  break;
235  }
236 
237  AimsConnectedComponent<short>( datac, _connectivity, bg, false, _minsize,
238  0, 0 );
239  std::cout << "done\n";
240 
241  // transform
242 
243  Motion motion;
244  if( !_matrix.empty() )
245  {
246  std::cout << "reading transformation...\n";
247  std::ifstream ms( _matrix.c_str() );
248  if( !ms )
249  {
250  std::cerr << "Can't open transformation file " << _matrix
251  << std::endl;
252  throw carto::file_error( _matrix );
253  }
254  std::vector<float> transl( 3 ), rot( 9 );
255  ms >> transl[0] >> transl[1] >> transl[2];
256  ms >> rot[0] >> rot[1] >> rot[2];
257  ms >> rot[3] >> rot[4] >> rot[5];
258  ms >> rot[6] >> rot[7] >> rot[8];
259  if( !ms )
260  {
261  std::cerr << "transformation file " << _matrix << " has wrong format\n";
262  throw carto::file_error( _matrix );
263  }
264  std::cout << "done\n";
265  // translation is in other form: t' = r^-1 * t
267  rm(0,0) = rot[0];
268  rm(0,1) = rot[1];
269  rm(0,2) = rot[2];
270  rm(1,0) = rot[3];
271  rm(1,1) = rot[4];
272  rm(1,2) = rot[5];
273  rm(2,0) = rot[6];
274  rm(2,1) = rot[7];
275  rm(2,2) = rot[8];
276  Motion mot2 = motion.inverse();
277  rm(0, 3) = transl[0];
278  rm(1, 3) = transl[1];
279  rm(2, 3) = transl[2];
280 
281  Point3df t2 = mot2.transform( transl[0], transl[1], transl[2] );
282  transl[0] = t2[0];
283  transl[1] = t2[1];
284  transl[2] = t2[2];
285  gr.setProperty( "Talairach_translation", transl );
286  gr.setProperty( "Talairach_rotation", rot );
287  // Talairach_scale ?
288  }
289 
290  // resampling
291  // well, we shouldn't resample anymore!
292 
293  // buckets
294 
295  std::cout << "converting to buckets...\n";
297  conv( true );
298  BucketMap<Void> bck;
299  conv.convert( datac, bck );
300  std::cout << "done, " << bck.size() << " buckets\n";
301 
302  // meshes
303 
304  std::map<size_t, AimsSurfaceTriangle> mesh;
305 
306  if( _domesh )
307  {
308  std::cout << "meshing components...\n";
309  std::map<size_t, std::list<AimsSurfaceTriangle> > meshl;
310  Mesher mesher;
311  mesher.setDecimation( 100.0, _deciMaxClearance, _deciMaxError, 120.0 );
312  mesher.setMinFacetNumber( _minFacetNumber );
313  mesher.setSmoothing( Mesher::LAPLACIAN, 5, 0.4 );
314  mesher.setSmoothingLaplacian( 180. );
315  mesher.doit( datac, meshl );
316  std::cout << "done\n";
317  //if( onenode )
318  //{
319  std::cout << "regrouping meshes...\n";
320  std::map<size_t, std::list<AimsSurfaceTriangle> >::iterator
321  im, em = meshl.end();
322  for( im=meshl.begin(); im!=em; ++im )
323  {
324  //std::cout << "* " << im->first << ", " << im->second.size();
325  AimsSurfaceTriangle & mesh2 = mesh[im->first];
326  //im->second.erase( im->second.begin() );
327  SurfaceManip::meshMerge( mesh2, im->second );
328  //std::cout << " -> " << mesh2.vertex().size() << " vertices\n";
329  }
330  std::cout << "done\n";
331  //}
332  }
333 
334  // vertices
335 
336  BucketMap<Void> *b;
337  BucketMap<Void>::iterator ib, eb = bck.end();
338  char num[50];
339  float voxvol = bck.sizeX() * bck.sizeY() * bck.sizeZ();
340  int index = 0;
342  Point3d pt;
344  std::vector<float> pf(3);
345  Point3df pm;
346 
347  std::cout << "making cluster vertices...\n";
348  for( ib=bck.begin(); ib!=eb; ++ib )
349  {
350  std::cout << "cluster " << ib->first << "..." << std::endl;
351  v = gr.addVertex( vertexsyntax );
352  b = new BucketMap<Void>;
353  b->setSizeXYZT( bck.sizeX(), bck.sizeY(), bck.sizeZ(), bck.sizeT() );
354  (*b)[0] = ib->second;
355  v->setProperty( bec.attribute, carto::rc_ptr<BucketMap<Void> >( b ) );
356  v->setProperty( "index", (int) ib->first );
357  pt = ib->second.begin()->first;
358  sprintf( num, "%d", (int) datat( pt[0], pt[1], pt[2] ) ); // label
359  v->setProperty( "name", std::string( num ) );
360  v->setProperty( "point_number", (int) ib->second.size() );
361  v->setProperty( "size", voxvol * ib->second.size() );
362  if( gtype == Fold )
363  {
364  v->setProperty( "skeleton_label", index++ );
365  v->setProperty( "ss_point_number", (int) ib->second.size() );
366  v->setProperty( "bottom_point_number", (int) 0 );
367  }
368  if( _domesh )
369  {
370  s = new AimsSurfaceTriangle( mesh[ ib->first ] );
371  v->setProperty( mec.attribute,
373  }
374  // cluster center
375  pf[0] = pf[1] = pf[2] = 0;
376  BucketMap<Void>::Bucket & bk = b->begin()->second;
377  for( ibb=bk.begin(), ebb=bk.end(); ibb!=ebb; ++ibb )
378  {
379  pf[0] += ibb->first[0];
380  pf[1] += ibb->first[1];
381  pf[2] += ibb->first[2];
382  }
383  pf[0] = vs[0] * pf[0] / bk.size();
384  pf[1] = vs[1] * pf[1] / bk.size();
385  pf[2] = vs[2] * pf[2] / bk.size();
386  v->setProperty( "gravity_center", pf );
387  // in talairach space
388  pm = motion.transform( pf[0], pf[1], pf[2] );
389  pf[0] = pm[0];
390  pf[1] = pm[1];
391  pf[2] = pm[2];
392  if( gtype == Fold )
393  v->setProperty( "refgravity_center", pf );
394  else
395  v->setProperty( "Talairach(mm)", pf );
396  sprintf( num, "%f %f %f", pf[0], pf[1], pf[2] );
397  v->setProperty( "label", std::string( num ) );
398  }
399  std::cout << "clusters created\n";
400 
401  // Relations ?
402  }
403 
404 }
405 
406 #endif
carto::VolumeRef< U > bin(const carto::VolumeRef< T > &sqv)
Vertex * addVertex(const std::string &s="")
Definition: mesher.h:53
void doit(const carto::rc_ptr< carto::Volume< short > > &thing, const std::string &name, const std::string &mode="binar")
@ LAPLACIAN
Definition: mesher.h:57
void setSmoothing(SmoothingType smoothType, int smoothIt, float smoothRate)
Smoothing.
void setDecimation(float deciReductionRate, float deciMaxClearance, float deciMaxError, float deciFeatureAngle)
Decimation.
void setMinFacetNumber(uint m)
Definition: mesher.h:189
void setSmoothingLaplacian(float smoothFeatureAngle)
AffineTransformation3d inverse() const
float sizeZ() const
void setSizeXYZT(float sizex, float sizey, float sizez, float sizet)
float sizeT() const
float sizeY() const
float sizeX() const
void make(Graph &gr, const carto::rc_ptr< carto::Volume< T > > &data)
Definition: clusterArg_d.h:57
T * iterator
static void meshMerge(AimsTimeSurface< D, T > &dst, const AimsTimeSurface< D, T > &add)
virtual void convert(const INP &in, OUTP &out) const
void convert(const INP &in, OUTP &out) const
void fillBorder(const T &value)
std::vector< int > getSize() const
Point3dd transform(double x, double y, double z) const
std::map< std::string, std::map< std::string, GraphElementCode > > GraphElementTable
std::string global_filename
std::string global_index_attribute
std::string local_file_attribute
AIMSDATA_API AimsTimeSurface< 3, Void > AimsSurfaceTriangle
threshold_t
AIMS_LOWER_OR_EQUAL_TO
AIMS_GREATER_OR_EQUAL_TO
AIMS_BETWEEN
AIMS_GREATER_THAN