libidx
/home/rex/ebltrunk/core/libidx/include/pyramids.hpp
00001 /***************************************************************************
00002  *   Copyright (C) 2011 by Pierre Sermanet   *
00003  *   pierre.sermanet@gmail.com   *
00004  *   All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *     * Redistributions of source code must retain the above copyright
00009  *       notice, this list of conditions and the following disclaimer.
00010  *     * Redistributions in binary form must reproduce the above copyright
00011  *       notice, this list of conditions and the following disclaimer in the
00012  *       documentation and/or other materials provided with the distribution.
00013  *     * Redistribution under a license not approved by the Open Source 
00014  *       Initiative (http://www.opensource.org) must display the 
00015  *       following acknowledgement in all advertising material:
00016  *        This product includes software developed at the Courant
00017  *        Institute of Mathematical Sciences (http://cims.nyu.edu).
00018  *     * The names of the authors may not be used to endorse or promote products
00019  *       derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00023  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00024  * DISCLAIMED. IN NO EVENT SHALL ThE AUTHORS BE LIABLE FOR ANY
00025  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00026  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00027  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00028  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00029  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  ***************************************************************************/
00032 
00033 #ifndef PYRAMIDS_HPP_
00034 #define PYRAMIDS_HPP_
00035 
00036 namespace ebl {
00037 
00039   // constructors/allocation
00040 
00041   template <class T>
00042   gaussian_pyramid<T>::gaussian_pyramid(double c) : a(c) {
00043     filter = create_burt_adelson_kernel<T>(a);
00044   }
00045 
00046   template <class T>
00047   gaussian_pyramid<T>::~gaussian_pyramid() {
00048   }
00049 
00051   // scaling operations
00052 
00053   template <class T>
00054   idx<T> gaussian_pyramid<T>::reduce(idx<T> &in, uint n) {
00055     if (n == 0) // no reductions anymore
00056       return in;
00057     // only accept 2D images or 3D with channel dim to 0.
00058     if ((in.order() != 2) && (in.order() != 3))
00059       eblerror("unexpected image format");
00060     int d0 =  1;
00061     int d1 = d0 + 1;
00062     intg ii = 1 + 2 * ((int) ((in.dim(d0) - 1) / 2));
00063     intg ij = 1 + 2 * ((int) ((in.dim(d1) - 1) / 2));
00064     intg oi = 1 + (ii - 5) / 2;
00065     intg oj = 1 + (ij - 5) / 2;
00066     // copy in into tin without borders
00067     idxdim di(in);
00068     di.setdim(d0, ii);
00069     di.setdim(d1, ij);
00070     red_tin = idx<T>(di);
00071     image_paste_center(in, red_tin);
00072     idx<T> tin = red_tin;
00073     // convolve filter over tin into out
00074     idxdim dout(in);
00075     dout.setdim(d0, oi);
00076     dout.setdim(d1, oj);
00077     idx<T> out(dout);   
00078     idx_clear(out);
00079     if (tin.order() == 3) { // loop over each channel
00080       idx_bloop2(ttin, tin, T, outt, out, T) {
00081         idx<T> uin = ttin.unfold(0, 5, 2);
00082         uin = uin.unfold(1, 5, 2);
00083         idx_m4dotm2acc(uin, filter, outt);
00084       }
00085     }  
00086     else {      
00087       idx<T> uin = tin.unfold(0, 5, 2);
00088       uin = uin.unfold(1, 5, 2);
00089       idx_m4dotm2acc(uin, filter, out); // just one channel
00090     }
00091     return reduce(out, n - 1);
00092   }
00093 
00094   template <class T>
00095   rect<uint> gaussian_pyramid<T>::reduce_rect(const rect<uint> &r, uint n) {
00096     if (n == 0)
00097       return r;
00098     uint h = 1+ ((1 + 2 * ((int) (r.height - 1) / 2)) - 5) / 2;
00099     uint w = 1+((1 + 2 * ((int) (r.width - 1) / 2)) - 5) / 2;  
00100     uint h0 = r.h0 / 2;
00101     uint w0 = r.w0 / 2;
00102     rect<uint> rr(h0, w0, h, w);
00103     return reduce_rect(rr, n - 1);
00104   }
00105 
00106   template <class T>
00107   uint gaussian_pyramid<T>::count_reductions(uint insz, uint outsz,
00108                                                  uint &dist) {
00109     if (insz <= outsz) {
00110       // set distance below outsz
00111       dist = outsz - insz;
00112       return 0;
00113     }
00114     uint newsz = ((1 + 2 * ((int) (insz - 1) / 2)) - 5) / 2;
00115     return 1 + count_reductions(newsz, outsz, dist);
00116   }
00117 
00118   template <class T>
00119   uint gaussian_pyramid<T>::
00120   count_reductions_exact(rect<uint> &inr, rect<uint> &outr,
00121                          rect<uint> &inr_exact) {
00122     // upsample from exact target size beyond current input size
00123     uint distup;
00124     uint expansions = count_expansions(outr.height, inr.height, distup);
00125     rect<uint> uprect = expand_rect(outr, expansions);
00126     rect<uint> downrect = expand_rect(outr, (std::max)((uint) 0,
00127                                                        expansions - 1));
00128     if (uprect.height - inr.height < inr.height - downrect.height) {
00129       inr_exact = uprect;
00130       return expansions;
00131     } else {
00132       inr_exact = downrect;
00133       return expansions - 1;
00134     }
00135   }
00136 
00137   template <class T>
00138   idx<T> gaussian_pyramid<T>::expand(idx<T> &in, uint n) {
00139     if (n == 0) // no more expansions
00140       return in; 
00141     // only accept 2D images or 3D with channel dim to 0.
00142     if ((in.order() != 2) && (in.order() != 3)) {
00143       cerr << "error: gaussian_pyramid only accepts 2D images ";
00144       cerr << "or 3D. ";
00145       cerr << "input image is " << in << endl;
00146       eblerror("unexpected image format");
00147     }
00148     int d0 = 1;
00149     int d1 = 2;
00150      intg ii = in.dim(d0);
00151     intg ij = in.dim(d1);
00152     intg oi = (ii - 1) * 2 + 5;
00153     intg oj = (ij - 1) * 2 + 5;
00154     
00155     idxdim di(in);
00156     di.setdim(d0, oi);
00157     di.setdim(d1, oj);      
00158     idx<T> tin(di);
00159     idx_clear(tin);
00160 
00161     // prepare filter x4
00162     idxdim df(filter);
00163     idx<T> filt(df);
00164     idx_copy(filter, filt);
00165     idx_dotc(filt, (T) 4, filt);
00166 
00167     if (tin.order() == 3) { // loop over each channel
00168       idx_bloop2(inn, in, T, ttin, tin, T) {
00169         idx<T> uin = ttin.unfold(0, 5, 2);
00170         uin = uin.unfold(1, 5, 2);
00171         idx_m2extm2acc(inn, filt, uin);
00172       }
00173     }
00174     else {      
00175       idx<T> uin = tin.unfold(0, 5, 2);
00176       uin = uin.unfold(1, 5, 2);
00177       idx_m2extm2acc(in, filt, uin); // just one channel
00178     }
00179     tin = cut_pad(tin, 2);
00180     return expand(tin, n - 1);
00181   }
00182 
00183   template <class T>
00184   rect<uint> gaussian_pyramid<T>::expand_rect(const rect<uint> &r, uint n) {
00185     if (n == 0)
00186       return r;
00187     uint h = (r.height - 1) * 2 + 5;
00188     uint w = (r.width - 1) * 2 + 5;
00189     uint h0 = r.h0 * 2;
00190     uint w0 = r.w0 * 2;
00191     rect<uint> rr(h0, w0, h, w);
00192     return expand_rect(rr, n - 1);
00193   }
00194   
00195   template <class T>
00196   uint gaussian_pyramid<T>::count_expansions(uint insz, uint outsz,
00197                                                  uint &dist) {
00198     if (insz > outsz) {
00199       return 0;
00200     }
00201     dist = (uint) abs((float)outsz - insz);
00202     uint newsz = (insz - 1) * 2 + 5;
00203     return 1 + count_expansions(newsz, outsz, dist);
00204   }
00205 
00207   // util methods
00208 
00209   template <class T>
00210   idx<T> gaussian_pyramid<T>::cut_pad(idx<T> &in, int nz) {
00211     idxdim dout(in);
00212     int d0 = 1;
00213     int d1 = d0 + 1;
00214     dout.setdim(d0, in.dim(d0) - 2 * nz);
00215     dout.setdim(d1, in.dim(d1) - 2 * nz);
00216     idx<T> o = idx<T>(dout);
00217     idx<T> i = in.narrow(d0, o.dim(d0), nz);
00218     i = i.narrow(d1, o.dim(d1), nz);
00219     idx_copy(i, o);
00220     return o;
00221   }
00222 
00223 } // end namespace ebl
00224 
00225 #endif /* PYRAMIDS_HPP_ */