00001 /*!@file Image/LowPass.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: Rob Peters <rjpeters at usc dot edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/LowPass.C $ 00035 // $Id: LowPass.C 12962 2010-03-06 02:13:53Z irock $ 00036 // 00037 00038 #ifndef IMAGE_LOWPASS_C_DEFINED 00039 #define IMAGE_LOWPASS_C_DEFINED 00040 00041 #include "Image/LowPass.H" 00042 00043 #include "Image/Convolutions.H" 00044 #include "Image/Image.H" 00045 #include "Image/Kernels.H" 00046 #include "Image/Pixels.H" 00047 #include "rutz/trace.h" 00048 00049 namespace 00050 { 00051 // helper function for median3x()/median3y()/median3() 00052 template <class T> 00053 T median3scalar(T a, T b, T c) 00054 { 00055 if (b < a) { T t = b; b = a; a = t; } 00056 if (c < b) { T t = c; c = b; b = t; } 00057 if (b < a) { T t = b; b = a; a = t; } 00058 00059 return b; 00060 } 00061 00062 // helper function for median3x()/median3y()/median3() 00063 template <class T> 00064 PixRGB<T> median3scalar(PixRGB<T> a, PixRGB<T> b, PixRGB<T> c) 00065 { 00066 return PixRGB<T>(median3scalar(a.p[0], b.p[0], c.p[0]), 00067 median3scalar(a.p[1], b.p[1], c.p[1]), 00068 median3scalar(a.p[2], b.p[2], c.p[2])); 00069 } 00070 00071 Image<PixRGB<float> > lowPass3x_rgb(const Image<PixRGB<float> >& src) 00072 { 00073 const int w = src.getWidth(), h = src.getHeight(); 00074 if (w < 2) return src; // nothing to smooth 00075 Image<PixRGB<float> > result(w, h, NO_INIT); 00076 Image<PixRGB<float> >::const_iterator sptr = src.begin(); 00077 Image<PixRGB<float> >::iterator dptr = result.beginw(); 00078 00079 // *** unfolded version (all particular cases treated) for max speed. 00080 // do not use access overload since can access the C array directly. 00081 // the bet is: float computations are faster than int (true for most 00082 // float copros), and int2float converts fast->do not have to divide 00083 // by the coeff sum since we directly use float coeffs. 00084 // notations: in () is the position of dest ptr, and ^ is src ptr 00085 // ########## horizontal pass 00086 for (int j = 0; j < h; j ++) 00087 { 00088 // leftmost point [ (2^) 1 ] / 3 00089 dptr->setRed(sptr[0].red() * (2.0F / 3.0F) 00090 + sptr[1].red() * (1.0F / 3.0F)); 00091 dptr->setGreen(sptr[0].green() * (2.0F / 3.0F) 00092 + sptr[1].green() * (1.0F / 3.0F)); 00093 dptr->setBlue(sptr[0].blue() * (2.0F / 3.0F) 00094 + sptr[1].blue() * (1.0F / 3.0F)); 00095 ++dptr; 00096 00097 // rest of the line except last point [ 1^ (2) 1 ] / 4 00098 for (int i = 0; i < w - 2; i ++) 00099 { 00100 dptr->setRed((sptr[0].red() + sptr[2].red()) 00101 * 0.25F + sptr[1].red() * 0.5F); 00102 dptr->setGreen((sptr[0].green() + sptr[2].green()) 00103 * 0.25F + sptr[1].green() * 0.5F); 00104 dptr->setBlue((sptr[0].blue() + sptr[2].blue()) 00105 * 0.25F + sptr[1].blue() * 0.5F); 00106 ++dptr; 00107 ++sptr; 00108 } 00109 00110 // last point [ 1^ (2) ] / 3 00111 dptr->setRed(sptr[0].red() * (1.0F / 3.0f) 00112 + sptr[1].red() * (2.0F / 3.0F)); 00113 dptr->setGreen(sptr[0].green() * (1.0F / 3.0f) 00114 + sptr[1].green() * (2.0F / 3.0F)); 00115 dptr->setBlue(sptr[0].blue() * (1.0F / 3.0f) 00116 + sptr[1].blue() * (2.0F / 3.0F)); 00117 ++dptr; 00118 sptr += 2; // sptr back to same position as dptr 00119 } 00120 return result; 00121 } 00122 00123 Image<PixRGB<float> > lowPass3y_rgb(const Image<PixRGB<float> >& src) 00124 { 00125 const int w = src.getWidth(), h = src.getHeight(); 00126 if (h < 2) return src; // nothing to smooth 00127 Image<PixRGB<float> > result(w, h, NO_INIT); 00128 Image<PixRGB<float> >::const_iterator sptr = src.begin(); 00129 Image<PixRGB<float> >::iterator dptr = result.beginw(); 00130 const int w2 = w * 2; // speedup 00131 00132 // ########## vertical pass (even though we scan horiz for speedup) 00133 // topmost points ( [ (2^) 1 ] / 3 )^T 00134 for (int i = 0; i < w; i ++) 00135 { 00136 //*dptr = sptr[0] * (2.0F / 3.0F) + sptr[w] * (1.0F / 3.0F); 00137 dptr->setRed(sptr[0].red() * (2.0F / 3.0F) 00138 + sptr[w].red() * (1.0F / 3.0F)); 00139 dptr->setGreen(sptr[0].green() * (2.0F / 3.0F) 00140 + sptr[w].green() * (1.0F / 3.0F)); 00141 dptr->setBlue(sptr[0].blue() * (2.0F / 3.0F) 00142 + sptr[w].blue() * (1.0F / 3.0F)); 00143 ++dptr; 00144 ++sptr; 00145 } 00146 sptr -= w; // go back to top-left 00147 00148 // rest of the column except last point ( [ 1^ (2) 1 ] / 4.0 )^T 00149 for (int j = 0; j < h - 2; j ++) 00150 for (int i = 0; i < w; i ++) 00151 { 00152 //*dptr = (sptr[0] + sptr[w2]) * 0.25F + sptr[w] * 0.5F; 00153 dptr->setRed((sptr[0].red() + sptr[w2].red()) 00154 * 0.25F + sptr[w].red() * 0.5F); 00155 dptr->setGreen((sptr[0].green() + sptr[w2].green()) 00156 * 0.25F + sptr[w].green() * 0.5F); 00157 dptr->setBlue((sptr[0].blue() + sptr[w2].blue()) 00158 * 0.25F + sptr[w].blue() * 0.5F); 00159 ++dptr; 00160 ++sptr; 00161 } 00162 00163 // last points ( [ 1^ (2) ] / 3 )^T 00164 for (int i = 0; i < w; i ++) 00165 { 00166 //*dptr = sptr[0] * (1.0F / 3.0F) + sptr[w] * (2.0F / 3.0F); 00167 dptr->setRed(sptr[0].red() * (1.0F / 3.0F) + sptr[w].red() 00168 * (2.0F / 3.0F)); 00169 dptr->setGreen(sptr[0].green() * (1.0F / 3.0F) + sptr[w].green() 00170 * (2.0F / 3.0F)); 00171 dptr->setBlue(sptr[0].blue() * (1.0F / 3.0F) + sptr[w].blue() 00172 * (2.0F / 3.0F)); 00173 ++dptr; 00174 ++sptr; 00175 } 00176 00177 // finished. here, sptr is one line before the end of array. 00178 return result; 00179 } 00180 } 00181 00182 // ###################################################################### 00183 template <> 00184 Image<promote_trait<PixRGB<float>, float>::TP> 00185 lowPass3x(const Image<PixRGB<float> >& src) 00186 { 00187 GVX_TRACE(__PRETTY_FUNCTION__); 00188 return lowPass3x_rgb(src); 00189 } 00190 00191 // ###################################################################### 00192 template <class T> 00193 Image<typename promote_trait<T, float>::TP> 00194 lowPass3x(const Image<T>& src) 00195 { 00196 GVX_TRACE(__PRETTY_FUNCTION__); 00197 const int w = src.getWidth(), h = src.getHeight(); 00198 // promote the source image to float if necessary, so that we do the 00199 // promotion only once for all, rather than many times as we access 00200 // the pixels of the image; if no promotion is necessary, "source" 00201 // will just point to the original data of "src" through the 00202 // copy-on-write/ref-counting behavior of Image: 00203 typedef typename promote_trait<T, float>::TP TF; 00204 const Image<TF> source = src; 00205 if (w < 2) return source; // nothing to smooth 00206 Image<TF> result(w, h, NO_INIT); 00207 typename Image<TF>::const_iterator sptr = source.begin(); 00208 typename Image<TF>::iterator dptr = result.beginw(); 00209 00210 // *** unfolded version (all particular cases treated) for max speed. 00211 // do not use access overload since can access the C array directly. 00212 // the bet is: float computations are faster than int (true for most 00213 // float copros), and int2float converts fast->do not have to divide 00214 // by the coeff sum since we directly use float coeffs. 00215 // notations: in () is the position of dest ptr, and ^ is src ptr 00216 // ########## horizontal pass 00217 for (int j = 0; j < h; j ++) 00218 { 00219 // leftmost point [ (2^) 1 ] / 3 00220 *dptr++ = sptr[0] * (2.0F / 3.0F) + sptr[1] * (1.0F / 3.0F); 00221 00222 // rest of the line except last point [ 1^ (2) 1 ] / 4 00223 for (int i = 0; i < w - 2; i ++) 00224 { 00225 *dptr++ = (sptr[0] + sptr[2]) * 0.25F + sptr[1] * 0.5F; 00226 sptr++; 00227 } 00228 00229 // last point [ 1^ (2) ] / 3 00230 *dptr++ = sptr[0] * (1.0F / 3.0F) + sptr[1] * (2.0F / 3.0F); 00231 sptr += 2; // sptr back to same position as dptr 00232 } 00233 return result; 00234 } 00235 00236 // ###################################################################### 00237 template <> 00238 Image<promote_trait<PixRGB<float>, float>::TP> 00239 lowPass3y(const Image<PixRGB<float> >& src) 00240 { 00241 GVX_TRACE(__PRETTY_FUNCTION__); 00242 return lowPass3y_rgb(src); 00243 } 00244 00245 // ###################################################################### 00246 template <class T> 00247 Image<typename promote_trait<T, float>::TP> 00248 lowPass3y(const Image<T>& src) 00249 { 00250 GVX_TRACE(__PRETTY_FUNCTION__); 00251 const int w = src.getWidth(), h = src.getHeight(); 00252 // promote the source image to float if necessary, so that we do the 00253 // promotion only once for all, rather than many times as we access 00254 // the pixels of the image; if no promotion is necessary, "source" 00255 // will just point to the original data of "src" through the 00256 // copy-on-write/ref-counting behavior of Image: 00257 typedef typename promote_trait<T, float>::TP TF; 00258 const Image<TF> source = src; 00259 if (h < 2) return source; // nothing to smooth 00260 Image<TF> result(w, h, NO_INIT); 00261 typename Image<TF>::const_iterator sptr = source.begin(); 00262 typename Image<TF>::iterator dptr = result.beginw(); 00263 const int w2 = w * 2; // speedup 00264 00265 // ########## vertical pass (even though we scan horiz for speedup) 00266 // topmost points ( [ (2^) 1 ] / 3 )^T 00267 for (int i = 0; i < w; i ++) 00268 { 00269 *dptr++ = sptr[0] * (2.0F / 3.0F) + sptr[w] * (1.0F / 3.0F); 00270 sptr++; 00271 } 00272 sptr -= w; // go back to top-left 00273 00274 // rest of the column except last point ( [ 1^ (2) 1 ] / 4.0 )^T 00275 for (int j = 0; j < h - 2; j ++) 00276 for (int i = 0; i < w; i ++) 00277 { 00278 *dptr++ = (sptr[0] + sptr[w2]) * 0.25F + sptr[w] * 0.5F; 00279 sptr++; 00280 } 00281 00282 // last points ( [ 1^ (2) ] / 3 )^T 00283 for (int i = 0; i < w; i ++) 00284 { 00285 *dptr++ = sptr[0] * (1.0F / 3.0F) + sptr[w] * (2.0F / 3.0F); 00286 sptr++; 00287 } 00288 00289 // finished. here, sptr is one line before the end of array. 00290 return result; 00291 } 00292 00293 // ###################################################################### 00294 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00295 Image<typename promote_trait<T, float>::TP> 00296 lowPass5x(const Image<T>& src) 00297 { 00298 GVX_TRACE(__PRETTY_FUNCTION__); 00299 const int w = src.getWidth(), h = src.getHeight(); 00300 // promote the source image to float if necessary, so that we do the 00301 // promotion only once for all, rather than many times as we access 00302 // the pixels of the image; if no promotion is necessary, "source" 00303 // will just point to the original data of "src" through the 00304 // copy-on-write/ref-counting behavior of Image: 00305 typedef typename promote_trait<T, float>::TP TF; 00306 const Image<TF> source = src; 00307 if (w < 2) return source; // nothing to smooth 00308 Image<TF> result(w, h, NO_INIT); 00309 typename Image<TF>::const_iterator sptr = source.begin(); 00310 typename Image<TF>::iterator dptr = result.beginw(); 00311 00312 if (w == 2) ////////////////////////////////////////////////// 00313 for (int j = 0; j < h; j ++) 00314 { 00315 // leftmost point [ (6^) 4 ] / 10 00316 *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[1] * (4.0F / 10.0F); 00317 00318 // rightmost point [ 4^ (6) ] / 10 00319 *dptr++ = sptr[0] * (4.0F / 10.0F) + sptr[1] * (6.0F / 10.0F); 00320 00321 sptr += 2; // sptr back to same position as dptr 00322 } 00323 else if (w == 3) ////////////////////////////////////////////////// 00324 for (int j = 0; j < h; j ++) 00325 { 00326 // leftmost point [ (6^) 4 1 ] / 11 00327 *dptr++ = sptr[0] * (6.0F / 11.0F) + 00328 sptr[1] * (4.0F / 11.0F) + 00329 sptr[2] * (1.0F / 11.0F); 00330 00331 // middle point [ 4^ (6) 4 ] / 14 00332 *dptr++ = (sptr[0] + sptr[2]) * (4.0F / 14.0F) + 00333 sptr[1] * (6.0F / 14.0F); 00334 00335 // rightmost point [ 1^ 4 (6) ] / 11 00336 *dptr++ = sptr[0] * (1.0F / 11.0F) + 00337 sptr[1] * (4.0F / 11.0F) + 00338 sptr[2] * (6.0F / 11.0F); 00339 00340 sptr += 3; // sptr back to same position as dptr 00341 } 00342 else ////////////////////////////// general case for width() >= 4 00343 // *** unfolded version (all particular cases treated) for 00344 // max speed. do not use access overloading since can 00345 // access the C array directly. the bet is: float 00346 // computations are faster than int (true for most float 00347 // copros), and int2float convert is fast -> do not have to 00348 // divide by the coeff sum since we directly use float 00349 // coeffs. 00350 // notations: in () is the position of dest ptr, and ^ is src ptr 00351 // ########## horizontal pass 00352 for (int j = 0; j < h; j ++) 00353 { 00354 // leftmost point [ (6^) 4 1 ] / 11 00355 *dptr++ = sptr[0] * (6.0F / 11.0F) + 00356 sptr[1] * (4.0F / 11.0F) + 00357 sptr[2] * (1.0F / 11.0F); 00358 00359 // second point [ 4^ (6) 4 1 ] / 15 00360 *dptr++ = (sptr[0] + sptr[2]) * (4.0F / 15.0F) + 00361 sptr[1] * (6.0F / 15.0F) + 00362 sptr[3] * (1.0F / 15.0F); 00363 00364 // rest of the line except last 2 points [ 1^ 4 (6) 4 1 ] / 16.0 00365 for (int i = 0; i < w - 4; i ++) 00366 { 00367 *dptr++ = (sptr[0] + sptr[4]) * (1.0F / 16.0F) + 00368 (sptr[1] + sptr[3]) * (4.0F / 16.0F) + 00369 sptr[2] * (6.0F / 16.0F); 00370 sptr++; 00371 } 00372 00373 // before last point [ 1^ 4 (6) 4 ] / 15 00374 *dptr++ = sptr[0] * (1.0F / 15.0F) + 00375 (sptr[1] + sptr[3]) * (4.0F / 15.0F) + 00376 sptr[2] * (6.0F / 15.0F); 00377 sptr++; 00378 00379 // last point [ 1^ 4 (6) ] / 11 00380 *dptr++ = sptr[0] * (1.0F / 11.0F) + 00381 sptr[1] * (4.0F / 11.0F) + 00382 sptr[2] * (6.0F / 11.0F); 00383 sptr += 3; // sptr back to same position as dptr 00384 } 00385 return result; 00386 } 00387 00388 // ###################################################################### 00389 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00390 Image<typename promote_trait<T, float>::TP> 00391 lowPass5y(const Image<T>& src) 00392 { 00393 GVX_TRACE(__PRETTY_FUNCTION__); 00394 const int w = src.getWidth(), h = src.getHeight(); 00395 // promote the source image to float if necessary, so that we do the 00396 // promotion only once for all, rather than many times as we access 00397 // the pixels of the image; if no promotion is necessary, "source" 00398 // will just point to the original data of "src" through the 00399 // copy-on-write/ref-counting behavior of Image: 00400 typedef typename promote_trait<T, float>::TP TF; 00401 const Image<TF> source = src; 00402 if (h < 2) return source; // nothing to smooth 00403 Image<TF> result(w, h, NO_INIT); 00404 typename Image<TF>::const_iterator sptr = source.begin(); 00405 typename Image<TF>::iterator dptr = result.beginw(); 00406 00407 // ########## vertical pass (even though we scan horiz for speedup) 00408 const int w2 = w * 2, w3 = w * 3, w4 = w * 4; // speedup 00409 00410 if (h == 2) ////////////////////////////////////////////////// 00411 { 00412 // topmost points ( [ (6^) 4 ] / 10 )^T 00413 for (int i = 0; i < w; i ++) 00414 { 00415 *dptr++ = sptr[0] * (6.0F / 10.0F) + 00416 sptr[w] * (4.0F / 10.0F); 00417 sptr++; 00418 } 00419 sptr -= w; // go back to top-left 00420 00421 // bottommost points ( [ 4^ (6) ] / 10 )^T 00422 for (int i = 0; i < w; i ++) 00423 { 00424 *dptr++ = sptr[0] * (4.0F / 10.0F) + 00425 sptr[w] * (6.0F / 10.0F); 00426 sptr++; 00427 } 00428 } 00429 else if (h == 3) ////////////////////////////////////////////////// 00430 { 00431 // topmost points ( [ (6^) 4 1 ] / 11 )^T 00432 for (int i = 0; i < w; i ++) 00433 { 00434 *dptr++ = sptr[ 0] * (6.0F / 11.0F) + 00435 sptr[ w] * (4.0F / 11.0F) + 00436 sptr[w2] * (1.0F / 11.0F); 00437 sptr++; 00438 } 00439 sptr -= w; // go back to top-left 00440 00441 // middle points ( [ 4^ (6) 4 ] / 14 )^T 00442 for (int i = 0; i < w; i ++) 00443 { 00444 *dptr++ = (sptr[ 0] + sptr[w2]) * (4.0F / 14.0F) + 00445 sptr[ w] * (6.0F / 14.0F); 00446 sptr++; 00447 } 00448 sptr -= w; // go back to top-left 00449 00450 // bottommost points ( [ 1^ 4 (6) ] / 11 )^T 00451 for (int i = 0; i < w; i ++) 00452 { 00453 *dptr++ = sptr[ 0] * (1.0F / 11.0F) + 00454 sptr[ w] * (4.0F / 11.0F) + 00455 sptr[w2] * (6.0F / 11.0F); 00456 sptr++; 00457 } 00458 } 00459 else ///////////////////////////////// general case for height >= 4 00460 { 00461 // topmost points ( [ (6^) 4 1 ] / 11 )^T 00462 for (int i = 0; i < w; i ++) 00463 { 00464 *dptr++ = sptr[ 0] * (6.0F / 11.0F) + 00465 sptr[ w] * (4.0F / 11.0F) + 00466 sptr[w2] * (1.0F / 11.0F); 00467 sptr++; 00468 } 00469 sptr -= w; // go back to top-left 00470 00471 // second topmost points ( [ 4^ (6) 4 1 ] / 15 )^T 00472 for (int i = 0; i < w; i ++) 00473 { 00474 *dptr++ = (sptr[ 0] + sptr[w2]) * (4.0F / 15.0F) + 00475 sptr[ w] * (6.0F / 15.0F) + 00476 sptr[w3] * (1.0F / 15.0F); 00477 sptr++; 00478 } 00479 sptr -= w; // go back to top-left 00480 00481 // rest of the column except last 2 points ( [ 1^ 4 (6) 4 1 ] / 16 )T 00482 for (int j = 0; j < h - 4; j ++) 00483 for (int i = 0; i < w; i ++) 00484 { 00485 *dptr++ = (sptr[ 0] + sptr[w4]) * (1.0F / 16.0F) + 00486 (sptr[ w] + sptr[w3]) * (4.0F / 16.0F) + 00487 sptr[w2] * (6.0F / 16.0F); 00488 sptr++; 00489 } 00490 00491 // before last points ( [ 1^ 4 (6) 4 ] / 15 )T 00492 for (int i = 0; i < w; i ++) 00493 { 00494 *dptr++ = sptr[ 0] * (1.0F / 15.0F) + 00495 (sptr[ w] + sptr[w3]) * (4.0F / 15.0F) + 00496 sptr[w2] * (6.0F / 15.0F); 00497 sptr++; 00498 } 00499 00500 // last points ( [ 1^ 4 (6) ] / 11 )T 00501 for (int i = 0; i < w; i ++) 00502 { 00503 *dptr++ = sptr[ 0] * (1.0F / 11.0F) + 00504 sptr[ w] * (4.0F / 11.0F) + 00505 sptr[w2] * (6.0F / 11.0F); 00506 sptr++; 00507 } 00508 // finished. here, sptr is two lines before the end of array. 00509 } 00510 return result; 00511 } 00512 00513 // ###################################################################### 00514 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00515 Image<typename promote_trait<T, float>::TP> 00516 lowPass5xDecX(const Image<T>& src, const int factor) 00517 { 00518 GVX_TRACE(__PRETTY_FUNCTION__); 00519 ASSERT(factor > 0); 00520 00521 // if factor == 1 then we don't decimate: 00522 if (factor == 1) return lowPass5x(src); 00523 00524 // now factor is guaranteed to be >= 2 00525 const int w = src.getWidth(), h = src.getHeight(); 00526 int w2 = w / factor; 00527 if (w2 == 0) w2 = 1; // do not go smaller than 1 pixel 00528 00529 // promote the source image to float if necessary, so that we do the 00530 // promotion only once for all, rather than many times as we access 00531 // the pixels of the image; if no promotion is necessary, "source" 00532 // will just point to the original data of "src" through the 00533 // copy-on-write/ref-counting behavior of Image: 00534 typedef typename promote_trait<T, float>::TP TF; 00535 const Image<TF> source = src; 00536 if (w < 2) return source; // nothing to smooth 00537 00538 Image<TF> result(w2, h, NO_INIT); 00539 typename Image<TF>::const_iterator sptr = source.begin(); 00540 typename Image<TF>::iterator dptr = result.beginw(); 00541 00542 if (w == 2) ////////////////////////////////////////////////// 00543 for (int j = 0; j < h; j ++) 00544 { 00545 // leftmost point [ (6^) 4 ] / 10 00546 *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[1] * (4.0F / 10.0F); 00547 00548 sptr += 2; // sptr back to same position as dptr 00549 } 00550 else if (w == 3) ////////////////////////////////////////////////// 00551 for (int j = 0; j < h; j ++) 00552 { 00553 // need the left most point in any case 00554 // leftmost point [ (6^) 4 1 ] / 11 00555 *dptr++ = sptr[0] * (6.0F / 11.0F) + 00556 sptr[1] * (4.0F / 11.0F) + 00557 sptr[2] * (1.0F / 11.0F); 00558 00559 // since factor >= 2 we don't need any other point. 00560 00561 sptr += 3; // sptr back to same position as dptr 00562 } 00563 else ////////////////////////////// general case for width() >= 4 00564 // *** unfolded version (all particular cases treated) for 00565 // max speed. do not use access overloading since can 00566 // access the C array directly. the bet is: float 00567 // computations are faster than int (true for most float 00568 // copros), and int2float convert is fast -> do not have to 00569 // divide by the coeff sum since we directly use float 00570 // coeffs. 00571 // notations: in () is the position of dest ptr, and ^ is src ptr 00572 // ########## horizontal pass 00573 for (int j = 0; j < h; j ++) 00574 { 00575 int i1 = 0, i2 = 0; 00576 typename Image<TF>::const_iterator sptr2 = sptr; 00577 00578 00579 // leftmost point [ (6^) 4 1 ] / 11 00580 *dptr++ = sptr2[0] * (6.0F / 11.0F) + 00581 sptr2[1] * (4.0F / 11.0F) + 00582 sptr2[2] * (1.0F / 11.0F); 00583 ++i2; 00584 i1 += factor; 00585 00586 // skip second point since factor >= 2: 00587 sptr2 += (factor-2); 00588 00589 // rest of the line except last 2 points [ 1^ 4 (6) 4 1 ] / 16.0 00590 while ((i1 < (w-2)) && (i2 < w2)) 00591 { 00592 *dptr++ = (sptr2[0] + sptr2[4]) * (1.0F / 16.0F) + 00593 (sptr2[1] + sptr2[3]) * (4.0F / 16.0F) + 00594 sptr2[2] * (6.0F / 16.0F); 00595 i1 += factor; sptr2 += factor; 00596 ++i2; 00597 } 00598 00599 // need special case for second to last point? 00600 if ((i2 < w2) && (i1 == (w-2))) 00601 { 00602 sptr2 = sptr + w - 4; 00603 // before last point [ 1^ 4 (6) 4 ] / 15 00604 *dptr++ = sptr2[0] * (1.0F / 15.0F) + 00605 (sptr2[1] + sptr2[3]) * (4.0F / 15.0F) + 00606 sptr2[2] * (6.0F / 15.0F); 00607 i1 += factor; 00608 ++i2; 00609 } 00610 00611 // need special case for last point? 00612 if ((i2 < w2) && (i1 == (w-1))) 00613 { 00614 sptr2 = sptr + w - 3; 00615 // last point [ 1^ 4 (6) ] / 11 00616 *dptr++ = sptr2[0] * (1.0F / 11.0F) + 00617 sptr2[1] * (4.0F / 11.0F) + 00618 sptr2[2] * (6.0F / 11.0F); 00619 ++i2; 00620 } 00621 sptr += w; 00622 } 00623 return result; 00624 } 00625 00626 // ###################################################################### 00627 template <class T> // Anderson's separable kernel: 1/16 * [1 4 6 4 1] 00628 Image<typename promote_trait<T, float>::TP> 00629 lowPass5yDecY(const Image<T>& src, const int factor) 00630 { 00631 GVX_TRACE(__PRETTY_FUNCTION__); 00632 ASSERT(factor > 0); 00633 00634 // if factor == 1 then we don't decimate: 00635 if (factor == 1) return lowPass5y(src); 00636 00637 // now factor is guaranteed to be >= 2 00638 const int w = src.getWidth(), h = src.getHeight(); 00639 int h2 = h / factor; 00640 if (h2 == 0) h2 = 1; // do not go smaller than 1 pixel 00641 00642 // promote the source image to float if necessary, so that we do the 00643 // promotion only once for all, rather than many times as we access 00644 // the pixels of the image; if no promotion is necessary, "source" 00645 // will just point to the original data of "src" through the 00646 // copy-on-write/ref-counting behavior of Image: 00647 typedef typename promote_trait<T, float>::TP TF; 00648 const Image<TF> source = src; 00649 if (h < 2) return source; // nothing to smooth 00650 00651 Image<TF> result(w, h2, NO_INIT); 00652 typename Image<TF>::const_iterator sptr = source.begin(); 00653 typename Image<TF>::iterator dptr = result.beginw(); 00654 00655 // ########## vertical pass (even though we scan horiz for speedup) 00656 const int w2 = w * 2, w3 = w * 3, w4 = w * 4; // speedup 00657 00658 if (h == 2) ////////////////////////////////////////////////// 00659 { 00660 // topmost points ( [ (6^) 4 ] / 10 )^T 00661 for (int i = 0; i < w; i ++) 00662 { 00663 *dptr++ = sptr[0] * (6.0F / 10.0F) + sptr[w] * (4.0F / 10.0F); 00664 sptr++; 00665 } 00666 sptr -= w; // go back to top-left 00667 } 00668 else if (h == 3) ////////////////////////////////////////////////// 00669 { 00670 // topmost points ( [ (6^) 4 1 ] / 11 )^T 00671 for (int i = 0; i < w; i ++) 00672 { 00673 *dptr++ = sptr[ 0] * (6.0F / 11.0F) + 00674 sptr[ w] * (4.0F / 11.0F) + 00675 sptr[w2] * (1.0F / 11.0F); 00676 sptr++; 00677 } 00678 sptr -= w; // go back to top-left 00679 00680 // since factor >= 2 we don't need any other point. 00681 } 00682 else ///////////////////////////////// general case for height >= 4 00683 { 00684 int i1 = 0, i2 = 0; 00685 const int skip = (factor - 1) * w; 00686 00687 // topmost points ( [ (6^) 4 1 ] / 11 )^T 00688 for (int i = 0; i < w; i ++) 00689 { 00690 *dptr++ = sptr[ 0] * (6.0F / 11.0F) + 00691 sptr[ w] * (4.0F / 11.0F) + 00692 sptr[w2] * (1.0F / 11.0F); 00693 sptr++; 00694 } 00695 sptr -= w; // go back to top-left 00696 ++i2; 00697 i1 += factor; 00698 00699 // second point skipped since factor >= 2 00700 sptr += (skip - w); 00701 00702 // rest of the column except last 2 points ( [ 1^ 4 (6) 4 1 ] / 16 )T 00703 while((i1 < (h-2)) && (i2 < h2)) 00704 { 00705 for (int i = 0; i < w; i ++) 00706 { 00707 *dptr++ = (sptr[ 0] + sptr[w4]) * (1.0F / 16.0F) + 00708 (sptr[ w] + sptr[w3]) * (4.0F / 16.0F) + 00709 sptr[w2] * (6.0F / 16.0F); 00710 sptr++; 00711 } 00712 sptr += skip; 00713 i1 += factor; 00714 ++ i2; 00715 } 00716 00717 // need special case for second to last point? 00718 if ((i2 < h2) && (i1 == (h-2))) 00719 { 00720 sptr = source.end() - w4; 00721 // before last points ( [ 1^ 4 (6) 4 ] / 15 )T 00722 for (int i = 0; i < w; i ++) 00723 { 00724 *dptr++ = sptr[ 0] * (1.0F / 15.0F) + 00725 (sptr[ w] + sptr[w3]) * (4.0F / 15.0F) + 00726 sptr[w2] * (6.0F / 15.0F); 00727 sptr++; 00728 } 00729 i1 += factor; 00730 ++i2; 00731 } 00732 00733 // need special case for last point? 00734 if ((i2 < h2) && (i1 == (h-1))) 00735 { 00736 sptr = source.end() - w3; 00737 // last points ( [ 1^ 4 (6) ] / 11 )T 00738 for (int i = 0; i < w; i ++) 00739 { 00740 *dptr++ = sptr[ 0] * (1.0F / 11.0F) + 00741 sptr[ w] * (4.0F / 11.0F) + 00742 sptr[w2] * (6.0F / 11.0F); 00743 sptr++; 00744 } 00745 } 00746 } 00747 return result; 00748 } 00749 00750 // ###################################################################### 00751 template <class T> 00752 Image<typename promote_trait<T, float>::TP> 00753 lowPass9x(const Image<T>& src) 00754 { 00755 GVX_TRACE(__PRETTY_FUNCTION__); 00756 const int w = src.getWidth(), h = src.getHeight(); 00757 // promote the source image to float if necessary, so that we do the 00758 // promotion only once for all, rather than many times as we access 00759 // the pixels of the image; if no promotion is necessary, "source" 00760 // will just point to the original data of "src" through the 00761 // copy-on-write/ref-counting behavior of Image: 00762 typedef typename promote_trait<T, float>::TP TF; 00763 const Image<TF> source = src; 00764 if (w < 2) return source; // nothing to smooth 00765 Image<TF> result(w, h, NO_INIT); 00766 typename Image<TF>::const_iterator sptr = source.begin(); 00767 typename Image<TF>::iterator dptr = result.beginw(); 00768 00769 if (w < 9) // use inefficient implementation for small images 00770 { 00771 float kernel[9] = { 1.0F / 256.0F, 8.0F / 256.0F, 28.0F / 256.0F, 00772 56.0F / 256.0F, 70.0F / 256.0F, 56.0F / 256.0F, 00773 28.0F / 256.0F, 8.0F / 256.0F, 1.0F / 256.0F }; 00774 return sepFilter(src, kernel, NULL, 9, 0, 00775 CONV_BOUNDARY_CLEAN); 00776 } 00777 00778 // boundary conditions: truncated filter 00779 for (int j = 0; j < h; j ++) 00780 { 00781 // leftmost points 00782 *dptr++ = sptr[0] * (70.0F / 163.0F) + 00783 sptr[1] * (56.0F / 163.0F) + 00784 sptr[2] * (28.0F / 163.0F) + 00785 sptr[3] * ( 8.0F / 163.0F) + 00786 sptr[4] * ( 1.0F / 163.0F); 00787 *dptr++ = (sptr[0] + sptr[2]) * (56.0F / 219.0F) + 00788 sptr[1] * (70.0F / 219.0F) + 00789 sptr[3] * (28.0F / 219.0F) + 00790 sptr[4] * ( 8.0F / 219.0F) + 00791 sptr[5] * ( 1.0F / 219.0F); 00792 *dptr++ = (sptr[0] + sptr[4]) * (28.0F / 247.0F) + 00793 (sptr[1] + sptr[3]) * (56.0F / 247.0F) + 00794 sptr[2] * (70.0F / 247.0F) + 00795 sptr[5] * ( 8.0F / 247.0F) + 00796 sptr[6] * ( 1.0F / 247.0F); 00797 *dptr++ = (sptr[0] + sptr[6]) * ( 8.0F / 255.0F) + 00798 (sptr[1] + sptr[5]) * (28.0F / 255.0F) + 00799 (sptr[2] + sptr[4]) * (56.0F / 255.0F) + 00800 sptr[3] * (70.0F / 255.0F) + 00801 sptr[7] * ( 1.0F / 255.0F); 00802 00803 // far from the borders 00804 for (int i = 0; i < w - 8; i ++) 00805 { 00806 *dptr++ = (sptr[0] + sptr[8]) * ( 1.0F / 256.0F) + 00807 (sptr[1] + sptr[7]) * ( 8.0F / 256.0F) + 00808 (sptr[2] + sptr[6]) * (28.0F / 256.0F) + 00809 (sptr[3] + sptr[5]) * (56.0F / 256.0F) + 00810 sptr[4] * (70.0F / 256.0F); 00811 sptr ++; 00812 } 00813 00814 // rightmost points 00815 *dptr++ = sptr[0] * ( 1.0F / 255.0F) + 00816 (sptr[1] + sptr[7]) * ( 8.0F / 255.0F) + 00817 (sptr[2] + sptr[6]) * (28.0F / 255.0F) + 00818 (sptr[3] + sptr[5]) * (56.0F / 255.0F) + 00819 sptr[4] * (70.0F / 255.0F); 00820 sptr ++; 00821 *dptr++ = sptr[0] * ( 1.0F / 247.0F) + 00822 sptr[1] * ( 8.0F / 247.0F) + 00823 (sptr[2] + sptr[6]) * (28.0F / 247.0F) + 00824 (sptr[3] + sptr[5]) * (56.0F / 247.0F) + 00825 sptr[4] * (70.0F / 247.0F); 00826 sptr ++; 00827 *dptr++ = sptr[0] * ( 1.0F / 219.0F) + 00828 sptr[1] * ( 8.0F / 219.0F) + 00829 sptr[2] * (28.0F / 219.0F) + 00830 (sptr[3] + sptr[5]) * (56.0F / 219.0F) + 00831 sptr[4] * (70.0F / 219.0F); 00832 sptr ++; 00833 *dptr++ = sptr[0] * ( 1.0F / 163.0F) + 00834 sptr[1] * ( 8.0F / 163.0F) + 00835 sptr[2] * (28.0F / 163.0F) + 00836 sptr[3] * (56.0F / 163.0F) + 00837 sptr[4] * (70.0F / 163.0F); 00838 sptr += 5; // sptr back to same as dptr (start of next line) 00839 } 00840 return result; 00841 } 00842 00843 // ###################################################################### 00844 template <class T> 00845 Image<typename promote_trait<T, float>::TP> 00846 lowPass9y(const Image<T>& src) 00847 { 00848 GVX_TRACE(__PRETTY_FUNCTION__); 00849 const int w = src.getWidth(), h = src.getHeight(); 00850 // promote the source image to float if necessary, so that we do the 00851 // promotion only once for all, rather than many times as we access 00852 // the pixels of the image; if no promotion is necessary, "source" 00853 // will just point to the original data of "src" through the 00854 // copy-on-write/ref-counting behavior of Image: 00855 typedef typename promote_trait<T, float>::TP TF; 00856 const Image<TF> source = src; 00857 if (h < 2) return source; // nothing to smooth 00858 Image<TF> result(w, h, NO_INIT); 00859 typename Image<TF>::const_iterator sptr = source.begin(); 00860 typename Image<TF>::iterator dptr = result.beginw(); 00861 00862 if (h < 9) // use inefficient implementation for small images 00863 { 00864 float kernel[9] = { 1.0F / 256.0F, 8.0F / 256.0F, 28.0F / 256.0F, 00865 56.0F / 256.0F, 70.0F / 256.0F, 56.0F / 256.0F, 00866 28.0F / 256.0F, 8.0F / 256.0F, 1.0F / 256.0F }; 00867 return sepFilter(src, NULL, kernel, 0, 9, 00868 CONV_BOUNDARY_CLEAN); 00869 } 00870 00871 // *** vertical pass *** 00872 const int w2 = w + w, w3 = w2 + w, w4 = w3 + w, w5 = w4 + w, w6 = w5 + w, 00873 w7 = w6 + w, w8 = w7 + w; // index computation speedup 00874 for (int i = 0; i < w; i ++) 00875 { 00876 *dptr++ = sptr[ 0] * (70.0F / 163.0F) + 00877 sptr[ w] * (56.0F / 163.0F) + 00878 sptr[w2] * (28.0F / 163.0F) + 00879 sptr[w3] * ( 8.0F / 163.0F) + 00880 sptr[w4] * ( 1.0F / 163.0F); 00881 sptr ++; 00882 } 00883 sptr -= w; // back to top-left 00884 for (int i = 0; i < w; i ++) 00885 { 00886 *dptr++ = (sptr[ 0] + sptr[w2]) * (56.0F / 219.0F) + 00887 sptr[ w] * (70.0F / 219.0F) + 00888 sptr[w3] * (28.0F / 219.0F) + 00889 sptr[w4] * ( 8.0F / 219.0F) + 00890 sptr[w5] * ( 1.0F / 219.0F); 00891 sptr ++; 00892 } 00893 sptr -= w; // back to top-left 00894 for (int i = 0; i < w; i ++) 00895 { 00896 *dptr++ = (sptr[ 0] + sptr[w4]) * (28.0F / 247.0F) + 00897 (sptr[ w] + sptr[w3]) * (56.0F / 247.0F) + 00898 sptr[w2] * (70.0F / 247.0F) + 00899 sptr[w5] * ( 8.0F / 247.0F) + 00900 sptr[w6] * ( 1.0F / 247.0F); 00901 sptr ++; 00902 } 00903 sptr -= w; // back to top-left 00904 for (int i = 0; i < w; i ++) 00905 { 00906 *dptr++ = (sptr[ 0] + sptr[w6]) * ( 8.0F / 255.0F) + 00907 (sptr[ w] + sptr[w5]) * (28.0F / 255.0F) + 00908 (sptr[w2] + sptr[w4]) * (56.0F / 255.0F) + 00909 sptr[w3] * (70.0F / 255.0F) + 00910 sptr[w7] * ( 1.0F / 255.0F); 00911 sptr ++; 00912 } 00913 sptr -= w; // back to top-left 00914 for (int j = 0; j < h - 8; j ++) 00915 for (int i = 0; i < w; i ++) 00916 { 00917 *dptr++ = (sptr[ 0] + sptr[w8]) * ( 1.0F / 256.0F) + 00918 (sptr[ w] + sptr[w7]) * ( 8.0F / 256.0F) + 00919 (sptr[w2] + sptr[w6]) * (28.0F / 256.0F) + 00920 (sptr[w3] + sptr[w5]) * (56.0F / 256.0F) + 00921 sptr[w4] * (70.0F / 256.0F); 00922 sptr ++; 00923 } 00924 for (int i = 0; i < w; i ++) 00925 { 00926 *dptr++ = sptr[ 0] * ( 1.0F / 255.0F) + 00927 (sptr[ w] + sptr[w7]) * ( 8.0F / 255.0F) + 00928 (sptr[w2] + sptr[w6]) * (28.0F / 255.0F) + 00929 (sptr[w3] + sptr[w5]) * (56.0F / 255.0F) + 00930 sptr[w4] * (70.0F / 255.0F); 00931 sptr ++; 00932 } 00933 for (int i = 0; i < w; i ++) 00934 { 00935 *dptr++ = sptr[ 0] * ( 1.0F / 247.0F) + 00936 sptr[ w] * ( 8.0F / 247.0F) + 00937 (sptr[w2] + sptr[w6]) * (28.0F / 247.0F) + 00938 (sptr[w3] + sptr[w5]) * (56.0F / 247.0F) + 00939 sptr[w4] * (70.0F / 247.0F); 00940 sptr ++; 00941 } 00942 for (int i = 0; i < w; i ++) 00943 { 00944 *dptr++ = sptr[ 0] * ( 1.0F / 219.0F) + 00945 sptr[ w] * ( 8.0F / 219.0F) + 00946 sptr[w2] * (28.0F / 219.0F) + 00947 (sptr[w3] + sptr[w5]) * (56.0F / 219.0F) + 00948 sptr[w4] * (70.0F / 219.0F); 00949 sptr ++; 00950 } 00951 for (int i = 0; i < w; i ++) 00952 { 00953 *dptr++ = sptr[ 0] * ( 1.0F / 163.0F) + 00954 sptr[ w] * ( 8.0F / 163.0F) + 00955 sptr[w2] * (28.0F / 163.0F) + 00956 sptr[w3] * (56.0F / 163.0F) + 00957 sptr[w4] * (70.0F / 163.0F); 00958 sptr ++; 00959 } 00960 return result; 00961 } 00962 00963 // ###################################################################### 00964 template <class T> 00965 Image<typename promote_trait<T, float>::TP> 00966 lowPass3(const Image<T>& src, const bool go_x, const bool go_y) 00967 { 00968 Image<typename promote_trait<T, float>::TP> result = src; 00969 if (go_x) result = lowPass3x(result); 00970 if (go_y) result = lowPass3y(result); 00971 return result; 00972 } 00973 00974 // ###################################################################### 00975 template <class T> 00976 Image<typename promote_trait<T, float>::TP> 00977 lowPass5(const Image<T>& src, const bool go_x, const bool go_y) 00978 { 00979 Image<typename promote_trait<T, float>::TP> result = src; 00980 if (go_x) result = lowPass5x(result); 00981 if (go_y) result = lowPass5y(result); 00982 return result; 00983 } 00984 00985 // ###################################################################### 00986 template <class T> 00987 Image<typename promote_trait<T, float>::TP> 00988 lowPass9(const Image<T>& src, const bool go_x, const bool go_y) 00989 { 00990 Image<typename promote_trait<T, float>::TP> result = src; 00991 if (go_x) result = lowPass9x(result); 00992 if (go_y) result = lowPass9y(result); 00993 return result; 00994 } 00995 00996 // ###################################################################### 00997 template <class T> 00998 Image<typename promote_trait<T, float>::TP> 00999 lowPass(const int N, const Image<T>& src, 01000 const bool go_x = true, const bool go_y = true) 01001 { 01002 Image<typename promote_trait<T, float>::TP> result = src; 01003 if (go_x) result = lowPassX(N, result); 01004 if (go_y) result = lowPassY(N, result); 01005 return result; 01006 } 01007 01008 // ###################################################################### 01009 template <class T> 01010 Image<typename promote_trait<T, float>::TP> 01011 lowPassX(const int N, const Image<T>& src) 01012 { 01013 GVX_TRACE(__PRETTY_FUNCTION__); 01014 switch (N) 01015 { 01016 case 3: return lowPass3x(src); 01017 case 5: return lowPass5x(src); 01018 case 9: return lowPass9x(src); 01019 default: break; 01020 } 01021 01022 const Image<float> kern = binomialKernel(N); 01023 ASSERT(kern.getWidth() == N); 01024 ASSERT(kern.getHeight() == 1); 01025 return sepFilter(src, kern.getArrayPtr(), NULL, N, 0, 01026 CONV_BOUNDARY_CLEAN); 01027 } 01028 01029 // ###################################################################### 01030 template <class T> 01031 Image<typename promote_trait<T, float>::TP> 01032 lowPassY(const int N, const Image<T>& src) 01033 { 01034 GVX_TRACE(__PRETTY_FUNCTION__); 01035 switch (N) 01036 { 01037 case 3: return lowPass3y(src); 01038 case 5: return lowPass5y(src); 01039 case 9: return lowPass9y(src); 01040 default: break; 01041 } 01042 01043 const Image<float> kern = binomialKernel(N); 01044 ASSERT(kern.getWidth() == N); 01045 ASSERT(kern.getHeight() == 1); 01046 return sepFilter(src, NULL, kern.getArrayPtr(), 0, N, 01047 CONV_BOUNDARY_CLEAN); 01048 } 01049 01050 // ###################################################################### 01051 template <class T> 01052 Image<T> median3x(const Image<T>& in) 01053 { 01054 if (in.getWidth() < 3) return in; 01055 01056 const int w = in.getWidth(); 01057 const int h = in.getHeight(); 01058 01059 Image<T> result(in.getDims(), NO_INIT); 01060 01061 typename Image<T>::const_iterator sptr = in.begin(); 01062 typename Image<T>::iterator dptr = result.beginw(); 01063 01064 for (int y = 0; y < h; ++y) 01065 for (int x = 0; x < w; ++x) 01066 { 01067 if (x == 0 || x == w-1) 01068 *dptr = *sptr; 01069 else 01070 *dptr = median3scalar(sptr[-1], sptr[0], sptr[1]); 01071 01072 ++dptr; 01073 ++sptr; 01074 } 01075 01076 return result; 01077 } 01078 01079 // ###################################################################### 01080 template <class T> 01081 Image<T> median3y(const Image<T>& in) 01082 { 01083 if (in.getHeight() < 3) return in; 01084 01085 const int w = in.getWidth(); 01086 const int h = in.getHeight(); 01087 01088 Image<T> result(in.getDims(), NO_INIT); 01089 01090 typename Image<T>::const_iterator sptr = in.begin(); 01091 typename Image<T>::iterator dptr = result.beginw(); 01092 01093 for (int y = 0; y < h; ++y) 01094 { 01095 if (y == 0 || y == h-1) 01096 for (int x = 0; x < w; ++x) 01097 *dptr++ = *sptr++; 01098 else 01099 for (int x = 0; x < w; ++x) 01100 { 01101 *dptr = median3scalar(sptr[-w], sptr[0], sptr[w]); 01102 01103 ++dptr; 01104 ++sptr; 01105 } 01106 } 01107 01108 return result; 01109 } 01110 01111 // ###################################################################### 01112 template <class T> 01113 Image<T> median3(const Image<T>& in, bool go_x, bool go_y) 01114 { 01115 Image<T> result = in; 01116 if (go_x) result = median3x(result); 01117 if (go_y) result = median3y(result); 01118 return result; 01119 } 01120 01121 // ###################################################################### 01122 template <class T> 01123 Image<typename promote_trait<T, float>::TP> 01124 convGauss(const Image<T>& src, const float sigmaX, const float sigmaY, 01125 const float threshperc) 01126 { 01127 GVX_TRACE(__PRETTY_FUNCTION__); 01128 Image<typename promote_trait<T, float>::TP> result = src; 01129 Image <float> kernel; 01130 if (sigmaX > 0.0) 01131 { 01132 kernel = gaussian<float>(0.0F, sigmaX, result.getWidth(),threshperc); 01133 result = sepFilter(result, kernel, Image<float>(), 01134 CONV_BOUNDARY_CLEAN); 01135 } 01136 if (sigmaY > 0.0) 01137 { 01138 kernel = gaussian<float>(0.0F, sigmaY, src.getHeight(), threshperc); 01139 result = sepFilter(result, Image<float>(), kernel, 01140 CONV_BOUNDARY_CLEAN); 01141 } 01142 return result; 01143 } 01144 01145 // Include the explicit instantiations 01146 #include "inst/Image/LowPass.I" 01147 01148 template 01149 Image<promote_trait<double, float>::TP> 01150 lowPass3(const Image<double>& src, const bool, const bool); 01151 01152 template 01153 Image<promote_trait<double, float>::TP> 01154 lowPass5(const Image<double>& src, const bool, const bool); 01155 01156 template 01157 Image<promote_trait<double, float>::TP> 01158 lowPass3x(const Image<double>& src); 01159 01160 template 01161 Image<promote_trait<double, float>::TP> 01162 lowPass3y(const Image<double>& src); 01163 01164 template 01165 Image<promote_trait<double, float>::TP> 01166 lowPass5x(const Image<double>& src); 01167 01168 template 01169 Image<promote_trait<double, float>::TP> 01170 lowPass5y(const Image<double>& src); 01171 01172 // ###################################################################### 01173 /* So things look consistent in everyone's emacs... */ 01174 /* Local Variables: */ 01175 /* mode: c++ */ 01176 /* indent-tabs-mode: nil */ 01177 /* End: */ 01178 01179 #endif // IMAGE_LOWPASS_C_DEFINED