filter_median_type.c

00001 
00002 #define TYPE_ADD(a) CONCAT2X(a, PIXEL_TYPE)
00003 
00004 #define SWAP_ONE(p,a,b) { register PIXEL_TYPE t=p[a];p[a]=p[b];p[b]=t; }
00005 #define SORT_ONE(p,a,b) { if (p[a]>p[b]) SWAP_ONE(p, a, b); }
00006 
00007 
00008 static PIXEL_TYPE TYPE_ADD(bf_get_median_9)(PIXEL_TYPE * p)
00009 {
00010 
00011     SORT_ONE(p,1, 2); SORT_ONE(p,4, 5); SORT_ONE(p,7,8);
00012     SORT_ONE(p,0, 1); SORT_ONE(p,3, 4); SORT_ONE(p,6,7);
00013     SORT_ONE(p,1, 2); SORT_ONE(p,4, 5); SORT_ONE(p,7,8);
00014     SORT_ONE(p,0, 3); SORT_ONE(p,5, 8); SORT_ONE(p,4,7);
00015     SORT_ONE(p,3, 6); SORT_ONE(p,1, 4); SORT_ONE(p,2,5);
00016     SORT_ONE(p,4, 7); SORT_ONE(p,4, 2); SORT_ONE(p,6,4);
00017     SORT_ONE(p,4, 2); return(p[4]);
00018 }
00019 
00020 static
00021 PIXEL_TYPE TYPE_ADD(bf_get_kth)(
00022     PIXEL_TYPE  *   a,
00023     unsigned         n,
00024     int         k)
00025 {
00026     PIXEL_TYPE x ;
00027     int    i, j, l, m ;
00028 
00029     l=0 ; m=n-1 ;
00030     while (l<m) {
00031         x=a[k] ;
00032         i=l ;
00033         j=m ;
00034         do {
00035             while (a[i]<x) i++ ;
00036             while (x<a[j]) j-- ;
00037             if (i<=j) {
00038                 const PIXEL_TYPE temp = a[i];
00039                 a[i] = a[j];
00040                 a[j] = temp;
00041                 i++ ; j-- ;
00042             }
00043         } while (i<=j) ;
00044         if (j<k) l=i ;
00045         if (k<i) m=j ;
00046     }
00047     return a[k] ;
00048 }
00049 
00050 static PIXEL_TYPE TYPE_ADD(bf_get_median_lower)(
00051     PIXEL_TYPE  *   a,
00052     unsigned         n)
00053 {
00054     if (n == 9) {
00055         return TYPE_ADD(bf_get_median_9)(a);
00056     } else
00057         return TYPE_ADD(bf_get_kth)(a, n, (n-1)/2);
00058 }
00059 
00060 static PIXEL_TYPE TYPE_ADD(bf_get_median_upper)(
00061     PIXEL_TYPE  *   a,
00062     unsigned         n)
00063 {
00064     if (n == 9) {
00065         return TYPE_ADD(bf_get_median_9)(a);
00066     } else
00067         return TYPE_ADD(bf_get_kth)(a, n, n/2);
00068 }
00069 
00070 static void
00071 TYPE_ADD(filter_median_bf)(const PIXEL_TYPE *in, PIXEL_TYPE *out,
00072                            unsigned Nx, unsigned Ny, unsigned Rx, unsigned Ry,
00073                            unsigned mode)
00074 {
00075     PIXEL_TYPE *data = malloc((2*Rx+1)*(2*Ry+1)*sizeof(*data));
00076     unsigned y;
00077 
00078     mode &= IRPLIB_FILTER_BORDER_MODE;
00079 
00080     if (mode == IRPLIB_FILTER_BORDER_FILTER) {
00081         for (y = 0; y < Ny; y++, out += Nx) {
00082             unsigned x;
00083 
00084             for (x = 0; x < Nx; x++) {
00085                 unsigned k = 0;
00086                 unsigned i, j;
00087                 for (j = y < Ry ? 0 : y-Ry; j <= (y+Ry >= Ny ? Ny - 1 : y+Ry); j++)
00088                     for (i = x < Rx ? 0 : x-Rx; i <= (x+Rx >= Nx ? Nx-1 : x+Rx); i++)
00089                         data[k++] = in[i + j*Nx];
00090             
00091                 if (((y + x) & 1) == 0) {
00092                     out[x] = TYPE_ADD(bf_get_median_upper)(data, k);
00093                 }
00094                 else {
00095                     out[x] = TYPE_ADD(bf_get_median_lower)(data, k);
00096                 }
00097             }
00098         }
00099     } else {
00100         if (mode == IRPLIB_FILTER_BORDER_CROP) {
00101             out += Rx;
00102         } else {
00103             if (mode == IRPLIB_FILTER_BORDER_COPY) 
00104                 (void)memcpy(out, in, (Ry*Nx+Rx)*sizeof(*out));
00105             out += Ry * Nx;
00106         }
00107 
00108         for (y = 0 + Ry; y < Ny-Ry; y++, out += Nx) {
00109             unsigned x = Rx;
00110 
00111             if (mode == IRPLIB_FILTER_BORDER_CROP) {
00112                 out -= 2*Rx; /* Nx - 2 Rx medians in each row */
00113             } else if (mode == IRPLIB_FILTER_BORDER_COPY) {
00114                 if (y != Ry) {
00115                     (void)memcpy(out-Rx, in + y * Nx - Rx, 2*Rx*sizeof(*out));
00116                 }
00117             }
00118 
00119             for (; x < Nx - Rx; x++) {
00120                 unsigned k = 0;
00121                 unsigned i, j;
00122                 for (j = y-Ry; j <= y+Ry; j++)
00123                     for (i = x-Rx; i <= x+Rx; i++)
00124                         data[k++] = in[i + j*Nx];
00125             
00126                 out[x] = TYPE_ADD(bf_get_median_lower)(data, k);
00127             }
00128 
00129             if (mode == IRPLIB_FILTER_BORDER_EXTRAPOL_OUT) {
00130                 unsigned i;
00131                 for (i = 0; i < Rx; i++) {
00132                     out[i] = out[Rx];
00133                 }
00134                 for (i = 0; i < Rx; i++) {
00135                     out[Nx-Rx+i] = out[Nx-Rx-1];
00136                 }
00137                 if (y == Ry) {
00138                     unsigned ir;
00139                     for (ir = 0; ir < Ry; ir++)
00140                         (void)memcpy(out-(Ry-ir)*Nx, out, Nx*sizeof(*out));
00141                 }
00142             } else if (mode == IRPLIB_FILTER_BORDER_COPY) {
00143                 if (y == Ny - Ry - 1) {
00144                     (void)memcpy(out + Nx-Rx, 
00145                                  in  + Nx-Rx + y * Nx,
00146                                  Rx*sizeof(*out));
00147                 }
00148             }
00149         }
00150 
00151         if (mode == IRPLIB_FILTER_BORDER_COPY) {
00152             (void)memcpy(out, in + y * Nx, Ry*Nx*sizeof(*out));
00153         } else if (mode == IRPLIB_FILTER_BORDER_EXTRAPOL_OUT) {
00154             unsigned ir;
00155 
00156             for (ir = 0; ir < Ry; ir++)
00157                 (void)memcpy(out+ir*Nx, out-Nx, Nx*sizeof(*out));
00158         }
00159     }
00160 
00161     free(data);
00162     return;
00163 }
00164 
00165 
00166 static int
00167 TYPE_ADD(test_irplib_image_filter)(unsigned Nx, unsigned Ny,
00168                                    unsigned Rx, unsigned Ry,
00169                                    unsigned mode,
00170                                    unsigned Nreps1,
00171                                    unsigned Nreps2)
00172 {
00173     mybool dofail = myfalse;
00174 
00175     PIXEL_TYPE *in  = malloc(Nx*Ny * sizeof(*in));
00176     PIXEL_TYPE *out = malloc(Nx*Ny * sizeof(*out)); /* Too large in crop mode */
00177     PIXEL_TYPE *ref = malloc(Nx*Ny * sizeof(*ref)); /* Too large in crop mode */
00178     const double myeps
00179 #ifdef PIXEL_TYPE_IS_INT
00180         = 0.0;
00181 #else
00182         = (mode & ~IRPLIB_FILTER_BORDER_MODE) == IRPLIB_FILTER_MEDIAN ? 0.0
00183         : 1e1 * Nx * Ny * (sizeof(PIXEL_TYPE) == 4 ? FLT_EPSILON : DBL_EPSILON);
00184 #endif
00185     double maxerr = 0.0;
00186 
00187     assure( Nx > 0 );
00188     assure( Ny > 0 );
00189 
00190     assure( in  != NULL );
00191     assure( out != NULL );
00192     assure( ref != NULL );
00193 
00194     {
00195         unsigned i, j;
00196         for (j = 0; j < Ny; j++) {
00197             for (i = 0; i < Nx; i++) {
00198                 in[i + j*Nx] = (PIXEL_TYPE)(10.0 + rand_gauss()*3.0);
00199                 /* fprintf(stderr, "(%d, %d): %f", i, j, in[i+j*Nx]); */
00200             }
00201             /* fprintf(stderr, "\n"); */
00202         }
00203     }
00204 
00205     {
00206         const unsigned Nxc
00207             = (mode & IRPLIB_FILTER_BORDER_MODE) == IRPLIB_FILTER_BORDER_CROP
00208             ? Nx - 2 * Rx : Nx;
00209         const unsigned Nyc
00210             = (mode & IRPLIB_FILTER_BORDER_MODE) == IRPLIB_FILTER_BORDER_CROP
00211             ? Ny - 2 * Ry : Ny;
00212         cpl_image  *imgin  = TYPE_ADD(cpl_image_wrap)(Nx, Ny, in);
00213         cpl_image  *imgout = TYPE_ADD(cpl_image_wrap)(Nxc, Nyc, out);
00214         cpl_image  *imgref = TYPE_ADD(cpl_image_wrap)(Nxc, Nyc, ref);
00215         
00216         unsigned i;
00217         for (i = 0; i < Nreps2; i++) {
00218             clock_t t, tbf;
00219             unsigned j;
00220             
00221             if ((mode & IRPLIB_FILTER_BORDER_MODE) == IRPLIB_FILTER_BORDER_NOP) {
00222                 /* The border will not be set by the filtering,
00223                    so preset it (to zero) */
00224                 memset(out, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00225                 memset(ref, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00226             }
00227 
00228             /* binary heap + column arrays */
00229             t = clock();
00230             for (j = 0; j < Nreps1; j++) {
00231                 irplib_image_filter(imgout, imgin, Rx, Ry, mode);
00232                 cpl_test_error(CPL_ERROR_NONE);
00233                 if (cpl_error_get_code() != CPL_ERROR_NONE) {
00234                     cpl_error_reset();
00235                     dofail = mytrue;
00236                 }
00237             }
00238             t = clock()-t;
00239             if (1) {
00240                 tbf = clock();
00241                 for (j = 0; j < Nreps1; j++) {
00242                     if ((mode & ~IRPLIB_FILTER_BORDER_MODE) == IRPLIB_FILTER_MEDIAN) {
00243                         TYPE_ADD(filter_median_bf)(in, ref, Nx, Ny, Rx, Ry, mode);
00244                     } else {
00245 #ifdef IRPLIB_FILTER_TEST_AVERAGE_FAST
00246                         TYPE_ADD(image_filter_average_ref)(ref, in, Nx, Ny,
00247                                                           Rx, Ry, mode);
00248 #elif 1
00249                         TYPE_ADD(image_filter_average_bf)(ref, in, Nx, Ny,
00250                                                           Rx, Ry, mode);
00251 #else
00252                         cpl_test_zero(filter_average_bf(imgref, imgin, Rx, Ry, mode));
00253 #endif
00254                     }
00255                 }
00256                 tbf = clock()-tbf;
00257                 cpl_msg_info(cpl_func, "Time to %u-filter %u X %u with %u X %u "
00258                              "[s]: %f %f", mode, Nx, Ny, Rx, Ry,
00259                              (double)t/CLOCKS_PER_SEC,
00260                              (double)tbf/CLOCKS_PER_SEC);
00261             
00262                 if (!dofail) {
00263                     unsigned x, y;
00264                     for (y = 0; y < Nyc; y++) {
00265                         for (x = 0; x < Nxc; x++) {
00266                             const PIXEL_TYPE m1 = out[x + y*Nxc];
00267                             const PIXEL_TYPE m2 = ref[x + y*Nxc];
00268                             double myerr = 0.0;
00269 
00270                             if (Ry > 1 && (y < Ry || y >= Ny-Ry) &&
00271                                 Rx > 1 && (x < Rx || x >= Nx-Rx))
00272                                 continue;
00273 
00274                             if (m1 < m2) {
00275                                 myerr = m2 - m1;
00276                                 if (myerr > myeps) {
00277                                     cpl_msg_error("", "(%d, %d): Filtered value too small: "
00278                                                   "%g < %g", x, y, (double)m1,
00279                                                   (double)m2);
00280                                     dofail = mytrue;
00281                                 } else {
00282 #if 0
00283                                     cpl_msg_debug("", "(%d, %d): Filtered value too small: "
00284                                                   "%g - %g = %g, ", x, y, (double)m1,
00285                                                     (double)m2, myerr);
00286 #endif
00287                                 }
00288                             } else if (m1 > m2) {
00289                                 myerr = m1 - m2;
00290                                 if (myerr > myeps) {
00291                                     cpl_msg_error("", "(%d, %d): Filtered value too large: "
00292                                                   "%g > %g", x, y, (double)m1, (double)m2);
00293                                     dofail = mytrue;
00294                                 } else {
00295 #if 0
00296                                     cpl_msg_debug("", "(%d, %d): Filtered value too large: "
00297                                                   "%g - %g = %g, ", x, y, (double)m1,
00298                                                     (double)m2, myerr);
00299 #endif
00300                                 }
00301 #if 0
00302                             } else {
00303                                 cpl_msg_debug("", "(%d, %d): Filtered value OK: %g",
00304                                        x, y, (double)m1);
00305 #endif
00306                             }
00307                             if (myerr > maxerr) {
00308                                 maxerr = myerr;
00309                             }
00310                         }
00311                     }
00312                     if (!dofail) {
00313                         cpl_msg_info(cpl_func, "Filtering is OK");
00314                         if (maxerr > 0.0) {
00315                             assert( myeps > 0.0);
00316                             cpl_msg_info("", "Largest filtering error [%g]: %g",
00317                                             myeps, maxerr/myeps);
00318                         }
00319                     }
00320                 }
00321             }
00322         }
00323         (void)cpl_image_unwrap(imgin);
00324         (void)cpl_image_unwrap(imgout);
00325         (void)cpl_image_unwrap(imgref);
00326     }
00327 
00328     free(in);
00329     free(out);
00330     free(ref);
00331 
00332     return (int)dofail;
00333 }
00334 
00335 #ifdef IRPLIB_FILTER_TEST_AVERAGE_FAST
00336 
00337 /*----------------------------------------------------------------------------*/
00350 /*----------------------------------------------------------------------------*/
00351 static void
00352 TYPE_ADD(image_filter_average_ref)(PIXEL_TYPE * out, const PIXEL_TYPE * in,
00353                                    int nx, int ny, int hsizex, int hsizey,
00354                                    unsigned border_mode)
00355 {
00356 
00357     PIXEL_TYPE * aux = calloc((nx+1)*(ny+1), sizeof(PIXEL_TYPE));
00358     int         i;
00359 
00360     assert(border_mode != 0);
00361 
00362     /* First build auxillary image:
00363      *
00364      * aux(x,y) = sum_{i=0,x-1} sum_{j=0,y-1}  image(i,j)
00365      *          = sum of rectangle (0,0)-(x-1,y-1)
00366      *
00367      */
00368 
00369 
00370     /* Column x=0 and row y=0 are already zero and need not be calculated,
00371      * start from 1.    */
00372 
00373     for (i = 0; i < (nx+1)*(ny+1); i++)
00374     {
00375         int x = i % (nx+1);
00376         int y = i / (nx+1);
00377 
00378         if ( x >= 1 && y >= 1)
00379         {
00380             aux[x + y*(nx+1)] = (PIXEL_TYPE)in[x-1 + (y-1) * nx]
00381             + aux  [x-1 +    y * (nx+1)]
00382             + aux  [x   + (y-1)* (nx+1)]
00383             - aux  [x-1 + (y-1)* (nx+1)];
00384         }
00385 
00386         /* Proof of induction step
00387          * (assume that formula holds up to (x-1,y) and (x,y-1) and prove formula for (x,y))
00388          *
00389          *  aux(x,y) = image(x-1, y-1) + aux(x-1, y) + aux(x, y-1) - aux(x-1, y-1)  (see code)
00390          *
00391          *  = image(x-1, y-1)
00392          *  + sum_{i=0,x-2}_{j=0,y-1} image(i,j)  _
00393          *  + sum_{i=0,x-1}_{j=0,y-2} image(i,j)   \_ sum_{j=0,y-2} image(x-1, j)
00394          *  - sum_{i=0,x-2}_{j=0,y-2} image(i,j)  _/
00395          *
00396          *  = sum_{i=0,x-2}_{j=0,y-1} image(i,j)
00397          *  + sum_          {j=0,y-1} image(x-1, j)
00398          *
00399          *  = sum_{j=0,y-1} [ ( sum_{i=0,x-2} image(i,j) ) + image(x-1,j) ]
00400          *  = sum_{j=0,y-1}     sum_{i=0,x-1} image(i,j)      q.e.d.
00401          *
00402          *  It's simpler when you draw it...
00403          */
00404     }
00405 
00406     /* Then calculate average = (flux in window) / (image size) */
00407     for (i = 0; i < nx*ny; i++)
00408     {
00409         int x = (i % nx);
00410         int y = (i / nx);
00411 
00412         int lower, upper;
00413         int left, right;
00414 
00415         lower = y - hsizey; if (lower <   0) lower = 0;
00416         upper = y + hsizey; if (upper >= ny) upper = ny - 1;
00417 
00418         left  = x - hsizex; if (left  <   0) left  = 0;
00419         right = x + hsizex; if (right >= nx) right = nx - 1;
00420 
00421         out[x + y*nx] = (PIXEL_TYPE)((
00422         (
00423             aux[(right+1) + (upper+1)*(nx+1)] +
00424             aux[ left     +  lower   *(nx+1)] -
00425             aux[ left     + (upper+1)*(nx+1)] -
00426             aux[(right+1) +  lower   *(nx+1)]
00427             )
00428         /
00429         (PIXEL_TYPE) ( (upper-lower+1) * (right-left+1) )));
00430     }
00431 
00432     free(aux);
00433 
00434     return;
00435 }
00436 
00437 #else
00438 
00439 /*----------------------------------------------------------------------------*/
00452 /*----------------------------------------------------------------------------*/
00453 static void
00454 TYPE_ADD(image_filter_average_bf)(PIXEL_TYPE * out, const PIXEL_TYPE * in,
00455                                   int Nx, int Ny, int hsizex, int hsizey,
00456                                   unsigned border_mode)
00457 {
00458 
00459     int y;
00460 
00461     assert( border_mode != 0);
00462 
00463 
00464     for (y = 0; y < Ny; y++, out += Nx) {
00465         int x;
00466 
00467         for (x = 0; x < Nx; x++) {
00468             int k = 0;
00469             int i, j;
00470             PIXEL_TYPE sum = (PIXEL_TYPE)0;
00471 
00472             for (j = y < hsizey ? 0 : y-hsizey;
00473                  j <= (y+hsizey >= Ny ? Ny - 1 : y+hsizey); j++) {
00474                 for (i = x < hsizex ? 0 : x-hsizex;
00475                      i <= (x+hsizex >= Nx ? Nx-1 : x+hsizex); i++) {
00476                     sum += in[i + j*Nx];
00477                     k++;
00478                 }
00479             }
00480             
00481             out[x] = sum/(PIXEL_TYPE)k;
00482         }
00483     }
00484 
00485     return;
00486 }
00487 
00488 #endif
00489 
00490 
00491 #undef SWAP_ONE
00492 #undef SORT_ONE

Generated on Wed Mar 9 15:46:16 2011 for NACO Pipeline Reference Manual by  doxygen 1.5.8