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

Generated on Thu Nov 15 14:32:25 2007 for UVES Pipeline Reference Manual by  doxygen 1.5.1