aimsalgo  5.1.2
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 
51 namespace 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 
62  class DiscreteU
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 
112  DiscreteU::DiscreteU( const DiscreteU & other ):
113  _support( other._support ),
114  _values( other._values )
115  {}
116 
118  {}
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
143  const Point2di & DiscreteU::support() const
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 
231  {}
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 
271  SplinePyramidBuilder::SplinePyramidBuilder( unsigned factor, unsigned n ):
272  _order( n ),
273  _factor( 1, Point4du(factor, factor, factor, factor) ),
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 
306  {}
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>
560  SplinePyramid::SplinePyramid( const std::vector<carto::VolumeRef<T> > & pyramid,
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
virtual ~DiscreteU()
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...
Definition: splinefilter.h:62
The method follows that of Under, Aldroubi & Eden, "The L2 Polynomial Spline Pyramid" in IEEE Transac...
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.
Definition: splinepyramid.h:56
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
int verbose