aimsalgo 6.0.0
Neuroimaging image processing
sampler.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_RESAMPLING_SAMPLER_H
36#define AIMS_RESAMPLING_SAMPLER_H
37
38#include <aims/def/assert.h>
39#include <cartodata/volume/volume.h>
40#include <aims/vector/vector.h>
41#include <aims/resampling/motion.h>
42#include <aims/bucket/bucketMap.h>
43#include <vector>
44
45typedef struct {
46 unsigned short x, y, z;
47 int offset;
48} PVItem;
49
50
51namespace carto
52{
53 extern template class Volume<PVItem>;
54}
55
56template <class T>
58{
59 public:
60
61 Sampler( ) : _ref( 0 ) { };
62 virtual ~Sampler() { }
63
64 virtual void doit(
65 const Motion& motion,
66 carto::rc_ptr<carto::Volume<PVItem> >& thing ) const;
67
68
69 void setRef( const carto::rc_ptr<carto::Volume<T> >& ref ) { _ref = &ref; }
70
71 protected:
72
73 void _sliceResamp( carto::rc_ptr<carto::Volume<PVItem> >& resamp,
74 PVItem* out,
75 const Point3df& start, int t,
76 const carto::rc_ptr<carto::Volume<float> >& Rinv ) const;
78};
79
80
81typedef struct {
82 unsigned short x, y, z ;
83 int offset ;
85
86template <class T>
88{
89 public:
90
91 BucketSampler( ) : _ref(0) { }
92 virtual ~BucketSampler() { }
93
94 virtual void doit( const Motion& motion,
95 std::vector< PVVectorItem >& thing,
96 const aims::BucketMap<T>& model ) const;
97
98 void setRef( const carto::rc_ptr<carto::Volume<T> >& ref ) { _ref = &ref; }
99
100 protected:
102};
103
104
105
106
107template <class T> inline
108void
110{
111
112 ASSERT( _ref );
113 ASSERT( thing->getSizeT() == (*_ref)->getSizeT() && thing->getBorders()[0] == 0 );
114
115 Motion dirMotion = motion;
116 std::unique_ptr<Motion> invMotion = motion.inverse();
117
118 // scale motion
119 Point3df sizeFrom( (*_ref)->getVoxelSize() );
120 Point3df sizeTo( thing->getVoxelSize() );
121 dirMotion.scale( sizeFrom, sizeTo );
122 invMotion->scale( sizeTo, sizeFrom );
123
124 PVItem *it;
125
126#ifdef DEBUG
127 std::cout << "Sampling volume [ 0] / slice [ 0]" << std::flush;
128#endif
129 for (int t = 0; t < thing->getSizeT(); t++ )
130 {
131 Point3df start = invMotion->translation();
132 for ( int s = 0; s < thing->getSizeZ(); s++ )
133 {
134#ifdef DEBUG
135 std::cout << "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
136 << std::setw( 3 ) << t << "] / slice ["
137 << std::setw( 3 ) << s << "]" << std::flush;
138#endif
139 it = &thing->at( 0, 0, s, t );
140 _sliceResamp( thing, it, start, t, invMotion->rotation() );
141 start[ 0 ] += invMotion->rotation()( 0, 2 );
142 start[ 1 ] += invMotion->rotation()( 1, 2 );
143 start[ 2 ] += invMotion->rotation()( 2, 2 );
144 }
145 }
146#ifdef DEBUG
147 std::cout << std::endl;
148#endif
149}
150
151// This method processes resampling information (offset and neighbor voxel contributions)
152// for each pixel of a 2D slice. In order to use only integers, floating point values
153// are scaled by 2^16.
154// Each voxel in target space is scanned to calculate the offset from source space
155// Non integer part of voxel contributions are stored in x, y and z. The 16 bits corresponding
156// to floating point contributions are retrived using the bitwise operation: & 0xffff.
157template <class T> inline
159 PVItem* out,
160 const Point3df& start, int t,
161 const carto::rc_ptr<carto::Volume<float> >& Rinv )
162 const
163{
164 // Dimensions of source space
165 int dimX1 = (*_ref)->getSizeX();
166
167 // Dimensions of target space
168 int dimX2 = resamp->getSizeX();
169 int dimY2 = resamp->getSizeY();
170
171 const int SIXTEEN = 16;
172 const int TWO_THEN_SIXTEEN = 65536;
173
174 // Source space, maximum coordinates shifted using size of short type (2^16).
175 // This is used for direct pointer comparisons.
176 int maxX = TWO_THEN_SIXTEEN * ( dimX1 - 1 );
177 int maxY = TWO_THEN_SIXTEEN * ( (*_ref)->getSizeY() - 1 );
178 int maxZ = TWO_THEN_SIXTEEN * ( (*_ref)->getSizeZ() - 1 );
179
180 // The start variable contains the coordinates offset in the source space
181 // for the origin (0, 0) in the target space.
182 // Source space, start coordinate scaled using size of short type (2^16).
183 // This is used to initialize each line pointer coordinate.
184 int xLinCurrent = ( int )( 65536.0 * start[ 0 ] );
185 int yLinCurrent = ( int )( 65536.0 * start[ 1 ] );
186 int zLinCurrent = ( int )( 65536.0 * start[ 2 ] );
187
188 // Source space, increments used for rotations.
189 // Values are shifted using size of short type (2^16)
190 // to deal with floating point part as integer.
191 int xu = ( int )( 65536.0 * Rinv->at( 0, 0 ) );
192 int yu = ( int )( 65536.0 * Rinv->at( 1, 0 ) );
193 int zu = ( int )( 65536.0 * Rinv->at( 2, 0 ) );
194 int xv = ( int )( 65536.0 * Rinv->at( 0, 1 ) );
195 int yv = ( int )( 65536.0 * Rinv->at( 1, 1 ) );
196 int zv = ( int )( 65536.0 * Rinv->at( 2, 1 ) );
197
198 // std::cout << "- xu: " << carto::toString(xu) << std::endl
199 // << "- yu: " << carto::toString(yu) << std::endl
200 // << "- zu: " << carto::toString(zu) << std::endl
201 // << "- xv: " << carto::toString(xv) << std::endl
202 // << "- yv: " << carto::toString(yv) << std::endl
203 // << "- zv: " << carto::toString(zv) << std::endl
204 // << std::flush;
205
206 int xCurrent, yCurrent, zCurrent;
207 const T *it;
208 int incr_vois[8] = { 0,
209 int( &(*_ref)->at( 1 ) - &(*_ref)->at( 0 ) ),
210 int( &(*_ref)->at( 1, 1 ) - &(*_ref)->at( 0 ) ),
211 int( &(*_ref)->at( 0, 1 ) - &(*_ref)->at( 0 ) ),
212 int( &(*_ref)->at( 0, 0, 1 ) - &(*_ref)->at( 0 ) ),
213 int( &(*_ref)->at( 1, 0, 1 ) - &(*_ref)->at( 0 ) ),
214 int( &(*_ref)->at( 1, 1, 1 ) - &(*_ref)->at( 0 ) ),
215 int( &(*_ref)->at( 0, 1, 1 ) - &(*_ref)->at( 0 ) ) };
216
217 // Loop around voxels in the target space to process
218 // pointer offset and neighbor voxel contributions (x, y, z)
219 // in the source space.
220 for (int v = dimY2; v--;) {
221 xCurrent = xLinCurrent;
222 yCurrent = yLinCurrent;
223 zCurrent = zLinCurrent;
224
225 for (int u = dimX2; u--;) {
226 // [NS-2025-04-11]: following test was changed to support
227 // 2D images. This can lead to changes in results.
228 if (xCurrent >= 0 && (xCurrent <= maxX) &&
229 yCurrent >= 0 && (yCurrent <= maxY) &&
230 zCurrent >= 0 && (zCurrent <= maxZ)) {
231 // Pointer to the value in source space
232 it = &(*_ref)->at(xCurrent >> SIXTEEN,
233 yCurrent >> SIXTEEN,
234 zCurrent >> SIXTEEN,
235 t);
236
237 if (*(it + incr_vois[0]) == -32768 ||
238 ((xCurrent < maxX) && *(it + incr_vois[1]) == -32768) ||
239 ((xCurrent < maxX) && (yCurrent < maxY) && *(it + incr_vois[2]) == -32768) ||
240 ((yCurrent < maxY) && *(it + incr_vois[3]) == -32768) ||
241 ((zCurrent < maxZ) && *(it + incr_vois[4]) == -32768) ||
242 ((xCurrent < maxX) && (zCurrent < maxZ) && *(it + incr_vois[5]) == -32768) ||
243 ((xCurrent < maxX) && (yCurrent < maxY) && (zCurrent < maxZ) && *(it + incr_vois[6]) == -32768) ||
244 ((yCurrent < maxY) && (zCurrent < maxZ) && *(it + incr_vois[7]) == -32768)) {
245
246 out->offset = -1;
247 }
248 else {
249 // The floating point part, (i.e. the 16 bits given using the bitwise operation: & 0xffff),
250 // is later used to process contribution of neighbors in interpolation.
251 // These contributions are stored in x, y and z
252 out->x = xCurrent & 0xffff;
253 out->y = yCurrent & 0xffff;
254 out->z = zCurrent & 0xffff;
255
256 out->offset = &(*_ref)->at( xCurrent >> SIXTEEN,
257 yCurrent >> SIXTEEN,
258 zCurrent >> SIXTEEN ) - &(*_ref)->at( 0 );
259 }
260 }
261 else {
262 out->offset = -1;
263 }
264 out++;
265 xCurrent += xu;
266 yCurrent += yu;
267 zCurrent += zu;
268 }
269 xLinCurrent += xv;
270 yLinCurrent += yv;
271 zLinCurrent += zv;
272 }
273}
274
275template <class T> inline
276void
278 std::vector< PVVectorItem >& thing,
279 const aims::BucketMap<T>& model ) const
280{
281 const int TWO_THEN_SIXTEEN = 65536;
282
283
284 thing.clear() ;
285
286 ASSERT( _ref );
287
288 Motion dirMotion = motion;
289 std::unique_ptr<Motion> invMotion = motion.inverse();
290
291
292 // scale motion
293 Point3df sizeFrom( (*_ref)->getVoxelSize() );
294 Point3df sizeTo( model.sizeX(), model.sizeY(), model.sizeZ() );
295
296 dirMotion.scale( sizeFrom, sizeTo );
297 invMotion->scale( sizeTo, sizeFrom );
298
299 typename aims::BucketMap<T>::Bucket::const_iterator
300 it = model.begin()->second.begin() ;
301
302 PVVectorItem item ;
303 int nbOfVoxels = model.begin()->second.size() ;
304
305 thing.reserve(nbOfVoxels) ;
306 thing.resize(nbOfVoxels) ;
307
308 Point3df x, y, z;
309
310 float transl0 = invMotion->translation()[0];
311 float transl1 = invMotion->translation()[1];
312 float transl2 = invMotion->translation()[2];
313
314 invMotion->setTranslation( 0. );
315
316 x = invMotion->transform( 1.F, 0.F, 0.F ) ;
317 y = invMotion->transform( 0.F, 1.F, 0.F ) ;
318 z = invMotion->transform( 0.F, 0.F, 1.F ) ;
319
320 int maxX = (*_ref)->getSizeX() - 1;
321 int maxY = (*_ref)->getSizeY() - 1;
322 int maxZ = (*_ref)->getSizeZ() - 1;
323 int oS= &(*_ref)->at( 0, 0, 1 ) - &(*_ref)->at( 0 ),
324 dX = &(*_ref)->at( (*_ref)->getSizeX() ) - &(*_ref)->at( 0 );
325
326 for(int i = 0 ; i < nbOfVoxels ; ++i , ++it )
327 {
328 float current0, current1, current2;
329 current0 = static_cast<float>( (it->first)[0] ) ;
330 current1 = static_cast<float>( (it->first)[1] ) ;
331 current2 = static_cast<float>( (it->first)[2] ) ;
332
333 float tmp0 = current0 * x[0] + current1 * y[0] + current2 * z[0] + transl0 ;
334 float tmp1 = current0 * x[1] + current1 * y[1] + current2 * z[1] + transl1 ;
335 float tmp2 = current0 * x[2] + current1 * y[2] + current2 * z[2] + transl2 ;
336
337
338 if ( tmp0 >= 0 && tmp0 < maxX &&
339 tmp1 >= 0 && tmp1 < maxY &&
340 tmp2 >= 0 && tmp2 < maxZ)
341 {
342 item.x = (unsigned short) (( tmp0 - int(tmp0) ) * TWO_THEN_SIXTEEN);
343 item.y = (unsigned short) (( tmp1 - int(tmp1) ) * TWO_THEN_SIXTEEN);
344 item.z = (unsigned short) (( tmp2 - int(tmp2) ) * TWO_THEN_SIXTEEN);
345 item.offset = int(tmp2) * oS +
346 int(tmp1) * dX +
347 int(tmp0);
348 }
349 else
350 {
351 item.offset = -1;
352 }
353
354 thing[i] = item ;
355 }
356}
357
358inline
362{
363 short *inptr;
364 float tmp;
365 long x, y, z;
366
367 long inx = out->getSizeX(),
368 iny = out->getSizeY(),
369 inz = out->getSizeZ();
370
371 const int TWO_THEN_SIXTEEN = 65536;
372 const float TWO_THEN_SIXTEEN_CUBE = 65536.0 * 65536.0 * 65536.0;
373
374 carto::const_NDIterator<PVItem> it(&comb->at(0),
375 comb->getSize(),
376 comb->getStrides());
377 carto::NDIterator<short> it1(&out->at(0),
378 out->getSize(),
379 out->getStrides());
380 std::vector<long> instr = in->getStrides();
381
382 for( ; !it.ended(); ++it, ++it1 )
383 if ( it->offset != -1L) {
384 z = it->offset / instr[2];
385 y = (it->offset % instr[2]) / instr[1];
386 x = (it->offset % instr[1]) / instr[0];
387
388 inptr = &in->at(0) + it->offset;
389 tmp = (*inptr) *
390 (float)(TWO_THEN_SIXTEEN - it->x) *
391 (float)(TWO_THEN_SIXTEEN - it->y) *
392 (float)(TWO_THEN_SIXTEEN - it->z);
393
394 if ((x+1) < inx) {
395 inptr += instr[0];
396 tmp += (*inptr) *
397 (float)(it->x) *
398 (float)(TWO_THEN_SIXTEEN - it->y) *
399 (float)(TWO_THEN_SIXTEEN - it->z);
400 }
401
402 if ((x+1) < inx
403 && (y+1) < iny) {
404 inptr += instr[1];
405 tmp += (*inptr) *
406 (float)(it->x) *
407 (float)(it->y) *
408 (float)(TWO_THEN_SIXTEEN - it->z);
409 }
410
411 if ((y+1) < iny) {
412 inptr -= instr[0];
413 tmp += (*inptr) *
414 (float)(TWO_THEN_SIXTEEN - it->x) *
415 (float)(it->y) *
416 (float)(TWO_THEN_SIXTEEN - it->z);
417 }
418
419 if ((z+1) < inz) {
420 inptr += instr[2] - instr[1];
421 tmp += (float)(TWO_THEN_SIXTEEN - it->x) *
422 (float)(TWO_THEN_SIXTEEN - it->y)*
423 (float)(it->z);
424 }
425
426 if ((x+1) < inx
427 && (z+1) < inz) {
428 inptr += instr[0];
429 tmp += (*inptr) *
430 (float)(it->x) *
431 (float)(TWO_THEN_SIXTEEN - it->y) *
432 (float)(it->z);
433 }
434
435 if ((x+1) < inx
436 && (y+1) < iny
437 && (z+1) < inz) {
438 inptr += instr[1];
439 tmp += (*inptr) *
440 (float)(it->x)*
441 (float)(it->y)*
442 (float)(it->z);
443 }
444
445 if ((y+1) < iny
446 && (z+1) < inz) {
447 inptr -= instr[0];
448 tmp += (*inptr) *
449 (float)(TWO_THEN_SIXTEEN - it->x) *
450 (float)(it->y)*
451 (float)(it->z);
452 }
453
454 *it1 = (short)(tmp / TWO_THEN_SIXTEEN_CUBE);
455 }
456}
457
458#endif
#define ASSERT(EX)
virtual ~BucketSampler()
Definition sampler.h:92
void setRef(const carto::rc_ptr< carto::Volume< T > > &ref)
Definition sampler.h:98
virtual void doit(const Motion &motion, std::vector< PVVectorItem > &thing, const aims::BucketMap< T > &model) const
Definition sampler.h:277
const carto::rc_ptr< carto::Volume< T > > * _ref
Definition sampler.h:101
Sampler()
Definition sampler.h:61
const carto::rc_ptr< carto::Volume< T > > * _ref
Definition sampler.h:77
virtual void doit(const Motion &motion, carto::rc_ptr< carto::Volume< PVItem > > &thing) const
Definition sampler.h:109
virtual ~Sampler()
Definition sampler.h:62
void _sliceResamp(carto::rc_ptr< carto::Volume< PVItem > > &resamp, PVItem *out, const Point3df &start, int t, const carto::rc_ptr< carto::Volume< float > > &Rinv) const
Definition sampler.h:158
void setRef(const carto::rc_ptr< carto::Volume< T > > &ref)
Definition sampler.h:69
std::unique_ptr< AffineTransformation3d > inverse() const
float sizeZ() const
float sizeY() const
float sizeX() const
std::ptrdiff_t offset() const
virtual void scale(const Point3df &sizeFrom, const Point3df &sizeTo)
void AimsSamplePV(const carto::rc_ptr< carto::Volume< short > > &in, carto::rc_ptr< carto::Volume< short > > &out, const carto::rc_ptr< carto::Volume< PVItem > > &comb)
Definition sampler.h:359
aims::AffineTransformation3d Motion
unsigned short x
Definition sampler.h:46
int offset
Definition sampler.h:47
unsigned short z
Definition sampler.h:46
unsigned short y
Definition sampler.h:46
unsigned short x
Definition sampler.h:82
unsigned short z
Definition sampler.h:82
unsigned short y
Definition sampler.h:82
AimsVector< float, 3 > Point3df