dwt.hh

00001 // Copyright (C) 2001, 2002, 2003, 2004  EPITA Research and Development Laboratory
00002 //
00003 // This file is part of the Olena Library.  This library is free
00004 // software; you can redistribute it and/or modify it under the terms
00005 // of the GNU General Public License version 2 as published by the
00006 // Free Software Foundation.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this library; see the file COPYING.  If not, write to
00015 // the Free Software Foundation, 59 Temple Place - Suite 330, Boston,
00016 // MA 02111-1307, USA.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software library without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to
00022 // produce an executable, this file does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public
00024 // License.  This exception does not however invalidate any other
00025 // reasons why the executable file might be covered by the GNU General
00026 // Public License.
00027 
00028 #ifndef OLENA_TRANSFORMS_DWT_HH
00029 # define OLENA_TRANSFORMS_DWT_HH
00030 
00031 # include <oln/config/system.hh>
00032 # include <oln/basics.hh>
00033 
00034 # include <ntg/basics.hh>
00035 # include <ntg/float.hh>
00036 # include <ntg/utils/cast.hh>
00037 # include <mlc/array/1d.hh>
00038 
00039 // FIXME: this file has not been adjusted to the coding style since it
00040 // will be completely rewritten in next release.
00041 
00042 namespace oln {
00043 
00047   namespace transforms {
00048 
00049     // macros used to define all the wavelets coefficients
00050 
00051 # define Wavelet_coeffs_definition(Name, Type, Size) \
00052     struct Name : public oln::internal::wavelet_coeffs_<Type, Size, Name > \
00053     { \
00054       Name()
00055 
00056 # define Wavelet_coeffs_begin \
00057       h = (wc_start =
00058 
00059 # define Wavelet_coeffs_end \
00060         , end); \
00061       init(); \
00062     }
00063 
00067     typedef enum {
00068       dwt_std,
00069       dwt_non_std
00070     } dwt_transform_type;
00071 
00072   } // end of namespace transforms
00073 
00074   namespace internal
00075   {
00077     static const ntg::float_d ln_2_ = 0.6931471805599453092;
00078 
00086     template <class T, unsigned N, class Self>
00087     struct wavelet_coeffs_
00088     {
00089       typedef T         value_t; 
00090       typedef Self      self_t; 
00091 
00092     public:
00093 
00094       // accessors
00096       const value_t getG(unsigned i) const { return g[i]; }
00098       const value_t getInvG(unsigned i) const { return ig[i]; }
00100       const value_t getH(unsigned i) const { return h[i]; }
00102       const value_t getInvH(unsigned i) const { return ih[i]; }
00104       const unsigned size() const { return size_; }
00105 
00106     protected:
00112       void init()
00113       {
00114         for (unsigned i = 0; i < size_; i += 2) {
00115           g[i] = -h[size_ - 1 - i];
00116           g[i + 1] = h[size_ - 2 - i];
00117           ig[size_ - 1 - i] = g[i + 1];
00118           ig[size_ - 2 - i] = h[i + 1];
00119           ih[size_ - 1 - i] = g[i];
00120           ih[size_ - 2 - i] = h[i];
00121         }
00122       }
00123 
00127       wavelet_coeffs_(){}
00128 
00134       ~wavelet_coeffs_()
00135       {
00136         mlc::is_false<N % 2>::ensure();
00137       }
00138 
00139       mlc::array1d< mlc::array1d_info<N>, value_t>      h; 
00140       mlc::internal::array1d_start_<value_t>            wc_start; 
00141 
00142     private:
00143 
00144       value_t   g[N]; 
00145       value_t   ih[N]; 
00146       value_t   ig[N]; 
00147       enum {
00148         size_ = N
00149       };
00150     };
00151 
00164     template <class I, class K>
00165     void dwt_transform_step_(abstract::image<I>& im,
00166                              const oln_point_type(I)& p_,
00167                              const unsigned d,
00168                              const unsigned n,
00169                              const K& coeffs)
00170     {
00171       assertion(n >= coeffs.size());
00172 
00173       const unsigned    half = n >> 1;
00174       unsigned          lim = n + 1 - coeffs.size();
00175       ntg::float_d*     tmp = new ntg::float_d[n];
00176       oln_point_type(I) p(p_);
00177       unsigned          i, j, k;
00178 
00179       for (i = 0, j = 0; j < lim; j += 2, i++) {
00180         tmp[i] = 0;
00181         tmp[i + half] = 0;
00182         for (k = 0; k < coeffs.size(); k++) {
00183           p.nth(d) = j + k;
00184           tmp[i] += im[p] * coeffs.getH(k);
00185           tmp[i + half] += im[p] * coeffs.getG(k);
00186         }
00187       }
00188       for (; i < half; j += 2, i++) {
00189         tmp[i] = 0;
00190         tmp[i + half] = 0;
00191         for (unsigned k = 0; k < coeffs.size(); k++) {
00192           p.nth(d) = (j + k) % n;
00193           tmp[i] += im[p] * coeffs.getH(k);
00194           tmp[i + half] += im[p] * coeffs.getG(k);
00195         }
00196       }
00197 
00198       for (i = 0; i < n; i++) {
00199         p.nth(d) = i;
00200         im[p] = tmp[i];
00201       }
00202 
00203       delete[] tmp;
00204     }
00205 
00218     template <class I, class K>
00219     void dwt_transform_inv_step_(abstract::image<I>& im,
00220                                  const oln_point_type(I)& p_,
00221                                  const unsigned d,
00222                                  const unsigned n,
00223                                  const K& coeffs)
00224     {
00225       assertion(n >= coeffs.size());
00226 
00227       const unsigned half = n >> 1;
00228       unsigned lim = coeffs.size() - 2;
00229       ntg::float_d* tmp = new ntg::float_d[n];
00230      oln_point_type(I) p(p_), q(p_);
00231       unsigned i, j, k, l;
00232 
00233       for (i = half - lim / 2, j = 0; j < lim; i++, j += 2) {
00234         tmp[j] = 0;
00235         tmp[j + 1] = 0;
00236         for (k = 0, l = 0; l < coeffs.size(); k++, l += 2) {
00237           p.nth(d) = (i + k) % half;
00238           q.nth(d) = p.nth(d) + half;
00239           tmp[j] += im[p] * coeffs.getInvH(l) + im[q] * coeffs.getInvH(l + 1);
00240           tmp[j + 1] += im[p] * coeffs.getInvG(l) + im[q] * coeffs.getInvG(l + 1);
00241         }
00242       }
00243       lim = n - 1;
00244       for (i = 0; j < lim; i++, j += 2) {
00245         tmp[j] = 0;
00246         tmp[j + 1] = 0;
00247         for (k = 0, l = 0; l < coeffs.size(); k++, l += 2) {
00248           p.nth(d) = i + k;
00249           q.nth(d) = p.nth(d) + half;
00250           tmp[j] += im[p] * coeffs.getInvH(l) + im[q] * coeffs.getInvH(l + 1);
00251           tmp[j + 1] += im[p] * coeffs.getInvG(l) + im[q] * coeffs.getInvG(l + 1);
00252         }
00253       }
00254 
00255       for (i = 0; i < n; i++) {
00256         p.nth(d) = i;
00257         im[p] = tmp[i];
00258       }
00259 
00260       delete[] tmp;
00261     }
00262 
00263     // Functions used to iterate over all dimensions except one
00267     typedef enum {
00268       dwt_fwd,
00269       dwt_bwd
00270     } dwt_transform_dir_;
00271 
00279     template <unsigned dim, unsigned skip,
00280               unsigned current = dim>
00281     struct dim_skip_iterate_rec_
00282     {
00286       template <class I, class K>
00287       static void doit(abstract::image<I>& im,
00288                       oln_point_type(I)& p,
00289                        const unsigned l1,
00290                        const unsigned l2,
00291                        const K& coeffs,
00292                        dwt_transform_dir_ d)
00293       {
00294         if (current != skip) {
00295           for (unsigned i = 0; i < l2; i++) {
00296             p.nth(current - 1) = i;
00297             dim_skip_iterate_rec_<dim, skip, current - 1>::
00298 	      doit(im, p, l1, l2, coeffs, d);
00299           }
00300           p.nth(current - 1) = 0;
00301         }
00302         else
00303           dim_skip_iterate_rec_<dim, skip, current - 1>::
00304 	    doit(im, p, l1, l2, coeffs, d);
00305       }
00306     };
00307 
00315     template <unsigned dim, unsigned skip>
00316     struct dim_skip_iterate_rec_<dim, skip, 0>
00317     {
00326       template <class I, class K>
00327       static void doit(abstract::image<I>& im,
00328                       oln_point_type(I)& p,
00329                        const unsigned l1,
00330                        const unsigned l2,
00331                        const K& coeffs,
00332                        dwt_transform_dir_ d)
00333       {
00334         unsigned n;
00335 
00336         switch (d) {
00337         case dwt_fwd:
00338           for (n = l2; n >= l1; n >>= 1)
00339             dwt_transform_step_(im, p, skip - 1, n, coeffs);
00340           break;
00341         case dwt_bwd:
00342           for (n = l1; n <= l2; n <<= 1)
00343             dwt_transform_inv_step_(im, p, skip - 1, n, coeffs);
00344           break;
00345         };
00346       }
00347     };
00348 
00355     template <unsigned dim, unsigned skip>
00356     struct dim_iterate_rec_
00357     {
00364       template <class I, class K>
00365       static void doit(abstract::image<I>& im,
00366                       oln_point_type(I)& p,
00367                        const unsigned l1,
00368                        const unsigned l2,
00369                        const K& coeffs,
00370                        dwt_transform_dir_ d)
00371       {
00372         dim_skip_iterate_rec_<dim, skip>::doit(im, p, l1, l2, coeffs, d);
00373         dim_iterate_rec_<dim, skip - 1>::doit(im, p, l1, l2, coeffs, d);
00374       }
00375     };
00376 
00383     template <unsigned dim>
00384     struct dim_iterate_rec_<dim, 0>
00385     {
00386 
00395       template <class I, class K>
00396       static void doit(abstract::image<I>& ,
00397                       oln_point_type(I)& ,
00398                        const unsigned ,
00399                        const unsigned ,
00400                        const K& ,
00401                        dwt_transform_dir_ )
00402       {
00403         // end of recursion
00404       }
00405     };
00406 
00413     template <class I, class K>
00414     void dwt_transform_(abstract::image<I>& im,
00415                         const unsigned l1,
00416                         const unsigned l2,
00417                         const K& coeffs,
00418                         transforms::dwt_transform_type t)
00419     {
00420      oln_point_type(I) p;
00421 
00422       switch (t) {
00423       case transforms::dwt_std:
00424         dim_iterate_rec_<I::dim, I::dim>::doit(im, p, l1, l2, coeffs, dwt_fwd);
00425         break;
00426       case transforms::dwt_non_std:
00427         for (unsigned n = l2; n >= l1; n >>= 1)
00428           dim_iterate_rec_<I::dim, I::dim>::doit(im, p, n, n, coeffs, dwt_fwd);
00429         break;
00430       }
00431     }
00432 
00439     template <class I, class K>
00440     void dwt_transform_inv_(abstract::image<I>& im,
00441                             const unsigned l1,
00442                             const unsigned l2,
00443                             const K& coeffs,
00444                             transforms::dwt_transform_type t)
00445     {
00446      oln_point_type(I) p;
00447 
00448       switch (t) {
00449       case transforms::dwt_std:
00450         dim_iterate_rec_<I::dim, I::dim>::doit(im, p, l1, l2, coeffs, dwt_bwd);
00451         break;
00452       case transforms::dwt_non_std:
00453         for (unsigned n = l1; n <= l2; n <<= 1)
00454           dim_iterate_rec_<I::dim, I::dim>::doit(im, p, n, n, coeffs, dwt_bwd);
00455         break;
00456       }
00457     }
00458 
00459   } // end of namespace internal
00460 
00461   namespace transforms {
00462 
00469     template <class I, class K>
00470     class dwt
00471     {
00472     public:
00473 
00474       typedef I                                         original_im_t; 
00475       typedef oln_value_type(I)                         original_im_value_t; 
00476       typedef typename mute<I, ntg::float_d>::ret       trans_im_t; 
00477       typedef typename K::self_t                        coeffs_t; 
00478 
00486       dwt(const original_im_t& im) : original_im(im)
00487       {
00488         ntg_is_a(original_im_value_t, ntg::real)::ensure();
00489 
00490         im_size = im.size().nth(0);
00491         assertion(im_size >= coeffs.size());
00492         for (unsigned i = 1; i < original_im_t::dim; i++)
00493           assertion(im_size == static_cast<unsigned>(im.size().nth(i)));
00494 
00495         max_level = static_cast<unsigned>(log(2 * im_size / coeffs.size()) /
00496                                internal::ln_2_);
00497 
00498         current_level = max_level;
00499 
00500         assertion(!(im_size % (1 << max_level)));
00501 
00502         trans_im = trans_im_t(im.size());
00503       }
00504 
00510       const trans_im_t transformed_image() const
00511       {
00512         return trans_im;
00513       }
00514 
00520       trans_im_t& transformed_image()
00521       {
00522         return trans_im;
00523       }
00524 
00532       trans_im_t transform(dwt_transform_type t = dwt_non_std,
00533                            bool normalized = true, unsigned l = 0)
00534       {
00535         if (l == 0) {
00536           l = max_level;
00537           current_level = max_level;
00538         } else {
00539           if (l > max_level)
00540             l = max_level;
00541           current_level = l;
00542         }
00543 
00544         oln_iter_type(trans_im_t) it(trans_im);
00545 
00546         if (normalized) {
00547           norm = pow(sqrt(2), original_im_t::dim * l);
00548           for_all(it)
00549             trans_im[it] = original_im[it] / norm;
00550         }
00551         else {
00552           norm = 1;
00553           for_all(it)
00554             trans_im[it] = original_im[it];
00555         }
00556 
00557         unsigned lim = im_size >> (l - 1);
00558         transform_type = t;
00559 
00560         internal::dwt_transform_(trans_im, lim, im_size, coeffs, t);
00561 
00562         return trans_im;
00563       }
00564 
00570       trans_im_t transform_inv(unsigned l = 0)
00571       {
00572         if (l == 0)
00573           l = current_level;
00574         else if (l > current_level)
00575           l = current_level;
00576 
00577         trans_im_t new_im(trans_im.size());
00578         oln_iter_type(trans_im_t) it(trans_im);
00579 
00580         if (norm != 1) {
00581           for_all(it)
00582             new_im[it] = trans_im[it] * norm;
00583         }
00584         else
00585           for_all(it)
00586             new_im[it] = trans_im[it];
00587 
00588         unsigned lim1 = im_size >> (current_level - 1);
00589         unsigned lim2 = im_size >> (current_level - l);
00590 
00591         internal::dwt_transform_inv_(new_im, lim1, lim2, coeffs, transform_type);
00592 
00593         return new_im;
00594       }
00595 
00603       template <class T1>
00604       typename mute<I, T1>::ret transform_inv(unsigned l = 0)
00605       {
00606         ntg_is_a(T1, ntg::real)::ensure();
00607 
00608         trans_im_t tmp_im = transform_inv(l);
00609         typename mute<I, T1>::ret new_im(tmp_im.size());
00610 
00611         oln_iter_type(trans_im_t) it(tmp_im);
00612 
00613         for_all(it)
00614           new_im[it] = (tmp_im[it] >= ntg_inf_val(T1) ?
00615                         (tmp_im[it] <= ntg_sup_val(T1) ?
00616                          tmp_im [it] :
00617                          ntg_sup_val(T1)) :
00618                         ntg_inf_val(T1));
00619         return new_im;
00620       }
00621 
00622     private:
00623 
00624       const original_im_t&      original_im; 
00625       trans_im_t                trans_im; 
00626       const coeffs_t            coeffs; 
00627       unsigned                  im_size; 
00628       unsigned                  max_level; 
00629       unsigned                  current_level; 
00630       ntg::float_d              norm; 
00631       dwt_transform_type        transform_type; 
00632     };
00633 
00634   } // end of namespace transforms
00635 
00636 } // end of namespace oln
00637 
00638 #endif // ! OLENA_TRANSFORMS_DWT_HH

Generated on Thu Apr 15 20:13:08 2004 for Olena by doxygen 1.3.6-20040222