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);
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;
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);
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));
00183 PIXEL_TYPE *ref = malloc(Nx*Ny * sizeof(*ref));
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
00230
00231 memset(out, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00232 memset(ref, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00233 }
00234
00235
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
00364
00365
00366
00367
00368
00369
00370
00371
00372
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
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405 }
00406
00407
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