aimsalgo  5.1.2
Neuroimaging image processing
diffusionSmoother_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_DIFFUSION_SMOOTHER_D_H
37 #define AIMS_DIFFUSION_SMOOTHER_D_H
38 
39 #include <cstdlib>
43 #include <stdlib.h>
44 #include <math.h>
45 #include <float.h>
46 
47 namespace aims {
48 
49 
50 template<typename T>
53 
54 template<typename T>
56 {
57  carto::VolumeRef<float> laplacian( 3, 3, 3, 1,
58  carto::AllocatorContext::fast() );
59  laplacian = 0.;
60  /* WARNING: this kernel is only suitable for isotropic, 1mm voxels.
61  Moreover I don't explain the 1/2 factor on the whole kernel
62  (I would expect coefs 1 -6 1 instead of 0.5 -3 0.5)
63  Anyway, this kernel is now completely rebuilt in doSmoothing() to
64  take into account voxel size, so it is not used as is.
65  (Denis, 2014/02/14)
66  */
67  laplacian(1,1,0) = laplacian(1,0,1) = laplacian(0,1,1) =
68  laplacian(2,1,1) = laplacian(1,2,1) = laplacian(1,1,2) = 0.5;
69  laplacian(1,1,1) = -3;
70 
71  return laplacian;
72 }
73 
74 template<class T>
76 {
77  if (maxiter < 0)
78  {
79  std::cerr << "diffusionConvolution Smoother: "
80  << "maxiter negative value is forbidden" << std::endl;
81  exit(EXIT_FAILURE);
82  }
83 }
84 
85 template<class T>
87  const carto::VolumeRef<T> & ima, int maxiter, bool verbose)
88 {
89  this->check(maxiter);
91  std::vector<float> vs = ima->getVoxelSize();
92  // rebuild the kernel accounting for possibly anisotropic voxel size
93  kernel(0,1,1) = kernel(2,1,1) = this->_dt / ( vs[0] * vs[0] );
94  kernel(1,0,1) = kernel(1,2,1) = this->_dt / ( vs[1] * vs[1] );
95  kernel(1,1,0) = kernel(1,1,2) = this->_dt / ( vs[2] * vs[2] );
96  kernel(1,1,1) = -this->_dt * (2. / (vs[0] * vs[0])
97  + 2. / (vs[1] * vs[1])
98  + 2. / (vs[2] * vs[2]) );
99  //
100  // 1 (center) + kernel * dt
101  kernel(1,1,1) = 1. + kernel(1,1,1);
102  /*
103  kernel(1,1,1) = 1. + kernel(1,1,1) * this->_dt;
104  kernel(1,1,0) = kernel(1,0,1) = kernel(0,1,1) =
105  kernel(2,1,1) = kernel(1,2,1) = kernel(1,1,2) = 0.5 * this->_dt;
106  */
107 
108  carto::VolumeRef<float> *tmp1, *tmp2, *swap;
109  AimsConvolution<float> convolution;
110 
111  std::vector<int> dim = ima->getSize();
113  carto::VolumeRef< float > imaF( dim ), ima2( dim );
114  conv.convert(ima, imaF);
115  tmp1 = &imaF; tmp2 = &ima2;
116 
117  for (int i = 0; i < maxiter; i++)
118  {
119  if (verbose) std::cout << "+" << std::flush;
120  if( _hasConstantSources )
121  {
122  int x, y, z;
123  for( z=0; z<dim[2]; ++z )
124  for( y=0; y<dim[1]; ++y )
125  for( x=0; x<dim[0]; ++x )
126  {
127  T & v = _constantSources( x, y, z );
128  if( v != _constantSourcesBackground )
129  (*tmp1)( x, y, z ) = v;
130  }
131  }
132  (*tmp2) = convolution.doit( *tmp1, kernel );
133  swap = tmp1;
134  tmp1 = tmp2;
135  tmp2 = swap;
136  }
137 
138  if( _hasConstantSources )
139  {
140  int x, y, z;
141  for( z=0; z<dim[2]; ++z )
142  for( y=0; y<dim[1]; ++y )
143  for( x=0; x<dim[0]; ++x )
144  {
145  T & v = _constantSources( x, y, z );
146  if( v != _constantSourcesBackground )
147  (*tmp1)( x, y, z ) = v;
148  }
149  }
150 
151  if (verbose) std::cout << "Finished" << std::endl;
153  conv2;
154  carto::VolumeRef<T> ima3( dim );
155  conv2.convert( (*tmp1), ima3);
156 
157  return ima3;
158 }
159 
160 
161 template<typename T>
163  const carto::VolumeRef<T> & sources, const T & bgr )
164 {
165  _constantSources = sources;
166  _constantSourcesBackground = bgr;
167  _hasConstantSources = true;
168 }
169 
170 
171 template <typename T>
173 {
174  _hasConstantSources = false;
175  _constantSources = carto::VolumeRef<T>();
176 }
177 
178 
179 template<typename T> carto::VolumeRef<T>
181 doSmoothing(const carto::VolumeRef<T> & ima, int maxiter, bool verbose)
182 {
183  this->check(maxiter);
185  std::vector<float> vs = ima->getVoxelSize();
186  // rebuild the kernel accounting for possibly anisotropic voxel size
187  kernel(0,1,1) = kernel(2,1,1) = this->_dt / ( vs[0] * vs[0] );
188  kernel(1,0,1) = kernel(1,2,1) = this->_dt / ( vs[1] * vs[1] );
189  kernel(1,1,0) = kernel(1,1,2) = this->_dt / ( vs[2] * vs[2] );
190  kernel(1,1,1) = -this->_dt * (2. / (vs[0] * vs[0])
191  + 2. / (vs[1] * vs[1])
192  + 2. / (vs[2] * vs[2]) );
193  //
194  // 1 (center) + kernel * dt
195  kernel(1,1,1) = 1. + kernel(1,1,1);
196  /*
197  kernel(1,1,1) = 1. + kernel(1,1,1) * this->_dt;
198  kernel(1,1,0) = kernel(1,0,1) = kernel(0,1,1) =
199  kernel(2,1,1) = kernel(1,2,1) = kernel(1,1,2) = 0.5 * this->_dt;
200  */
201 
202  carto::VolumeRef<float> *tmp1, *tmp2, *swap;
203  AimsMaskedConvolution<float> convolution( this->_mask,
204  this->_background, this->_safe );
205 
207  std::vector<int> dim = ima->getSize();
208  carto::VolumeRef< float > imaF( dim ), ima2( dim );
209  conv.convert(ima, imaF);
210  tmp1 = &imaF; tmp2 = &ima2;
211 
212  for (int i = 0; i < maxiter; i++)
213  {
214  if (verbose) std::cout << "+" << std::flush;
215  if (_has_neumann_condition)
216  update_neumann_conditions(*tmp1);
217  (*tmp2) = convolution.doit((*tmp1), kernel);
218  swap = tmp1;
219  tmp1 = tmp2;
220  tmp2 = swap;
221  }
222 
223  if (verbose) std::cout << "Finished" << std::endl;
225  conv2;
226  carto::VolumeRef<T> ima3( dim );
227  conv2.convert( (*tmp1), ima3);
228 
229  return ima3;
230 }
231 
232 
233 template<typename T> inline
235 add_neumann_condition(const Point3df &p)
236 {
237  _has_neumann_condition = true;
238  _neumann_conditions.push_back(p);
239 }
240 
241 
242 
243 template<typename T>
245 update_neumann_conditions(carto::VolumeRef<float> &ima)
246 {
247  int d;
248  Point3di dim( ima->getSizeX(), ima->getSizeY(), ima->getSizeZ() );
249 
250  for (unsigned int i = 0; i < _neumann_conditions.size(); ++i)
251  {
252  //copy first encountred unmasked value among neighbours
253  const Point3df &p = _neumann_conditions[i];
254  for (i = 0; i < 3; ++i)
255  for (d = -1; d <= 1; d += 2)
256  {
257  Point3di p2(p);
258  p2[i] += d;
259  if (p2[i] < 0 or p2[i] >= dim[i]) continue;
260  if (((this->_mask))(p2[0], p2[1], p2[2]) != 0)
261  {
262  ima(p[0], p[1], p[2]) =ima(p2[0], p2[1], p2[2]);
263  i = d = 3;
264  break;
265  }
266  }
267  }
268 }
269 
270 
271 template<typename T> carto::VolumeRef<T>
273 doSmoothing(const carto::VolumeRef<T> & ima, int maxiter, bool verbose)
274 {
275  this->check(maxiter);
276 
277  carto::VolumeRef<float> *tmp1, *tmp2, *swap;
278 
280  std::vector<int> dim = ima->getSize();
281  carto::VolumeRef< float > imaF( dim ), ima2( dim );
282  conv.convert(ima, imaF);
283  tmp1 = &imaF; tmp2 = &ima2;
284 
285  for (int i = 0; i < maxiter; i++)
286  {
287  if (verbose) std::cout << "+" << std::flush;
288  convolution((*tmp1), (*tmp2));
289  swap = tmp1;
290  tmp1 = tmp2;
291  tmp2 = swap;
292  }
293 
294  if (verbose) std::cout << "Finished" << std::endl;
296  conv2;
297  carto::VolumeRef<T> ima3( dim );
298  conv2.convert( (*tmp1), ima3);
299 
300  return ima3;
301 }
302 
303 template<typename T> void
305 convolution(const carto::VolumeRef<float> &ima1, carto::VolumeRef<float> &ima2) const
306 {
307  int i, d, x, y, z, t, n;
308  int dx = ima1->getSizeX();
309  int dy = ima1->getSizeY();
310  int dz = ima1->getSizeZ();
311  int dt = ima1->getSizeT();
312  Point3di dim( dx, dy, dz );
313 
314  for (t = 0; t < dt; t++)
315  for (z = 0; z < dz; z++)
316  for (y = 0; y < dy; y++)
317  for (x = 0; x < dx; x++)
318  {
319  std::cout << "x,y,z = " << x <<", " << y << ", " << z << std::endl;
320  std::cout << "mask = " << ((*this->_mask)(x, y, z, t)) << std::endl;
321  if ((*this->_mask)(x, y, z, t) == this->_background or
322  (*this->_mask)(x, y, z, t) == this->_neumann_value)
323  {
324  ima2(x, y, z, t) = ima1(x, y, z, t);
325  continue;
326  }
327  n = 0;
328  T val = (T) 0.;
329 
330  for (i = 0; i < 3; ++i)
331  for (d = -1; d <= 1; d += 2)
332  {
333  Point3di p2(x, y, z);
334  p2[i] += d;
335  if (p2[i] < 0 or p2[i] >= dim[i]) continue;
336  if ((*this->_mask)(p2[0], p2[1], p2[2], t)
337  == this->_neumann_value) continue;
338  n++;
339  val += ima1(p2[0], p2[1], p2[2], t);
340  }
341  val -= n * ima1(x, y, z, t);
342  ima2(x, y, z, t) = ima1(x, y, z, t) + this->_dt * val;
343  }
344 }
345 //FIXME : manque une version en connexité 26
346 
347 }
348 
349 #endif
The template class to make convolutions.
Definition: convol.h:53
carto::VolumeRef< T > doit(carto::rc_ptr< carto::Volume< T > > &, carto::rc_ptr< carto::Volume< T > > &)
Definition: convol.h:131
Make convolution only on a specified mask.
Definition: convol.h:104
static carto::VolumeRef< float > init_laplacian(void)
static carto::VolumeRef< float > laplacian
Heat diffusion with a volume of given datasource (Dirichlet conditions)
void setConstantSources(const carto::VolumeRef< T > &, const T &background)
virtual carto::VolumeRef< T > doSmoothing(const carto::VolumeRef< T > &ima, int maxiter, bool verbose=false)
virtual void convert(const INP &in, OUTP &out) const
int getSizeZ() const
std::vector< float > getVoxelSize() const
int getSizeT() const
std::vector< int > getSize() const
int getSizeY() const
int getSizeX() const
int verbose
void swap(scoped_ptr< T > &x, scoped_ptr< T > &y)