Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

meanNxN_Filter.cpp

Go to the documentation of this file.
00001 /* ---------------------------------------------------------------------------
00002     Phission :
00003         Realtime Vision Processing System
00004 
00005     Copyright (C) 2003-2006 Philip D.S. Thoren (pthoren@cs.uml.edu)
00006     University of Massachusetts at Lowell,
00007     Laboratory for Artificial Intelligence and Robotics
00008 
00009  ---------------------------------------------------------------------------
00010     mean NxN
00011 
00012     * This code is part of IPL, and is released under version 2 of the GPL.
00013     * Copyright (c) 2003 John R. Watson.  See README and COPYING for more
00014     * information.
00015  ---------------------------------------------------------------------------
00016 
00017     This file is part of Phission.
00018 
00019     Phission is free software; you can redistribute it and/or modify
00020     it under the terms of the GNU Lesser General Public License as published by
00021     the Free Software Foundation; either version 2 of the License, or
00022     (at your option) any later version.
00023 
00024     Phission is distributed in the hope that it will be useful,
00025     but WITHOUT ANY WARRANTY; without even the implied warranty of
00026     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00027     GNU Lesser General Public License for more details.
00028 
00029     You should have received a copy of the GNU Lesser General Public License
00030     along with Phission; if not, write to the Free Software
00031     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00032 
00033  ---------------------------------------------------------------------------*/
00034 #ifdef HAVE_CONFIG_H
00035     #include <phissionconfig.h>
00036 #endif
00037 
00038 #include <phStandard.h>
00039 
00040 #include <meanNxN_Filter.h>
00041 
00042 #include <phError.h>
00043 #include <phMemory.h>
00044 #include <phPrint.h>
00045 
00046 /* ---------------------------------------------------------------------- *
00047  * From John R. Watson's IPL, included with Phission:                     *
00048  *          phission/filter/packages/ipl-1.0.0.tar.gz                     *
00049  * ---------------------------------------------------------------------- */
00050 #ifdef __cplusplus
00051 extern "C" {
00052 #endif /* __cplusplus */
00053 
00054 /* ----------------------------------------------------------------------------
00055  * mean.c -- Mean filter
00056  * ----------------------------------------------------------------------------
00057  * John R. Watson (jwatson@cs.uml.edu)
00058  * 91.549 Robotics II, Vision Project 1
00059  * DUE 11/13/03
00060  * ----------------------------------------------------------------------------
00061  * This code is part of IPL, and is released under version 2 of the GPL.
00062  * Copyright (c) 2003 John R. Watson.  See README and COPYING for more
00063  * information.
00064  */
00065 
00066 static void ipl__blur_mean_3x3(uint8_t *src,
00067                    uint8_t *dst,
00068                    const int w,
00069                    const int h);
00070 
00071 static void ipl__blur_mean_5x5(uint8_t *src,
00072                    uint8_t *dst,
00073                    const int w,
00074                    const int h);
00075 
00076 static void ipl__blur_mean_7x7(uint8_t *src,
00077                    uint8_t *dst,
00078                    const int w,
00079                    const int h);
00080 
00081 static void ipl__blur_mean_nxn(uint8_t *src,
00082                    uint8_t *dst,
00083                    const int w,
00084                    const int h,
00085                    const int k);
00086 
00087 /* ----------------------------------------------------------------------------
00088  * ipl_blur_mean -- jacket for the mean blurs
00089  * ----------------------------------------------------------------------------
00090  * ------------------------------------------------------------------------- */
00091 int ipl_blur_mean(uint8_t *src,
00092           uint8_t *dst,
00093           const int w,
00094           const int h,
00095           const int k)
00096 {
00097     phFUNCTION("ipl_blur_mean")
00098     
00099     /* I only really care about the kernel size.  it must be odd.
00100      * if we have an optimized entry point, use it
00101      */
00102     if ((k & 1) == 0)
00103     {
00104         phERR_PRINT("filter kernel size must be odd");
00105         return -1;
00106     }
00107 
00108     if (k < 3)
00109     {
00110         phERR_PRINT("filter kernel size must be > 3");
00111         return -2;
00112     }
00113 
00114     if (k == 3)
00115         ipl__blur_mean_3x3(src, dst, w, h);
00116     else if (k == 5)
00117         ipl__blur_mean_5x5(src, dst, w, h);
00118     else if (k == 7)
00119         ipl__blur_mean_7x7(src, dst, w, h);
00120     else
00121         ipl__blur_mean_nxn(src, dst, w, h, k);
00122 
00123     return 0;
00124 }
00125 
00126 /* ----------------------------------------------------------------------------
00127  * ipl__blur_mean_3x3 -- 3x3 mean blur
00128  * ----------------------------------------------------------------------------
00129  * This is a hard-coded 3x3 kernel mean blur, which is approximately 2.7x
00130  * faster than the generic NxN mean blur below.
00131  * ------------------------------------------------------------------------- */
00132 static void ipl__blur_mean_3x3(uint8_t *src,
00133                    uint8_t *dst,
00134                    const int w,
00135                    const int h)
00136 {
00137     uint8_t *srcp;
00138     int stride;
00139     int r;
00140     int g;
00141     int b;
00142     int x;
00143     int y;
00144 
00145     /* this is our row stride */
00146     stride = w * 3;
00147 
00148     /* 3x3 convolutions have a 1 pixel border around the output image,
00149      * because we can't convolve edge pixels.  thus, we must bump the dst
00150      * ptr 1 pixel down and in before we start writing to it
00151      */
00152     dst += (w + 1) * 3;
00153 
00154     /* a 3x3 convolution requires 9 adjacent pixels.  the two inner loops
00155      * necessary for convolution are unrolled here for optimality
00156      */
00157     for (y=0; y<h-2; y++)
00158     {
00159         for (x=0; x<w-2; x++)
00160         {
00161             /* get a pointer to the current pixel, and then bump
00162              * the src pointer to the next pixel
00163              */
00164             srcp = src;
00165             src += 3;
00166 
00167             /* compute the sum of the pixels in the first row */
00168             r = *srcp + *(srcp + 3) + *(srcp + 6);
00169             g = *(srcp + 1) + *(srcp + 4) + *(srcp + 7);
00170             b = *(srcp + 2) + *(srcp + 5) + *(srcp + 8);
00171 
00172             /* move down to the next row */
00173             srcp += stride;
00174         
00175             /* add the sum of the pixels in the second row */
00176             r += *srcp + *(srcp + 3) + *(srcp + 6);
00177             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7);
00178             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8);
00179 
00180             srcp += stride;
00181 
00182             /* add the sum of the pixels in the third row, and
00183              * then compute the average and set the output to that
00184              * value
00185              */
00186             r += *srcp + *(srcp + 3) + *(srcp + 6);
00187             r /= 9;
00188             *dst++ = (uint8_t)r;
00189             
00190             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7);
00191             g /= 9;
00192             *dst++ = (uint8_t)g;
00193             
00194             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8);
00195             b /= 9;
00196             *dst++ = (uint8_t)b;
00197         }
00198         
00199         /* move down to the next row (border * 6)*/
00200         dst += 6;
00201         src += 6;
00202     }
00203 }
00204 
00205 /* ----------------------------------------------------------------------------
00206  * ipl__blur_mean_5x5 -- 5x5 mean blur
00207  * ----------------------------------------------------------------------------
00208  * This is a hard-coded 5x5 kernel mean blur, which is approximately 3.2x
00209  * faster than the generic NxN mean blur below.
00210  * ------------------------------------------------------------------------- */
00211 static void ipl__blur_mean_5x5(uint8_t *src,
00212                    uint8_t *dst,
00213                    const int w,
00214                    const int h)
00215 {
00216     uint8_t *srcp;
00217     int stride;
00218     int r;
00219     int g;
00220     int b;
00221     int x;
00222     int y;
00223 
00224     /* this is our row stride */
00225     stride = w * 3;
00226 
00227     /* 5x5 convolutions have a 2 pixel border around the output image,
00228      * because we can't convolve edge pixels.  thus, we must bump the dst
00229      * ptr 2 pixels down and in before we start writing to it
00230      */
00231     dst += ((2 * w) + 2) * 3;
00232 
00233     /* a 5x5 convolution requires 25 adjacent pixels.  the two inner loops
00234      * necessary for convolution are unrolled here for optimality
00235      */
00236     for (y=0; y<h-4; y++)
00237     {
00238         for (x=0; x<w-4; x++)
00239         {
00240             /* get a pointer to the current pixel, and then bump
00241              * the src pointer to the next pixel
00242              */
00243             srcp = src;
00244             src += 3;
00245 
00246             /* compute the sum of the pixels in the first row */
00247             r = *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00248                 *(srcp + 12);
00249 
00250             g = *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00251                 *(srcp + 10) + *(srcp + 13);
00252             
00253             b = *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00254                 *(srcp + 11) + *(srcp + 14);
00255 
00256             /* move down to the next row */
00257             srcp += stride;
00258         
00259             /* add the sum of the pixels in the second row */
00260             r += *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00261                  *(srcp + 12);
00262 
00263             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00264                  *(srcp + 10) + *(srcp + 13);
00265             
00266             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00267                  *(srcp + 11) + *(srcp + 14);
00268 
00269             srcp += stride;
00270 
00271             /* add the sum of the pixels in the third row, and
00272              * then compute the average and set the output to that
00273              * value
00274              */
00275             r += *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00276                  *(srcp + 12);
00277             r /= 25;
00278             *dst++ = (uint8_t)r;
00279 
00280             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00281                  *(srcp + 10) + *(srcp + 13);
00282             g /= 25;
00283             *dst++ = (uint8_t)g;
00284             
00285             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00286                  *(srcp + 11) + *(srcp + 14);
00287             b /= 25;
00288             *dst++ = (uint8_t)b;
00289         }
00290         
00291         /* move down to the next row (border * 6) */
00292         dst += 12;
00293         src += 12;
00294     }
00295 }
00296 
00297 /* ----------------------------------------------------------------------------
00298  * ipl__blur_mean_7x7 -- 7x7 mean blur
00299  * ----------------------------------------------------------------------------
00300  * This is a hard-coded 7x7 kernel mean blur, which is approximately 4.6x
00301  * faster than the generic NxN mean blur below.
00302  * ------------------------------------------------------------------------- */
00303 static void ipl__blur_mean_7x7(uint8_t *src,
00304                    uint8_t *dst,
00305                    const int w,
00306                    const int h)
00307 {
00308     uint8_t *srcp;
00309     int stride;
00310     int r;
00311     int g;
00312     int b;
00313     int x;
00314     int y;
00315 
00316     /* this is our row stride */
00317     stride = w * 3;
00318 
00319     /* 7x7 convolutions have a 3 pixel border around the output image,
00320      * because we can't convolve edge pixels.  thus, we must bump the dst
00321      * ptr 3 pixels down and in before we start writing to it
00322      */
00323     dst += ((3 * w) + 3) * 3;
00324 
00325     /* a 7x7 convolution requires 49 adjacent pixels.  the two inner loops
00326      * necessary for convolution are unrolled here for optimality
00327      */
00328     for (y=0; y<h-6; y++)
00329     {
00330         for (x=0; x<w-6; x++)
00331         {
00332             /* get a pointer to the current pixel, and then bump
00333              * the src pointer to the next pixel
00334              */
00335             srcp = src;
00336             src += 3;
00337 
00338             /* compute the sum of the pixels in the first row */
00339             r = *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00340                 *(srcp + 12) + *(srcp + 15) + *(srcp + 18);
00341 
00342             g = *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00343                 *(srcp + 10) + *(srcp + 13) + *(srcp + 16) +
00344                 *(srcp + 19);
00345             
00346             b = *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00347                 *(srcp + 11) + *(srcp + 14) + *(srcp + 17) +
00348                 *(srcp + 20);
00349 
00350             /* move down to the next row */
00351             srcp += stride;
00352         
00353             /* add the sum of the pixels in the second row */
00354             r += *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00355                  *(srcp + 12) + *(srcp + 15) + *(srcp + 18);
00356 
00357             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00358                  *(srcp + 10) + *(srcp + 13) + *(srcp + 16) +
00359                  *(srcp + 19);
00360             
00361             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00362                  *(srcp + 11) + *(srcp + 14) + *(srcp + 17) +
00363                  *(srcp + 20);
00364 
00365             srcp += stride;
00366 
00367             /* add the sum of the pixels in the third row, and
00368              * then compute the average and set the output to that
00369              * value
00370              */
00371             r += *srcp + *(srcp + 3) + *(srcp + 6) + *(srcp + 9) +
00372                  *(srcp + 12) + *(srcp + 15) + *(srcp + 18);
00373             r /= 49;
00374             *dst++ = (uint8_t)r;
00375 
00376             g += *(srcp + 1) + *(srcp + 4) + *(srcp + 7) +
00377                  *(srcp + 10) + *(srcp + 13) + *(srcp + 16) +
00378                  *(srcp + 19);
00379             g /= 49;
00380             *dst++ = (uint8_t)g;
00381             
00382             b += *(srcp + 2) + *(srcp + 5) + *(srcp + 8) +
00383                  *(srcp + 11) + *(srcp + 14) + *(srcp + 17) +
00384                  *(srcp + 20);
00385             b /= 49;
00386             *dst++ = (uint8_t)b;
00387         }
00388         
00389         /* move down to the next row (border * 6)*/
00390         dst += 18;
00391         src += 18;
00392     }
00393 }
00394 
00395 /* ----------------------------------------------------------------------------
00396  * ------------------------------------------------------------------------- */
00397 static void ipl__blur_mean_nxn(uint8_t *src,
00398                    uint8_t *dst,
00399                    const int w,
00400                    const int h,
00401                    const int k)
00402 {
00403     uint8_t *srcp;
00404     int rstride;    /* row stride */
00405     int wstride;    /* window stride */
00406     int border;
00407     int ksize;
00408     int r;
00409     int g;
00410     int b;
00411     int x;
00412     int y;
00413     int i;
00414     int j;
00415 
00416     /* we can't filter edge pixels in a k*k convolution, so we'll have a
00417      * k / 2 border around the output image
00418      */
00419     border  = k / 2;
00420     ksize   = k * k;
00421 
00422     /* row stride for moving along the src & dst images */
00423     rstride = border * 6;
00424 
00425     /* window row stride for moving along the k*k src window */
00426     wstride = (w - k) * 3;
00427 
00428     /* our output starts "border" pixels down and in from the top left */
00429     dst += ((border * w) + border) * 3;
00430 
00431     for (y=0; y<h-(k-1); y++)
00432     {
00433         for (x=0; x<w-(k-1); x++)
00434         {
00435             r = 0;
00436             g = 0;
00437             b = 0;
00438 
00439             srcp = src;
00440             src += 3;
00441         
00442             /* add up the pixels in the current k*k window */   
00443             for (i=0; i<k; i++)
00444             {
00445                 for (j=0; j<k; j++)
00446                 {
00447                     r += *srcp++;
00448                     g += *srcp++;
00449                     b += *srcp++;
00450                 }
00451                 
00452                 /* move down to the next row in the window */
00453                 srcp += wstride;
00454             }
00455 
00456             /* average the pixel values */
00457             *dst++ = (uint8_t)(r / ksize);
00458             *dst++ = (uint8_t)(g / ksize);
00459             *dst++ = (uint8_t)(b / ksize);
00460         }
00461         
00462         /* move down to the next row */
00463         dst += rstride;
00464         src += rstride;
00465     }
00466 }
00467   
00468 #ifdef __cplusplus
00469 }; /* extern "C" */
00470 #endif
00471 
00472 /* ---------------------------------------------------------------------- */
00473 meanNxN_Filter::meanNxN_Filter(uint32_t kernel_size) :
00474     phFilter("meanNxN_Filter")
00475 
00476 {
00477     this->m_dst         = NULL;
00478     this->m_dstSize     = 0;
00479     this->m_format      = phImageRGB24 | phImageHSV24;
00480     this->m_kernel_size = 3;
00481     
00482     set(kernel_size);
00483 }
00484 
00485 /* ---------------------------------------------------------------------- */
00486 meanNxN_Filter::~meanNxN_Filter()
00487 {
00488     phFree(this->m_dst);
00489 }
00490 
00491 /* ------------------------------------------------------------------------ */
00492 phFilter *meanNxN_Filter::cloneFilter()
00493 {
00494     return (phFilter *)new meanNxN_Filter(this->m_kernel_size);
00495 }
00496 
00497 /* ---------------------------------------------------------------------- */
00498 int meanNxN_Filter::set(uint32_t kernel_size)
00499 {
00500     if(kernel_size < 3)
00501     {
00502         kernel_size = 3;
00503     }
00504     else if(kernel_size % 2 == 0) 
00505     {
00506         this->m_kernel_size = kernel_size - 1;
00507     }
00508     else
00509     {
00510         this->m_kernel_size = kernel_size;
00511     }
00512 
00513     return phSUCCESS;
00514 }
00515 
00516 /* ---------------------------------------------------------------------- */
00517 int meanNxN_Filter::filter()
00518 {
00519     phFUNCTION("meanNxN_Filter::filter")
00520 
00521     /* Begin filter */
00522     phDALLOC_RESIZE(this->m_dst,
00523                     this->m_dstSize,
00524                     width * height * depth,
00525                     uint8_t);
00526     
00527     rc = ipl_blur_mean( (uint8_t *)Image,
00528                         (uint8_t *)this->m_dst,
00529                         width,
00530                         height,
00531                         this->m_kernel_size);
00532     phCHECK_RC(rc,NULL,"ipl_blur_mean returned error.");
00533     
00534     /* dstSize should be the same size as the Image, otherwise things
00535      * went nutty and if we segfault, who the heck knows what went wrong */
00536     phMemcpy(Image,
00537            this->m_dst,
00538            this->m_dstSize);
00539     
00540     /* End Filter */
00541     
00542     return phSUCCESS;
00543 error:
00544     return phFAIL;
00545 }
00546 




Copyright (C) 2002 - 2007 Philip D.S. Thoren ( pthoren@users.sourceforge.net )
University Of Massachusetts at Lowell
Robotics Lab
SourceForge.net Logo

Generated on Sat Jun 16 02:44:10 2007 for phission by  doxygen 1.4.4