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

medianNxN_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     meadian 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 <medianNxN_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 {
00053 #endif /* __cplusplus */
00054  /* ----------------------------------------------------------------------------
00055  * median.c -- Median blur
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 
00067 /* this is one of those "cute tricks" */
00068 #ifdef SWAP
00069 #define SWAP_OLD SWAP
00070 #undef SWAP
00071 #endif /* ifdef SWAP */
00072 #define SWAP(a, b)  \
00073     (a) ^= (b); \
00074     (b) ^= (a); \
00075     (a) ^= (b);
00076 
00077 /* this is based on some 32-bit fixed point math principles.  You might not
00078  * believe me, but using fixed point over floating point saved about 170 usecs
00079  * in the median filter...so it stays.
00080  *
00081  * You convert RGB values to an intensity like so:
00082  *  LUMA = (R * 0.3) + (G * 0.59) + (B * 0.11)
00083  *
00084  * When converting the constants to fixed point, I multiplied by 256 rather
00085  * than 65536 to save me a bitshift later in the multiplication.  The fixed
00086  * point macros in ipl.h should explain
00087  * 
00088  */
00089 #define LUMA_RGB(ptr)               \
00090     (uint8_t)(((*(ptr)    << 8) * 77  +     \
00091           (*((ptr)+1) << 8) * 151 +     \
00092           (*((ptr)+2) << 8) * 28) >> 16)
00093 
00094 #define R   0   /* red channel */
00095 #define G   1   /* green channel */
00096 #define B   2   /* blue channel */
00097 #define L   3   /* luminance */
00098 
00099 /* ----------------------------------------------------------------------------
00100  * ------------------------------------------------------------------------- */
00101 static int ipl__get_median_index(uint8_t *a, const int len)
00102 {
00103     static int ranks[121];
00104     int swapped;
00105     int gap;
00106     int i;
00107     int j;
00108 
00109     /* we're sorting elment indices rather than the elements */
00110     for (i=0; i<len; i++)
00111         ranks[i] = i;
00112 
00113     gap = len;
00114     
00115     /* this is a COMB SORT.  it is about 2x faster than a bubble sort, and
00116      * not much more complicated
00117      */
00118     for (;;)
00119     {
00120         swapped = 0;
00121     
00122         /* divide the gap by 1.3 on each pass.  when gap = 1, this
00123          * becomes a bubble sort
00124          */ 
00125         gap = (gap * 10) / 13;
00126     
00127         /* these gap values are statistically bad, so we adjust them */ 
00128         if (gap == 9 || gap == 10)
00129             gap = 11;
00130         if (gap < 1)
00131             gap = 1;
00132 
00133         for (i=0; i<len-gap; i++)
00134         {
00135             j = i + gap;
00136             if (a[ranks[i]] > a[ranks[j]])
00137             {
00138                 SWAP(ranks[i], ranks[j]);
00139                 swapped++;
00140             }
00141         }
00142 
00143         if (gap == 1 && !swapped)
00144             break;
00145     }
00146 
00147     /* return the *index* of the median value in the luminance array */
00148     return ranks[len / 2];
00149 }
00150 
00151 /* ----------------------------------------------------------------------------
00152  * ------------------------------------------------------------------------- */
00153 int ipl_blur_median(uint8_t *src,
00154             uint8_t *dst,
00155             const int w,
00156             const int h,
00157             const int k)
00158 {
00159     phFUNCTION("ipl_blur_median")
00160     
00161     static uint8_t median[4][121];
00162     uint8_t *srcp;
00163     int rstride;
00164     int wstride;
00165     int border;
00166     int ksize;
00167     int idx;
00168     int n;
00169     int x;
00170     int y;
00171     int i;
00172     int j;
00173 
00174     /* check the kernel size.  it must be odd */
00175     if ((k & 1) == 0)
00176     {
00177         phERR_PRINT("filter kernel size must be odd");
00178         return -1;
00179     }
00180     
00181     /* the way I figure it, if you *really* want a kernel size greater
00182      * than 11, get off the robot
00183      */
00184     if (k < 3 || k > 11)
00185     {
00186         phERR_PRINT("filter kernel size must be between 3 and 11"); 
00187         return -2;
00188     }
00189     
00190     border = k / 2;
00191     ksize  = k * k;
00192 
00193     /* row stride for moving along the src & dst images */
00194     rstride = (k - 1) * 3;
00195 
00196     /* window row stride for moving along the k*k src window */
00197     wstride = (w - k) * 3;
00198 
00199     /* our output starts "border" pixels down and in from the top left */
00200     dst += ((border * w) + border) * 3;
00201 
00202     for (y=0; y<h-(k-1); y++)
00203     {
00204         for (x=0; x<w-(k-1); x++)
00205         {
00206             srcp = src;
00207             src += 3;
00208             n    = 0;
00209             
00210             for (i=0; i<k; i++)
00211             {
00212                 for (j=0; j<k; j++)
00213                 {
00214                     median[L][n] = LUMA_RGB(srcp);
00215                     median[R][n] = *srcp++; 
00216                     median[G][n] = *srcp++;
00217                     median[B][n] = *srcp++;
00218 
00219                     n++;
00220                 }
00221                 srcp += wstride;
00222             }
00223 
00224             idx = ipl__get_median_index(median[L], ksize);
00225 
00226             *dst++ = median[R][idx];
00227             *dst++ = median[G][idx];
00228             *dst++ = median[B][idx];
00229         }
00230         src += rstride;
00231         dst += rstride;
00232     }
00233 
00234     return 0;
00235 }   
00236 
00237 #ifdef SWAP_OLD
00238 #undef SWAP
00239 #define SWAP SWAP_OLD
00240 #undef SWAP_OLD
00241 #endif
00242 
00243 #ifdef __cplusplus
00244 }; /* extern "C" */
00245 #endif /* __cplusplus */
00246 
00247 /* ---------------------------------------------------------------------- */
00248 medianNxN_Filter::medianNxN_Filter(uint32_t kernel_size ) :
00249     phFilter("medianNxN_Filter")
00250 
00251 {
00252     this->m_format = phImageRGB24 | phImageHSV24;
00253 
00254     this->m_output      = NULL;
00255     this->m_outputSize  = 0;
00256     this->m_kernel_size = 3;
00257     
00258     this->set(kernel_size);
00259 }
00260 
00261 /* ---------------------------------------------------------------------- */
00262 medianNxN_Filter::~medianNxN_Filter()
00263 {
00264     phFree(this->m_output);
00265 }
00266 
00267 /* ------------------------------------------------------------------------ */
00268 phFilter *medianNxN_Filter::cloneFilter()
00269 {
00270     return (phFilter *)new medianNxN_Filter(this->m_kernel_size);
00271 }
00272 
00273 /* ---------------------------------------------------------------------- */
00274 int medianNxN_Filter::set(uint32_t kernel_size)
00275 {
00276     /* make sure the kernel at least of size 3,
00277      * it makes no sense to have a kernel any smaller */
00278     if(kernel_size < 3)
00279     {
00280         /* 3: default kernel size */
00281         this->m_kernel_size = 3;
00282     }
00283     /* make kernel size an odd value */
00284     else if ((kernel_size % 2) == 0) 
00285     {
00286         this->m_kernel_size = kernel_size - 1;
00287     }
00288     else
00289     {
00290         this->m_kernel_size = kernel_size;
00291     }
00292  
00293     return phSUCCESS;
00294 }
00295 
00296 /* ---------------------------------------------------------------------- */
00297 int medianNxN_Filter::filter()
00298 {
00299     phFUNCTION("medianNxN_Filter::filter")
00300 
00301     phDALLOC_RESIZE(this->m_output,
00302                     this->m_outputSize,
00303                     width*height*depth,
00304                     uint8_t);
00305 
00306     rc = ipl_blur_median((uint8_t *)Image, 
00307                          (uint8_t *)this->m_output,
00308                          width,
00309                          height,
00310                          this->m_kernel_size );
00311     phCHECK_RC(rc,NULL,"ipl_blur_median returned error.");
00312     
00313     phMemcpy(Image,
00314            this->m_output,
00315            this->m_outputSize);
00316 
00317     return phSUCCESS;
00318 error:
00319     
00320     return phFAIL;
00321 }
00322 




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