aimstil  5.0.5
dwt.tpp
Go to the documentation of this file.
1 
2 namespace til
3 {
4 
5  //---------------------------------------------------------------------------
6 
7  /// namespace for boundary conditions
8  // TODO: could actually be in a separate file... included from here.
9  namespace bc
10  {
11  struct ThinMirror
12  {
13  std::size_t operator()(int i, std::size_t n)
14  {
15  assert(i >= -1);
16  if (i>=0) { assert(std::size_t(i) <= n); }
17  if (i == -1) return 3;
18  else if (i == int(n)) return n-4;
19  //else if (i == int(n)) return ( n%2 ? n-2 : n-4 );
20  else return i;
21  }
22  };
23 
24  struct Cyclic
25  {
26  std::size_t operator()(int i, std::size_t n)
27  {
28  assert(i >= -1);
29  if (i>=0) { assert(std::size_t(i) <= n); }
30  if (i == -1) return (n-1);
31  else if (i == int(n)) return 0;
32  else return i;
33  }
34  };
35  }
36 
37 
38 
39  //---------------------------------------------------------------------------
40 
41  //----------------------------------------------//
42  // Various anonymous helper functions for DWT //
43  //----------------------------------------------//
44 
45  namespace
46  {
47  /// Computes the number of elements reached when hopping in an array of size length with a step of size s.
48  struct SteppedSize : public std::binary_function<std::size_t, std::size_t, std::size_t>
49  {
50  std::size_t operator()(std::size_t length, std::size_t step)
51  { return 1 + (length-1) / step; }
52  };
53 
54  /// Initial step size -- it should be the largest power of two x so that 1+(4-1)*x is smaller than n.
55  struct StepInit : public std::unary_function<std::size_t, std::size_t>
56  {
57  std::size_t operator()(std::size_t n)
58  {
59  // This loop may actually be more efficient than a closed form formula for reasonable n.
60  std::size_t res;
61  for (res = 1; 1+(4-1)*res <= n; res *= 2);
62  return res/2;
63  }
64  };
65 
66  inline std::size_t index_offset(
67  std::size_t x, std::size_t y, std::size_t z,
68  std::size_t dimx, std::size_t dimy)
69  {
70  return x + dimx * ( y + dimy * z);
71  }
72 
73  inline std::size_t index_offset(
74  std::size_t x, std::size_t y,
75  std::size_t dimx)
76  {
77  return x + dimx * y;
78  }
79 
80 
81  /*
82  inline std::size_t wrap(int i, std::size_t n)
83  {
84  assert(i >= -1);
85  if (i>=0) { assert(std::size_t(i) <= n); }
86  if (i == -1) return 3;
87  else if (i == int(n)) return n-4;
88  //else if (i == int(n)) return ( n%2 ? n-2 : n-4 );
89  else return i;
90  }
91  */
92  }
93 
94  //---------------------------------------------------------------------------
95 
96  template < typename T, typename BC >
97  void DWTCubic<T, BC>::Direct::
98  operator()(T * s, std::size_t n, std::size_t step)
99  {
100  for (std::size_t i = 0; i < n; i+=2) s[i*step] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(1.0/4.0);
101  for (std::size_t i = 1; i < n; i+=2) s[i*step] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] );
102  for (std::size_t i = 0; i < n; i+=2) s[i*step] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(3.0/16.0);
103 
104  // This is the "constant L1 norm" normalization
105  //for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(4);
106 
107  // This is the usual normalization
108  for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(2);
109  for (std::size_t i = 1; i < n; i+=2) s[i*step] *= T(1.0/2.0);
110  }
111  //---------------------------------------------------------------------------
112 
113  template < typename T, typename BC >
114  void DWTCubic<T,BC>::Inverse::
115  operator()(T * s, std::size_t n, std::size_t step)
116  {
117  // This is the "constant L1 norm" normalization
118  //for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(1.0/4.0);
119 
120  std::size_t step2 = 2 * step;
121  std::size_t ns = n * step;
122  // This is the usual normalization
123  for (std::size_t i = 0; i < ns; i += step2) s[i] *= T(1.0/2.0);
124  for (std::size_t i = step; i < ns; i += step2) s[i] *= T(2);
125 
126  for (std::size_t i = 0, j = 0; i < n; i+=2, j += step2) s[j] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(3.0/16.0);
127  for (std::size_t i = 1, j = step; i < n; i+=2, j += step2) s[j] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] );
128  for (std::size_t i = 0, j = 0; i < n; i+=2, j += step2) s[j] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(1.0/4.0);
129  }
130 
131  //---------------------------------------------------------------------------
132 
133  template < typename T, typename BC >
134  void DWTCubicConjugate< T, BC >::Direct::
135  operator()(T * s, std::size_t n, std::size_t step)
136  {
137  for (std::size_t i = 1; i < n; i+=2) s[i*step] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(1.0/4.0);
138  for (std::size_t i = 0; i < n; i+=2) s[i*step] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] );
139  for (std::size_t i = 1; i < n; i+=2) s[i*step] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(3.0/16.0);
140 
141  //for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(1.0/(4.0));
142 
143  //for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(std::sqrt(2.0)/4);
144  //for (std::size_t i = 1; i < n; i+=2) s[i*step] *= T(std::sqrt(2.0));
145 
146  for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(1.0/2.0);
147  for (std::size_t i = 1; i < n; i+=2) s[i*step] *= T(2);
148  }
149 
150  //---------------------------------------------------------------------------
151 
152  template < typename T, typename BC >
153  void DWTCubicConjugate< T, BC >::Inverse::
154  operator()(T * s, std::size_t n, std::size_t step)
155  {
156  for (std::size_t i = 0; i < n; i+=2) s[i*step] *= T(2);
157  for (std::size_t i = 1; i < n; i+=2) s[i*step] *= T(1.0/2.0);
158  for (std::size_t i = 1; i < n; i+=2) s[i*step] += ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(3.0/16.0);
159  for (std::size_t i = 0; i < n; i+=2) s[i*step] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] );
160  for (std::size_t i = 1; i < n; i+=2) s[i*step] -= ( s[BC()(i+1,n)*step] + s[BC()(i-1,n)*step] ) * T(1.0/4.0);
161  }
162 
163  //---------------------------------------------------------------------------
164 
165  template < typename DWT >
166  void DWTND<DWT, 2>::operator()
167  (
168  typename DWT::prec_type * im
169  , numeric_array<std::size_t,2> dim
170  , int dir
171  , numeric_array<std::size_t,2> step
172  , numeric_array<std::size_t,2> real_dim
173  )
174  {
175  assert(dir >= 0);
176  assert(dir < 2);
177  if (dir == 0)
178  {
179  for (std::size_t j = 0; j < dim[1]; ++j)
180  {
181  m_dwt(im+j*step[1]*real_dim[0], dim[0], step[0]);
182  }
183  }
184  else if (dir == 1)
185  {
186  for (std::size_t i = 0; i < dim[0]; ++i)
187  {
188  m_dwt(im+i*step[0], dim[1], real_dim[0]*step[1]);
189  }
190  }
191  }
192 
193  //---------------------------------------------------------------------------
194 
195  template < typename DWT >
196  void DWTND<DWT,3>::operator()(prec_type * im, numeric_array<std::size_t,3> dim, int dir, numeric_array<std::size_t,3> step, numeric_array<std::size_t,3> real_dim)
197  {
198  assert(dir >= 0);
199  assert(dir < 3);
200  if (dir == 0)
201  {
202  for (std::size_t k = 0; k < dim[2]; ++k)
203  for (std::size_t j = 0; j < dim[1]; ++j)
204  {
205  m_dwt(im+index_offset(0, j*step[1], k*step[2], real_dim[0], real_dim[1]), dim[0], step[0]);
206  }
207  }
208  else if (dir == 1)
209  {
210  for (std::size_t k = 0; k < dim[2]; ++k)
211  for (std::size_t i = 0; i < dim[0]; ++i)
212  {
213  m_dwt(im+index_offset(i*step[0], 0, k*step[2], real_dim[0], real_dim[1]), dim[1], real_dim[0]*step[1]);
214  }
215  }
216  else if (dir == 2)
217  {
218  for (std::size_t j = 0; j < dim[1]; ++j)
219  for (std::size_t i = 0; i < dim[0]; ++i)
220  {
221  m_dwt(im+index_offset(i*step[0], j*step[1], 0, real_dim[0], real_dim[1]), dim[2], real_dim[0]*real_dim[1]*step[2]);
222  }
223  }
224  }
225 
226  //---------------------------------------------------------------------------
227 
228  template < typename DWT >
229  void MultiDWT::Direct<DWT>::operator()
230  (
231  prec_type * s, ///< Input array. This also contains the output, the computation being in-place.
232  std::size_t n ///< Length of the input.
233  )
234  {
235  std::size_t sm = 1;
236  while (n >= 4)
237  {
238  m_dwt(s, n, sm);
239  n = SteppedSize()(n, 2);
240  sm *= 2;
241  }
242  }
243 
244  //---------------------------------------------------------------------------
245 
246  template < typename IDWT >
247  void MultiDWT::Inverse<IDWT>::operator()
248  (
249  prec_type * s, ///< The input array. Also contains the output, since the computation is in-place.
250  std::size_t n ///< The input length.
251  )
252  {
253  for (std::size_t sm = StepInit()(n); sm > 0; sm /= 2)
254  {
255  m_idwt(s, SteppedSize()(n, sm), sm);
256  }
257  }
258 
259  //---------------------------------------------------------------------------
260 
261  template < typename DWT, std::size_t D >
262  void MultiDWTND::Direct<DWT,D>::operator()
263  (
264  prec_type * im
265  , const numeric_array<std::size_t,D> dim
266  )
267  {
268  numeric_array<std::size_t,D> sm;
269  std::fill(sm.begin(), sm.end(), 1);
270  numeric_array<std::size_t,D> sm_bis = sm;
271  numeric_array<std::size_t,D> ssize = dim;
272  numeric_array<std::size_t,D> ssize_bis = dim;
273 
274  numeric_array<bool,D> f;
275  for (std::size_t i = 0; i < D; ++i) f[i] = (dim[i] >= 4);
276 
277  while (or_all(f.begin(), f.end()))
278  {
279  // loop in all dimensions, starting from the lowest.
280  for (std::size_t i = 0; i < D; ++i)
281  {
282  if (f[i])
283  {
284  //std::cout << "dir " << i << " step " << sm[0] << " " << sm[1] << " " << sm[2] << " dim " << ssize[0] << " " << ssize[1] << " " << ssize[2] << std::endl;
285  m_dwt(im, ssize, i, sm, dim);
286  if (ssize_bis[i] >= (4-1)*2+1)
287  {
288  //ssize_bis[i] = 1 + (ssize_bis[i]-1) / 2;
289  ssize_bis[i] = SteppedSize()(ssize_bis[i], 2);
290  sm_bis[i] *= 2;
291  }
292  else f[i] = false;
293  }
294  }
295  sm = sm_bis;
296  ssize = ssize_bis;
297  }
298  }
299 
300  //---------------------------------------------------------------------------
301 
302  template < typename IDWT, std::size_t D >
303  void
304  MultiDWTND::Inverse< IDWT, D >::
305  operator()(prec_type * im, const numeric_array<std::size_t,D> dim)
306  {
307  numeric_array<std::size_t,D> sm;
308  numeric_array<std::size_t,D> ssize;
309  std::transform(dim.begin(), dim.end(), sm.begin(), StepInit());
310  // NB: sm_bis has to be initialized here, because it might not be initialized in the
311  // following loop.
312  numeric_array<std::size_t,D> sm_bis = sm;
313 
314  do
315  {
316  // loop in all dimensions, starting with the highest
317  for (int i = D-1; i >= 0; --i)
318  {
319  if (sm[i] >= 1 && greater_than_others(sm, i))
320  {
321  std::transform(dim.begin(), dim.end(), sm.begin(), ssize.begin(), SteppedSize());
322  //for (std::size_t j = 0; j < D; ++j) ssize[j] = SteppedSize()(dim[j], sm[j]);
323  //std::cout << "dir " << i << " step " << sm[0] << " " << sm[1] << " dim " << ssize[0] << " " << ssize[1] << " rdim " << dim[0] << " " << dim[1] << std::endl;
324  //std::cout << "dir " << i << " step " << sm[0] << " " << sm[1] << " " << sm[2] << " dim " << ssize[0] << " " << ssize[1] << " " << ssize[2] << std::endl;
325  m_idwt(im, ssize, i, sm, dim);
326  sm_bis[i] = sm[i] / 2;
327  }
328  }
329  sm = sm_bis;
330  } while (!all_less(sm, 1));
331  }
332 
333  //---------------------------------------------------------------------------
334 
335  template < typename T >
336  void MultiDWTPower< T >::
337  operator()(T * s, std::size_t length, std::size_t hop)
338  {
339  for (std::size_t step = 2; SteppedSize()(length, step) >= 4; step *= 2)
340  {
341  for (std::size_t i = 0; i < length; i += step)
342  {
343  s[i*hop] *= 2;
344  }
345  }
346  }
347 
348  //---------------------------------------------------------------------------
349 
350  template < typename T >
351  void MultiDWTNDPower<T,3>::
352  operator()(T * im, numeric_array<std::size_t,3> dim)
353  {
354  MultiDWTPower<T> power;
355  for (std::size_t k = 0; k < dim[2]; ++k)
356  for (std::size_t j = 0; j < dim[1]; ++j)
357  {
358  power(im+(k*dim[1]+j)*dim[0], dim[0], 1);
359  }
360  for (std::size_t k = 0; k < dim[2]; ++k)
361  for (std::size_t i = 0; i < dim[0]; ++i)
362  {
363  power(im+i+ k*dim[0]*dim[1], dim[1], dim[0]);
364  }
365  for (std::size_t j = 0; j < dim[1]; ++j)
366  for (std::size_t i = 0; i < dim[0]; ++i)
367  {
368  power(im+i+j*dim[0], dim[2], dim[0]*dim[1]);
369  }
370  }
371 
372  //---------------------------------------------------------------------------
373 
374  namespace
375  {
376  /// Reorder sequence by putting the even index first, then the odd.
377  template < typename T >
378  void shuffle_step(T * s, std::size_t length, T * buffer, std::size_t jump)
379  {
380  for (std::size_t i = 0; i < length; ++i)
381  {
382  buffer[i] = s[i*jump];
383  }
384  for (T * p = buffer; p < buffer+length; p+=2, s+=jump)
385  {
386  *s = *p;
387  }
388  for (T * p = buffer+1; p < buffer+length; p+=2, s+=jump)
389  {
390  *s = *p;
391  }
392  }
393 
394  /// Reorder sequence by dispatching first half on even indexes, second half on odd.
395  template < typename T >
396  void unshuffle_step(T * s, std::size_t length, T * buffer, std::size_t jump)
397  {
398  for (std::size_t i = 0, j = 0; i < length; ++i, j += jump)
399  {
400  buffer[i] = s[j];
401  }
402  std::size_t jump2 = 2*jump;
403  std::size_t jl = jump * length;
404  for (T * p = s; p < s + jl; p += jump2)
405  {
406  *p = *(buffer++);
407  }
408  for (T * p = s+jump; p < s + jl; p += jump2)
409  {
410  *p = *(buffer++);
411  }
412  }
413  } // namespace
414 
415  //---------------------------------------------------------------------------
416 
417  template < typename T >
418  void MultiDWTShuffle<T>::shuffle(T * s, std::size_t length, std::size_t jump)
419  {
420  if (m_buffer.size() < length) m_buffer.resize(length);
421  for (std::size_t step = 1; SteppedSize()(length, step) >= 4; step *= 2)
422  {
423  //std::cout << "length " << SteppedSize()(step, length) << " step " << step << std::endl;
424  shuffle_step(s, SteppedSize()(length, step), &m_buffer.front(), jump);
425  }
426  }
427 
428  //---------------------------------------------------------------------------
429 
430  template < typename T >
431  void MultiDWTShuffle<T>::unshuffle(T * s, std::size_t length, std::size_t jump)
432  {
433  if (m_buffer.size() < length) m_buffer.resize(length);
434  std::size_t step;
435  for (step = 1; SteppedSize()(length, step) >= 4; step *= 2);
436  do
437  {
438  step/=2;
439  unshuffle_step(s, SteppedSize()(length, step), &m_buffer.front(), jump);
440  } while (step > 1);
441  }
442 
443  //---------------------------------------------------------------------------
444 
445  template < typename T >
446  void MultiDWTNDShuffle<T,2>::shuffle(T * im, numeric_array<std::size_t,2> dim)
447  {
448  MultiDWTShuffle<T> shuffle;
449  for (std::size_t j = 0; j < dim[1]; ++j)
450  {
451  shuffle.shuffle(im+j*dim[0], dim[0], 1);
452  }
453  for (std::size_t i = 0; i < dim[0]; ++i)
454  {
455  shuffle.shuffle(im+i, dim[1], dim[0]);
456  }
457  }
458 
459  //---------------------------------------------------------------------------
460 
461  template < typename T >
462  void MultiDWTNDShuffle<T,2>::unshuffle(T * im, numeric_array<std::size_t,2> dim)
463  {
464  MultiDWTShuffle<T> shuffle;
465  for (std::size_t j = 0; j < dim[1]; ++j)
466  {
467  shuffle.unshuffle(im+j*dim[0], dim[0], 1);
468  }
469  for (std::size_t i = 0; i < dim[0]; ++i)
470  {
471  shuffle.unshuffle(im+i, dim[1], dim[0]);
472  }
473  }
474 
475  //---------------------------------------------------------------------------
476 
477  template < typename T >
478  void MultiDWTNDShuffle<T,3>::shuffle(T * im, numeric_array<std::size_t,3> dim)
479  {
480  MultiDWTShuffle<T> shuffle;
481  for (std::size_t k = 0; k < dim[2]; ++k)
482  for (std::size_t j = 0; j < dim[1]; ++j)
483  {
484  shuffle.shuffle(im+(k*dim[1]+j)*dim[0], dim[0], 1);
485  }
486  for (std::size_t k = 0; k < dim[2]; ++k)
487  for (std::size_t i = 0; i < dim[0]; ++i)
488  {
489  shuffle.shuffle(im+i+ k*dim[0]*dim[1], dim[1], dim[0]);
490  }
491  for (std::size_t j = 0; j < dim[1]; ++j)
492  for (std::size_t i = 0; i < dim[0]; ++i)
493  {
494  shuffle.shuffle(im+i+j*dim[0], dim[2], dim[0]*dim[1]);
495  }
496  }
497 
498  //---------------------------------------------------------------------------
499 
500  template < typename T >
501  void MultiDWTNDShuffle<T,3>::unshuffle(T * im, numeric_array<std::size_t,3> dim)
502  {
503  MultiDWTShuffle<T> shuffle;
504  for (std::size_t k = 0; k < dim[2]; ++k)
505  for (std::size_t j = 0; j < dim[1]; ++j)
506  {
507  shuffle.unshuffle(im+(k*dim[1]+j)*dim[0], dim[0], 1);
508  }
509  for (std::size_t k = 0; k < dim[2]; ++k)
510  for (std::size_t i = 0; i < dim[0]; ++i)
511  {
512  shuffle.unshuffle(im+i+ k*dim[0]*dim[1], dim[1], dim[0]);
513  }
514  for (std::size_t j = 0; j < dim[1]; ++j)
515  for (std::size_t i = 0; i < dim[0]; ++i)
516  {
517  shuffle.unshuffle(im+i+j*dim[0], dim[2], dim[0]*dim[1]);
518  }
519  }
520 
521  //---------------------------------------------------------------------------
522 
523  /// In-place (4-2) DWT via lifting.
524  template < typename T, typename BC >
525  inline void dwt_cubic(T * s, std::size_t n, std::size_t step, BC)
526  {
527  typename DWTCubic<T, BC>::Direct()(s, n, step);
528  }
529  /// Same as above with cyclic bc by default
530  template < typename T >
531  inline void dwt_cubic(T * s, std::size_t n, std::size_t step)
532  {
533  dwt_cubic(s, n, step, bc::Cyclic());
534  }
535 
536  /// In-place inverse (4-2) DWT via lifting.
537  template < typename T, typename BC >
538  inline void idwt_cubic(T * s, std::size_t n, std::size_t step, BC)
539  {
540  typename DWTCubic<T, BC>::Inverse()(s, n, step);
541  }
542  /// Same as above with cyclic bc by default
543  template < typename T >
544  inline void idwt_cubic(T * s, std::size_t n, std::size_t step)
545  {
546  idwt_cubic(s, n, step, bc::Cyclic());
547  }
548 
549  template < typename T, std::size_t D >
550  inline void dwtND_cubic(T * im, numeric_array<std::size_t, D> dim)
551  {
552  numeric_array<std::size_t, D> step;
553  for (std::size_t i = 0; i < D; ++i)
554  {
555  step[i] = 1;
556  }
557 
558  for (std::size_t i = 0; i < D; ++i)
559  {
560  DWTND<typename DWTCubic<T, bc::Cyclic>::Direct,D>()(im, dim, i, step, dim);
561  }
562  }
563 
564  template < typename T, std::size_t D >
565  inline void dwtND_cubicConjugate(T * im, numeric_array<std::size_t, D> dim)
566  {
567  numeric_array<std::size_t, D> step;
568  for (std::size_t i = 0; i < D; ++i)
569  {
570  step[i] = 1;
571  }
572 
573  for (std::size_t i = 0; i < D; ++i)
574  {
575  DWTND<typename DWTCubicConjugate<T, bc::Cyclic>::Direct,D>()(im, dim, i, step, dim);
576  }
577  }
578 
579 
580  /*
581  /// In-place multidimensional (4-2) DWT along a given direction.
582  template < typename T, std::size_t D >
583  inline void dwtND_cubic(T * im, numeric_array<std::size_t,D> dim, int dir, numeric_array<std::size_t,D> step, numeric_array<std::size_t,D> real_dim)
584  {
585  DWTND<DWTCubic<T>,D>()(im, dim, dir, step, real_dim);
586  }
587 
588  /// In-place multidimensional inverse (4-2) DWT along a given direction.
589  template < typename T, std::size_t D >
590  inline void idwtND_cubic(T * im, numeric_array<std::size_t,D> dim, int dir, numeric_array<std::size_t,D> step, numeric_array<std::size_t,D> real_dim)
591  {
592  DWTND<IDWTCubic<T>,D>()(im, dim, dir, step, real_dim);
593  }
594  */
595 
596  template < typename T, typename BC >
597  void multi_dwt_cubic(T * s, std::size_t dim, BC)
598  {
599  MultiDWT::Direct<typename DWTCubic<T, BC>::Direct>()(s, dim);
600  }
601  template < typename T >
602  void multi_dwt_cubic(T * s, std::size_t dim)
603  {
604  multi_dwt_cubic(s, dim, bc::Cyclic());
605  }
606 
607  template < typename T, typename BC >
608  void multi_idwt_cubic(T * s, std::size_t dim, BC)
609  {
610  MultiDWT::Inverse<typename DWTCubic<T, BC>::Inverse>()(s, dim);
611  }
612  template < typename T >
613  void multi_idwt_cubic(T * s, std::size_t dim)
614  {
615  multi_idwt_cubic(s, dim, bc::Cyclic());
616  }
617 
618  template < typename T, std::size_t D, typename BC >
619  void multi_dwtND_cubic(T * im, numeric_array<std::size_t,D> dim, BC)
620  {
621  MultiDWTND::Direct<DWTND<typename DWTCubic<T, BC>::Direct,D>,D>()(im, dim);
622  }
623  template < typename T, std::size_t D >
624  void multi_dwtND_cubic(T * im, numeric_array<std::size_t,D> dim)
625  {
626  multi_dwtND_cubic(im, dim, bc::Cyclic());
627  }
628 
629  template < typename T, std::size_t D, typename BC >
630  void multi_idwtND_cubic(T * im, numeric_array<std::size_t,D> dim, BC)
631  {
632  MultiDWTND::Inverse<DWTND<typename DWTCubic<T, BC>::Inverse,D>,D>()(im, dim);
633  }
634  template < typename T, std::size_t D >
635  void multi_idwtND_cubic(T * im, numeric_array<std::size_t,D> dim)
636  {
637  multi_idwtND_cubic(im, dim, bc::Cyclic());
638  }
639 
640  template < typename T >
641  void multi_dwt_shuffle(T * s, std::size_t n)
642  {
643  MultiDWTShuffle<T>().shuffle(s,n);
644  }
645 
646  template < typename T >
647  void multi_dwt_unshuffle(T * s, std::size_t n)
648  {
649  MultiDWTShuffle<T>().unshuffle(s, n);
650  }
651 
652  template < typename T, std::size_t D >
653  void multi_dwtND_shuffle(T * im, numeric_array<std::size_t, D> dim)
654  {
655  MultiDWTNDShuffle<T,D>().shuffle(im, dim);
656  }
657 
658  template < typename T, std::size_t D >
659  void multi_dwtND_unshuffle(T * im, numeric_array<std::size_t, D> dim)
660  {
661  MultiDWTNDShuffle<T,D>().unshuffle(im, dim);
662  }
663 
664  template < typename T, std::size_t D >
665  void multi_dwtND_power(T * im, numeric_array<std::size_t, D> dim)
666  {
667  MultiDWTNDPower<T,D>()(im, dim);
668  }
669 
670 } // namespace til
671