aimsalgo 6.0.0
Neuroimaging image processing
splinepyramid_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#ifndef AIMS_INTERPOLATION_SPLINEPYRAMID_D_H
35#define AIMS_INTERPOLATION_SPLINEPYRAMID_D_H
36
37//--- aims -------------------------------------------------------------------
40#include <aims/signalfilter/splinefilter.h> // aims::DirectBSplineFilter/InverseBSplineFitler
42//--- cartobase --------------------------------------------------------------
43#include <cartobase/config/verbose.h> // carto::verbose
44//--- std --------------------------------------------------------------------
45#include <algorithm>
46#include <cmath>
47#include <limits>
48#include <iostream>
49//----------------------------------------------------------------------------
50
51namespace aims {
52
53 //==========================================================================
54 //
55 // MOVING AVERAGE KERNEL
56 //
57 //==========================================================================
58 // u_m^n in Unser et al paper.
59 // It can be used either to efficiently compute an expanded B-Spline kernel
60 // or to downsample coefficients in the dual space
61
63 {
64 public:
65 DiscreteU( unsigned m, unsigned n );
66 DiscreteU( const DiscreteU & other );
67 virtual ~DiscreteU();
68 DiscreteU & operator= ( const DiscreteU & other );
69
70 double operator() ( int x ) const;
71 double at( int x ) const;
72 const Point2di & support() const;
73
74 protected:
76 std::vector<double> _values;
77 };
78
79 DiscreteU::DiscreteU( unsigned m, unsigned n )
80 {
81 if( m == 1 )
82 {
83 _values.reserve(1);
84 _values.push_back(1.);
85 _support[0] = 0;
86 _support[1] = 0;
87 }
88
89 if( n == 1 && m == 2 )
90 {
91 _values.reserve(3);
92 _values.push_back(.5);
93 _values.push_back(1.);
94 _values.push_back(.5);
95 _support[0] = -1;
96 _support[1] = 1;
97 }
98
99 if( n == 3 && m == 2 )
100 {
101 _values.reserve(5);
102 _values.push_back(1./8);
103 _values.push_back(.5);
104 _values.push_back(3./4);
105 _values.push_back(.5);
106 _values.push_back(1./8);
107 _support[0] = -2;
108 _support[1] = 2;
109 }
110 }
111
113 _support( other._support ),
114 _values( other._values )
115 {}
116
119
121 {
122 if( this != &other )
123 {
124 _values = other._values;
125 _support = other._support;
126 }
127 return *this;
128 }
129
130 inline
131 double DiscreteU::operator() ( int x ) const
132 {
133 return _values[ x - _support[0] ];
134 }
135
136 inline
137 double DiscreteU::at( int x ) const
138 {
139 return _values[ x - _support[0] ];
140 }
141
142 inline
144 {
145 return _support;
146 }
147
148 //==========================================================================
149 //
150 // U(2,n) * B(2n+1)
151 //
152 //==========================================================================
153 // To save computation time, the first level dual is not saved and the
154 // second level dual is computed at once by a U*B subsampling
155
157 {
158 public:
159 DiscreteUB( unsigned m, unsigned n );
160 DiscreteUB( const DiscreteUB & other );
161 virtual ~DiscreteUB();
162 DiscreteUB & operator= ( const DiscreteUB & other );
163
164 double operator() ( int x ) const;
165 double at( int x ) const;
166 const Point2di & support() const;
167
168 protected:
170 std::vector<double> _values;
171 };
172
173 DiscreteUB::DiscreteUB( unsigned m, unsigned n )
174 {
175 if( m == 1 )
176 {
177 _values.reserve(7);
178 _values.push_back( 1. / 5040. );
179 _values.push_back( 120. / 5040. );
180 _values.push_back( 1191. / 5040. );
181 _values.push_back( 2416. / 5040. );
182 _values.push_back( 1191. / 5040. );
183 _values.push_back( 120. / 5040. );
184 _values.push_back( 1. / 5040. );
185 _support[0] = -3;
186 _support[1] = 3;
187 }
188
189 if( n == 1 && m == 2 )
190 {
191 _values.reserve(9);
192 _values.push_back( .5 / 5040. );
193 _values.push_back( 61. / 5040. );
194 _values.push_back( 716. / 5040. );
195 _values.push_back( 2459. / 5040. );
196 _values.push_back( 3607. / 5040. );
197 _values.push_back( 2459. / 5040. );
198 _values.push_back( 716. / 5040. );
199 _values.push_back( 61. / 5040. );
200 _values.push_back( .5 / 5040. );
201 _support[0] = -4;
202 _support[1] = 4;
203 }
204
205 if( n == 3 && m == 2 )
206 {
207 _values.reserve(11);
208 _values.push_back( 1. / 40320. );
209 _values.push_back( 124. / 40320. );
210 _values.push_back( 1677. / 40320. );
211 _values.push_back( 7904. / 40320. );
212 _values.push_back( 18482. / 40320. );
213 _values.push_back( 24264. / 40320. );
214 _values.push_back( 18482. / 40320. );
215 _values.push_back( 7904. / 40320. );
216 _values.push_back( 1677. / 40320. );
217 _values.push_back( 124. / 40320. );
218 _values.push_back( 1. / 40320. );
219 _support[0] = -5;
220 _support[1] = 5;
221
222 }
223 }
224
226 _support( other._support ),
227 _values( other._values )
228 {}
229
232
234 {
235 if( this != &other )
236 {
237 _values = other._values;
238 _support = other._support;
239 }
240 return *this;
241 }
242
243 inline
244 double DiscreteUB::operator() ( int x ) const
245 {
246 return _values[ x - _support[0] ];
247 }
248
249 inline
250 double DiscreteUB::at( int x ) const
251 {
252 return _values[ x - _support[0] ];
253 }
254
255 inline
257 {
258 return _support;
259 }
260
261 //==========================================================================
262 //
263 // SPLINE PYRAMID BUILDER
264 //
265 //==========================================================================
266
267 //--------------------------------------------------------------------------
269 //--------------------------------------------------------------------------
270
272 _order( n ),
274 _dir( 4, true ),
275 _verbose( carto::verbose )
276 {
277 _dir[3] = false;
278 }
279
281 _order( n ),
282 _factor( 1, factor ),
283 _dir( 4, true ),
284 _verbose( carto::verbose )
285 {
286 _dir[3] = false;
287 }
288
289 SplinePyramidBuilder::SplinePyramidBuilder( const std::vector<Point4du> & factor, unsigned n ):
290 _order( n ),
291 _factor( factor ),
292 _dir( 4, true ),
293 _verbose( carto::verbose )
294 {
295 _dir[3] = false;
296 }
297
299 _order( other._order ),
300 _factor( other._factor ),
301 _dir( other._dir ),
302 _verbose( other._verbose )
303 {}
304
307
309 {
310 if( this != &other )
311 {
312 _order = other._order;
313 _factor = other._factor;
314 _dir = other._dir;
315 _verbose = other._verbose;
316 }
317 return *this;
318 }
319
320
321 //--------------------------------------------------------------------------
323 //--------------------------------------------------------------------------
324
325 // helpers
326
327 std::vector<Point4du> SplinePyramidBuilder::computeFactors( const std::vector<int> & size ) const
328 {
329 std::vector<Point4du> factors;
330 if( _factor.size() > 1 )
331 {
332 factors = _factor;
333 }
334 else
335 {
336 unsigned nlevels = 0;
337 Point4dl level_size( size[0], size[1], size[2], size[3] );
338 bool ok = true;
339 while( ok )
340 {
341 ++nlevels;
342 for( int i = 0; i < 4; ++i )
343 {
344 if( _dir[i] ) {
345 level_size[i] /= _factor[0][i];
346 if( level_size[i] == 1 )
347 ok = false;
348 }
349 }
350 }
351 factors.assign( nlevels, _factor[0] );
352 }
353
354 Point4dl level_size( size[0], size[1], size[2], size[3] );
355 for( std::vector<Point4du>::iterator f = factors.begin();
356 f != factors.end(); ++f )
357 {
358 for( int i = 0; i < 4; ++i )
359 {
360 if( _dir[i] )
361 {
362 if( level_size[i] / (*f)[i] == 0 )
363 (*f)[i] = 1;
364 else
365 level_size[i] /= (*f)[i];
366 }
367 else
368 (*f)[i] = 1;
369 }
370 if( *f == Point4du(1, 1, 1, 1) )
371 {
372 factors.erase( f, factors.end() );
373 break;
374 }
375 }
376
377 return factors;
378 }
379
380 // doer
381
382 template <typename T>
384 {
385 std::vector<Point4du> factors = computeFactors( vol.getSize() );
386 std::vector<carto::VolumeRef<double> > pyramid;
387 pyramid.reserve( factors.size() + 1 );
388 std::vector<InterpolatedVolume> interpol( factors.size() + 1 );
389
390 // ROOT LEVEL
391 if( is_coeff )
392 {
393 if( _verbose > 1 )
394 std::cout << "Copy root level spline coefficients... " << std::endl;
395 pyramid.push_back( carto::copy<double, T>(vol) );
396 }
397 else
398 {
399 if( _verbose > 1 )
400 std::cout << "Compute root level spline coefficients from image... " << std::endl;
401 pyramid.push_back( carto::copy<double, T>(vol) );
402
403 if( _verbose > 0 )
404 std::cout << "BSpline inverse filter: " << std::flush;
405 InverseBSplineFilter invfilter( _order );
406 invfilter.setDirections( directions() );
407 invfilter.setVerbose( _verbose - 1 );
408 invfilter.execute( pyramid[0], true );
409 }
410 interpol[0].setCoeff( pyramid[0] );
411
412 // FIRST LEVEL
413 if( _verbose > 1 )
414 std::cout << "Compute dual coefficients for level 1... " << std::endl;
415
416 if( _verbose > 0 )
417 std::cout << "Moving average * Direct BSpline filter/subsampling: " << std::flush;
418 std::vector<DiscreteUB> bufunc;
419 bufunc.reserve(4);
420 bufunc.push_back( DiscreteUB( factors[0][0], _order ) );
421 bufunc.push_back( DiscreteUB( factors[0][1], _order ) );
422 bufunc.push_back( DiscreteUB( factors[0][2], _order ) );
423 bufunc.push_back( DiscreteUB( factors[0][3], _order ) );
424 ConvolutionSubSampler<DiscreteUB> busub( bufunc,factors[0] );
425 busub.setDirections( directions() );
426 busub.setVerbose( _verbose - 1 );
427 pyramid.push_back( busub.execute<double, double>( pyramid[0] ) );
428 pyramid[1] /= factors[0][0] * factors[0][1] * factors[0][2] * factors[0][3];
429
430 // OTHER LEVELS
431 std::vector<Point4du>::iterator f = ( factors.begin() == factors.end()
432 ? factors.end()
433 : ++(factors.begin()) );
434 int l = 2;
435 for( ; f != factors.end(); ++f, ++l )
436 {
437 if( _verbose > 0 )
438 std::cout << "Compute dual coefficients for level " << l << "... " << std::endl;
439
440 if( _verbose > 1 )
441 std::cout << "Moving average filter/subsampling: " << std::flush;
442 std::vector<DiscreteU> bfunc;
443 bfunc.reserve(4);
444 bfunc.push_back( DiscreteU( (*f)[0], _order ) );
445 bfunc.push_back( DiscreteU( (*f)[1], _order ) );
446 bfunc.push_back( DiscreteU( (*f)[2], _order ) );
447 bfunc.push_back( DiscreteU( (*f)[3], _order ) );
448 ConvolutionSubSampler<DiscreteU> sub( bfunc, *f );
449 sub.setDirections( directions()[0] && (*f)[0] > 1,
450 directions()[1] && (*f)[1] > 1,
451 directions()[2] && (*f)[2] > 1,
452 directions()[3] && (*f)[3] > 1 );
453 sub.setVerbose( _verbose - 1 );
454 pyramid.push_back( sub.execute<double, double>( pyramid[l-1] ) );
455 pyramid[l] /= (*f)[0] * (*f)[1] * (*f)[2] * (*f)[3];
456 interpol[l].setCoeff( pyramid[l] );
457
458 if( _verbose > 0 )
459 std::cout << "Compute spline coefficients for level " << l-1 << "... " << std::endl;
460 if( _verbose > 1 )
461 std::cout << "BSpline inverse filter: " << std::flush;
462 InverseBSplineFilter invfilter( 2 * _order + 1 );
463 invfilter.setDirections( directions() );
464 invfilter.setVerbose( _verbose - 1 );
465 invfilter.execute( pyramid[l-1], true );
466 if( _verbose > 1 )
467 std::cout << std::endl;
468 interpol[l-1].setCoeff( pyramid[l-1] );
469 }
470
471 // LAST LEVEL
472 if( _verbose > 0 )
473 std::cout << "Compute spline coefficients for level " << l-1 << "... " << std::endl;
474 if( _verbose > 1 )
475 std::cout << "BSpline inverse filter: " << std::flush;
476 InverseBSplineFilter invfilter( 2 * _order + 1 );
477 invfilter.setDirections( directions() );
478 invfilter.setVerbose( _verbose - 1 );
479 invfilter.execute( pyramid[l-1], true );
480 if( _verbose > 1 )
481 std::cout << std::endl;
482 interpol[l-1].setCoeff( pyramid[l-1] );
483
484 return SplinePyramid( interpol );
485 }
486
487
488 //--------------------------------------------------------------------------
490 //--------------------------------------------------------------------------
491
493 {
494 return _order;
495 }
496
497 const std::vector<bool> & SplinePyramidBuilder::directions() const
498 {
499 return _dir;
500 }
501
502 const std::vector<Point4du> & SplinePyramidBuilder::factor() const
503 {
504 return _factor;
505 }
506
508 {
509 _order = n;
510 }
511
513 {
514 _factor.assign( 1, Point4du( r, r, r, r ) );
515 }
516
518 {
519 _factor.assign( 1, r );
520 }
521
522 void SplinePyramidBuilder::setFactor( const std::vector<Point4du> & r )
523 {
524 _factor = r;
525 }
526
527 void SplinePyramidBuilder::setDirections( const std::vector<bool> & dir )
528 {
529 _dir.assign( 4, true );
530 _dir[3] = false;
531 for( std::vector<bool>::size_type i = 0; i < dir.size() && i < _dir.size(); ++i )
532 _dir[i] = dir[i];
533 }
534
535 void SplinePyramidBuilder::setDirections( bool dirx, bool diry, bool dirz, bool dirt )
536 {
537 _dir[0] = dirx;
538 _dir[1] = diry;
539 _dir[2] = dirz;
540 _dir[3] = dirt;
541 }
542
544 {
545 _verbose = verbose;
546 }
547
549 {
550 _verbose = 0;
551 }
552
553//============================================================================
554//
555// SPLINE PYRAMID
556//
557//============================================================================
558
559 template <typename T>
561 unsigned order,
562 bool is_coeff ):
563 _pyramid()
564 {
565 if( is_coeff )
566 _pyramid.assign( pyramid.size(), InterpolatedVolume() );
567 else
568 _pyramid.reserve( pyramid.size() );
569
570 for( size_t i = 0; i < pyramid.size(); ++i )
571 {
572 if( is_coeff )
573 _pyramid[i].setCoeff( pyramid[i] );
574 else
575 _pyramid.push_back( InterpolatedVolume( pyramid[i], order ) );
576 }
577 }
578
579} // namespace aims
580
581#endif // AIMS_INTERPOLATION_SPLINEPYRAMID_D_H
carto::VolumeRef< OUT > execute(const carto::VolumeRef< IN > &in) const
Execution.
void setDirections(const std::vector< bool > &dir)
double operator()(int x) const
double at(int x) const
std::vector< double > _values
DiscreteUB(unsigned m, unsigned n)
DiscreteUB & operator=(const DiscreteUB &other)
const Point2di & support() const
DiscreteU & operator=(const DiscreteU &other)
std::vector< double > _values
DiscreteU(unsigned m, unsigned n)
double operator()(int x) const
const Point2di & support() const
double at(int x) const
virtual void setDirections(const std::vector< bool > &dir)
carto::VolumeRef< double > execute(const carto::VolumeRef< T > &in) const
Execution.
virtual void setVerbose(int verbose=1)
Verbosity level.
Spline interpolation of volumes with simple accessors to interpolated values.
This filter uses an inverse B-Spline convolution function to transform a discrete signal to its splin...
void setDirections(const std::vector< bool > &dir)
SplinePyramidBuilder(unsigned factor=2, unsigned spline_order=3)
Constructors / Destructors / Copy.
unsigned order() const
Parameters.
const std::vector< bool > & directions() const
std::vector< bool > _dir
void setVerbose(int verbose=1)
SplinePyramid execute(const carto::VolumeRef< T > &vol, bool is_coeff=false) const
Execution.
std::vector< Point4du > computeFactors(const std::vector< int > &size) const
Execution.
std::vector< Point4du > _factor
const std::vector< Point4du > & factor() const
SplinePyramidBuilder & operator=(const SplinePyramidBuilder &other)
Pyramid of Interpolated Volumes.
const std::vector< InterpolatedVolume > & pyramid() const
Change pyramid.
SplinePyramid(const std::vector< InterpolatedVolume > &pyramid=std::vector< InterpolatedVolume >())
Constructors / Destructors / Copy.
std::vector< InterpolatedVolume > _pyramid
std::vector< int > getSize() const
AimsVector< int64_t, 4 > Point4dl
AimsVector< int32_t, 2 > Point2di
AimsVector< uint32_t, 4 > Point4du