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;
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));
00177 PIXEL_TYPE *ref = malloc(Nx*Ny * sizeof(*ref));
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
00200 }
00201
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
00223
00224 memset(out, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00225 memset(ref, 0, Nxc*Nyc * sizeof(PIXEL_TYPE));
00226 }
00227
00228
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
00363
00364
00365
00366
00367
00368
00369
00370
00371
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
00387
00388
00389
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404 }
00405
00406
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