libidx
|
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_ */