aimsalgo 6.0.0
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>
42#include <aims/utility/converter_volume.h>
43#include <stdlib.h>
44#include <math.h>
45#include <float.h>
46
47namespace aims {
48
49
50template<typename T>
53
54template<typename T>
56{
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
74template<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
85template<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
161template<typename T>
163 const carto::VolumeRef<T> & sources, const T & bgr )
164{
165 _constantSources = sources;
166 _constantSourcesBackground = bgr;
167 _hasConstantSources = true;
168}
169
170
171template <typename T>
173{
174 _hasConstantSources = false;
175 _constantSources = carto::VolumeRef<T>();
176}
177
178
179template<typename T> carto::VolumeRef<T>
181doSmoothing(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
233template<typename T> inline
235add_neumann_condition(const Point3df &p)
236{
237 _has_neumann_condition = true;
238 _neumann_conditions.push_back(p);
239}
240
241
242
243template<typename T>
245update_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
271template<typename T> carto::VolumeRef<T>
273doSmoothing(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
303template<typename T> void
305convolution(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
carto::VolumeRef< short > _mask
void setConstantSources(const carto::VolumeRef< T > &, const T &background)
virtual carto::VolumeRef< T > doSmoothing(const carto::VolumeRef< T > &ima, int maxiter, bool verbose=false)
void convolution(const carto::VolumeRef< float > &ima1, carto::VolumeRef< float > &ima2) const
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
carto::VolumeRef< float > BaseDiffusionSmoother< T >::laplacian
AimsVector< float, 3 > Point3df
AimsVector< int32_t, 3 > Point3di