00001 /*!@file Image/LowPassLpt.C low-pass filtering and smoothing functions */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: David J. Berg <dberg@usc.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/LowPassLpt.C $ 00035 // 00036 00037 #ifndef IMAGE_LOWPASSLPT_C_DEFINED 00038 #define IMAGE_LOWPASSLPT_C_DEFINED 00039 00040 #include "Image/LowPassLpt.H" 00041 00042 #include "Image/Convolutions.H" 00043 #include "Image/LowPass.H" 00044 #include "Image/Image.H" 00045 #include "Image/Kernels.H" 00046 #include "Image/Pixels.H" 00047 #include "rutz/trace.h" 00048 00049 // ###################################################################### 00050 template <class T_or_RGB> 00051 Image<typename promote_trait<T_or_RGB, float>::TP> 00052 lowPassLpt(const Image<T_or_RGB>& src, const uint taps, BorderPolicy policy) 00053 { 00054 if (taps == 5) 00055 if (policy == CROSS_HEMI) 00056 return lowPassLpt5w(lowPass5x(src)); 00057 else if (policy == SEPARATE_HEMI) 00058 return lowPass5y(lowPassLpt5r(src)); 00059 else 00060 return lowPassLpt5w(lowPassLpt5r(src)); 00061 else if (taps == 3) 00062 if (policy == CROSS_HEMI) 00063 return lowPassLpt3w(lowPass3x(src)); 00064 else if (policy == SEPARATE_HEMI) 00065 return lowPass3y(lowPassLpt3r(src)); 00066 else 00067 return lowPassLpt3w(lowPassLpt3r(src)); 00068 else 00069 return Image<typename promote_trait<T_or_RGB, float>::TP>(); 00070 } 00071 00072 00073 // ###################################################################### 00074 template <class T_or_RGB> 00075 Image<typename promote_trait<T_or_RGB, float>::TP> 00076 lowPassLpt3(const Image<T_or_RGB>& src, BorderPolicy policy) 00077 { 00078 if (policy == CROSS_HEMI) 00079 return lowPassLpt3w(lowPass3x(src)); 00080 else if (policy == SEPARATE_HEMI) 00081 return lowPass3y(lowPassLpt3r(src)); 00082 else 00083 return lowPassLpt3w(lowPassLpt3r(src)); 00084 } 00085 00086 // ###################################################################### 00087 template <class T_or_RGB> 00088 Image<typename promote_trait<T_or_RGB, float>::TP> 00089 lowPassLpt3r(const Image<T_or_RGB>& src) 00090 { 00091 //really this should only be for images with even width, but the 00092 // operator will still work so we wont disallow it explicitly. 00093 GVX_TRACE(__PRETTY_FUNCTION__); 00094 const int w = src.getWidth(), h = src.getHeight(), 00095 hf = w / 2, h2 = 2*h; 00096 // promote the source image to float if necessary, so that we do the 00097 // promotion only once for all, rather than many times as we access 00098 // the pixels of the image; if no promotion is necessary, "source" 00099 // will just point to the original data of "src" through the 00100 // copy-on-write/ref-counting behavior of Image: 00101 typedef typename promote_trait<T_or_RGB, float>::TP TF; 00102 const Image<TF> source = src; 00103 if (w < 2) 00104 return source; // nothing to smooth 00105 00106 Image<TF> result(w, h, NO_INIT); 00107 typename Image<TF>::const_iterator sptr = source.begin(); 00108 typename Image<TF>::iterator dptr = result.beginw(); 00109 00110 // Do not use access overload since can access the C array directly. 00111 // the bet is: float computations are faster than int (true for most 00112 // float copros), and int2float converts fast->do not have to divide 00113 // by the coeff sum since we directly use float coeffs. 00114 // notations: in () is the position of dest ptr, and ^ is src ptr 00115 // ########## horizontal pass 00116 for (int j = 0; j < h2; j ++) 00117 { 00118 // leftmost point [ (2^) 1 ] / 3 00119 *dptr++ = sptr[0] * (2.0F / 3.0F) + sptr[1] * (1.0F / 3.0F); 00120 00121 // rest of the line up to the vertical meridian [ 1^ (2) 1] / 4 00122 for (int i = 0; i < hf - 2; i ++) 00123 { 00124 *dptr++ = (sptr[0] + sptr[2]) * 0.25F + sptr[1] * 0.5F; 00125 sptr++; 00126 } 00127 00128 // last point [ 1^ (2) ] / 3 00129 *dptr++ = sptr[0] * (1.0F / 3.0F) + sptr[1] * (2.0F / 3.0F); 00130 sptr += 2; // sptr back to same position as dptr 00131 } 00132 return result; 00133 } 00134 00135 // ###################################################################### 00136 template <class T_or_RGB> 00137 Image<typename promote_trait<T_or_RGB, float>::TP> 00138 lowPassLpt3w(const Image<T_or_RGB>& src) 00139 { 00140 GVX_TRACE(__PRETTY_FUNCTION__); 00141 const int w = src.getWidth(), h = src.getHeight(); 00142 // promote the source image to float if necessary, so that we do the 00143 // promotion only once for all, rather than many times as we access 00144 // the pixels of the image; if no promotion is necessary, "source" 00145 // will just point to the original data of "src" through the 00146 // copy-on-write/ref-counting behavior of Image: 00147 typedef typename promote_trait<T_or_RGB, float>::TP TF; 00148 const Image<TF> source = src; 00149 if (h < 2) 00150 return source; // nothing to smooth 00151 Image<TF> result(w, h, NO_INIT); 00152 typename Image<TF>::const_iterator sptr = source.begin(), 00153 sptrh = source.begin() + w - 1;//the last point in the first image row 00154 typename Image<TF>::iterator dptr = result.beginw(); 00155 const int w2 = w * 2; // speedup 00156 00157 //'<' symbol means opposide side of the image 00158 // ########## vertical pass (even though we scan horiz for speedup) 00159 // topmost points ( [1< (2^) 1 ] / 4 )^T 00160 for (int i = 0; i < w; i ++) 00161 { 00162 //at the border get the pixel from the other hemiefield 00163 *dptr++ = (sptrh[0] + sptr[w]) * 0.25F + sptr[0] * 0.5F; 00164 ++sptr; 00165 --sptrh; 00166 } 00167 sptr -= w; // go back to top-left 00168 00169 // rest of the column except last point ( [ 1^ (2) 1 ] / 4.0 )^T 00170 for (int j = 0; j < h - 2; j ++) 00171 for (int i = 0; i < w; i ++) 00172 { 00173 *dptr++ = (sptr[0] + sptr[w2]) * 0.25F + sptr[w] * 0.5F; 00174 ++sptr; 00175 } 00176 00177 // last points ( [ 1^ (2) 1<] / 4 )^T 00178 sptrh += w*h-1;//go to the last point in the image 00179 for (int i = 0; i < w; i ++) 00180 { 00181 *dptr++ = (sptr[0] + sptrh[0]) * 0.25F + sptr[w] * 0.5F; 00182 ++sptr; 00183 --sptrh; 00184 } 00185 00186 // finished. here, sptr is one line before the end of array. 00187 return result; 00188 } 00189 00190 // ###################################################################### 00191 template <class T_or_RGB> 00192 Image<typename promote_trait<T_or_RGB, float>::TP> 00193 lowPassLpt5(const Image<T_or_RGB>& src, BorderPolicy policy) 00194 { 00195 if (policy == CROSS_HEMI) 00196 return lowPassLpt5w(lowPass5x(src)); 00197 else if (policy == SEPARATE_HEMI) 00198 return lowPass5y(lowPassLpt5r(src)); 00199 else 00200 return lowPassLpt5w(lowPassLpt5r(src)); 00201 } 00202 00203 // ###################################################################### 00204 template <class T_or_RGB> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00205 Image<typename promote_trait<T_or_RGB, float>::TP> 00206 lowPassLpt5r(const Image<T_or_RGB>& src) 00207 { 00208 //this operator really only makes sense on even width images but 00209 //since it will still work we wont explicity disallow it. 00210 GVX_TRACE(__PRETTY_FUNCTION__); 00211 const int w = src.getWidth(), h = src.getHeight(), 00212 hf = w/2, h2 = 2*h; 00213 // promote the source image to float if necessary, so that we do the 00214 // promotion only once for all, rather than many times as we access 00215 // the pixels of the image; if no promotion is necessary, "source" 00216 // will just point to the original data of "src" through the 00217 // copy-on-write/ref-counting behavior of Image: 00218 typedef typename promote_trait<T_or_RGB, float>::TP TF; 00219 const Image<TF> source = src; 00220 if (w < 4) 00221 return source; // nothing to smooth 00222 Image<TF> result(w, h, NO_INIT); 00223 typename Image<TF>::const_iterator sptr = source.begin(); 00224 typename Image<TF>::iterator dptr = result.beginw(); 00225 00226 //Do not use access overloading since can 00227 // access the C array directly. the bet is: float 00228 // computations are faster than int (true for most float 00229 // copros), and int2float convert is fast -> do not have to 00230 // divide by the coeff sum since we directly use float 00231 // coeffs. 00232 // notations: in () is the position of dest ptr, and ^ is src ptr 00233 // ########## horizontal pass 00234 for (int j = 0; j < h2; j ++) 00235 { 00236 // leftmost point [ (6^) 4 1 ] / 11 00237 *dptr++ = sptr[0] * (6.0F / 11.0F) + 00238 sptr[1] * (4.0F / 11.0F) + 00239 sptr[2] * (1.0F / 11.0F); 00240 00241 // second point [ 4^ (6) 4 1 ] / 15 00242 *dptr++ = (sptr[0] + sptr[2]) * (4.0F / 15.0F) + 00243 sptr[1] * (6.0F / 15.0F) + 00244 sptr[3] * (1.0F / 15.0F); 00245 00246 // rest of the line to vertical meridian [ 1^ 4 (6) 4 1 ] / 16.0 00247 for (int i = 0; i < hf - 4; i ++) 00248 { 00249 *dptr++ = (sptr[0] + sptr[4]) * (1.0F / 16.0F) + 00250 (sptr[1] + sptr[3]) * (4.0F / 16.0F) + 00251 sptr[2] * (6.0F / 16.0F); 00252 ++sptr; 00253 } 00254 00255 // before last point [ 1^ 4 (6) 4 ] / 15 00256 *dptr++ = sptr[0] * (1.0F / 15.0F) + 00257 (sptr[1] + sptr[3]) * (4.0F / 15.0F) + 00258 sptr[2] * (6.0F / 15.0F); 00259 ++sptr; 00260 00261 // last point [ 1^ 4 (6) ] / 11 00262 *dptr++ = sptr[0] * (1.0F / 11.0F) + 00263 sptr[1] * (4.0F / 11.0F) + 00264 sptr[2] * (6.0F / 11.0F); 00265 sptr += 3; // sptr back to same position as dptr 00266 } 00267 return result; 00268 } 00269 00270 // ###################################################################### 00271 template <class T_or_RGB> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00272 Image<typename promote_trait<T_or_RGB, float>::TP> 00273 lowPassLpt5w(const Image<T_or_RGB>& src) 00274 { 00275 GVX_TRACE(__PRETTY_FUNCTION__); 00276 const int w = src.getWidth(), h = src.getHeight(); 00277 // promote the source image to float if necessary, so that we do the 00278 // promotion only once for all, rather than many times as we access 00279 // the pixels of the image; if no promotion is necessary, "source" 00280 // will just point to the original data of "src" through the 00281 // copy-on-write/ref-counting behavior of Image: 00282 typedef typename promote_trait<T_or_RGB, float>::TP TF; 00283 const Image<TF> source = src; 00284 if (h < 4) 00285 return source; // nothing to smooth 00286 Image<TF> result(w, h, NO_INIT); 00287 typename Image<TF>::const_iterator sptr = source.begin(), 00288 sptrh = source.begin()+w-1;//the last point in the first image row 00289 typename Image<TF>::iterator dptr = result.beginw(); 00290 00291 // ########## vertical pass (even though we scan horiz for speedup) 00292 const int w2 = w * 2, w3 = w * 3, w4 = w * 4; // speedup 00293 //'<' symbol means opposite side of the image 00294 // topmost points ( [1< 4< (6^) 4 1 ] / 16 )^T 00295 for (int i = 0; i < w; i ++) 00296 { 00297 *dptr++ = sptr[0] * (6.0F / 16.0F) + 00298 (sptr[w] + sptrh[0] ) * (4.0F / 16.0F) + 00299 (sptr[w2] + sptrh[w2] ) * (1.0F / 16.0F); 00300 ++sptr; 00301 --sptrh; 00302 } 00303 sptr -= w; // go back to top-left 00304 sptrh += w;//go back to last point in first row 00305 00306 // second topmost points ( [1< 4^ (6) 4 1 ] / 16 )^T 00307 for (int i = 0; i < w; i ++) 00308 { 00309 *dptr++ = (sptr[0] + sptr[w2]) * (4.0F / 16.0F) + 00310 sptr[w] * (6.0F / 16.0F) + 00311 (sptr[w3] + sptrh[0]) * (1.0F / 16.0F); 00312 ++sptr; 00313 --sptrh; 00314 } 00315 sptr -= w; // go back to top-left 00316 00317 // rest of the column except last 2 points ( [ 1^ 4 (6) 4 1 ] / 16 )T 00318 for (int j = 0; j < h - 4; j ++) 00319 for (int i = 0; i < w; i ++) 00320 { 00321 *dptr++ = (sptr[ 0] + sptr[w4]) * (1.0F / 16.0F) + 00322 (sptr[ w] + sptr[w3]) * (4.0F / 16.0F) + 00323 sptr[w2] * (6.0F / 16.0F); 00324 sptr++; 00325 } 00326 00327 sptrh = source.end();//the last point in the image 00328 // before last points ( [ 1^ 4 (6) 4 1< ] / 16 )T 00329 for (int i = 0; i < w; i ++) 00330 { 00331 *dptr++ = (sptr[0] + sptrh[0]) * (1.0F / 16.0F) + 00332 (sptr[w] + sptr[w3]) * (4.0F / 16.0F) + 00333 sptr[w2] * (6.0F / 16.0F); 00334 ++sptr; 00335 --sptrh; 00336 } 00337 --sptrh;//how we are the last pixel in the second to last row. 00338 // last points ( [ 1^ 4 (6) 4< 1< ] / 16 )T 00339 for (int i = 0; i < w; i ++) 00340 { 00341 *dptr++ = (sptr[0] + sptrh[0]) * (1.0F / 16.0F) + 00342 (sptr[w] + sptrh[w]) * (4.0F / 16.0F) + 00343 sptr[w2] * (6.0F / 16.0F); 00344 ++sptr; 00345 --sptrh; 00346 } 00347 // finished. here, sptr is two lines before the end of array. 00348 return result; 00349 } 00350 00351 // ###################################################################### 00352 // Include the explicit instantiations 00353 // ###################################################################### 00354 #include "inst/Image/LowPassLpt.I" 00355 00356 template 00357 Image<promote_trait<double, float>::TP> 00358 lowPassLpt(const Image<double>& src, const uint taps, 00359 BorderPolicy policy); 00360 00361 template 00362 Image<promote_trait<double, float>::TP> 00363 lowPassLpt3(const Image<double>& src, BorderPolicy policy); 00364 00365 template 00366 Image<promote_trait<double, float>::TP> 00367 lowPassLpt3r(const Image<double>& src); 00368 00369 template 00370 Image<promote_trait<double, float>::TP> 00371 lowPassLpt3w(const Image<double>& src); 00372 00373 template 00374 Image<promote_trait<double, float>::TP> 00375 lowPassLpt5(const Image<double>& src, BorderPolicy policy); 00376 00377 template 00378 Image<promote_trait<double, float>::TP> 00379 lowPassLpt5r(const Image<double>& src); 00380 00381 template 00382 Image<promote_trait<double, float>::TP> 00383 lowPassLpt5w(const Image<double>& src); 00384 00385 // ###################################################################### 00386 /* So things look consistent in everyone's emacs... */ 00387 /* Local Variables: */ 00388 /* mode: c++ */ 00389 /* indent-tabs-mode: nil */ 00390 /* End: */ 00391 00392 #endif // IMAGE_LOWPASSLPT_C_DEFINED