piuspatch
v0.1
USB addition to PIE backend
|
00001 00030 #include <stdlib.h> 00031 #include <string.h> 00032 #include <values.h> 00033 #include <math.h> 00034 00035 #define BACKEND_NAME sanei_ir /* name of this module for debugging */ 00036 00037 #include "../include/sane/sane.h" 00038 #include "../include/sane/sanei_debug.h" 00039 #include "../include/sane/sanei_ir.h" 00040 #include "../include/sane/sanei_magic.h" 00041 00042 00043 double * 00044 sanei_ir_create_norm_histo (const SANE_Parameters * params, 00045 const SANEI_IR_bufptr img_data); 00046 double * sanei_ir_accumulate_norm_histo (double * histo_data); 00047 00048 00049 /* Initialize sanei_ir 00050 */ 00051 void 00052 sanei_ir_init (void) 00053 { 00054 DBG_INIT (); 00055 } 00056 00057 00058 /* Create a normalized histogram of a grayscale image, internal 00059 */ 00060 double * 00061 sanei_ir_create_norm_histo (const SANE_Parameters * params, 00062 const SANEI_IR_bufptr img_data) 00063 { 00064 uint8_t *img_data8; 00065 uint16_t *img_data16; 00066 int is, i; 00067 int num_pixels; 00068 int *histo_data = NULL; 00069 double *histo = NULL; 00070 double term; 00071 00072 DBG (10, "sanei_ir_create_histo\n"); 00073 00074 if ((params->format != SANE_FRAME_GRAY) 00075 && (params->format != SANE_FRAME_RED) 00076 && (params->format != SANE_FRAME_GREEN) 00077 && (params->format != SANE_FRAME_BLUE)) 00078 { 00079 DBG (5, "sanei_ir_create_norm_histo: invalid format\n"); 00080 return NULL; 00081 } 00082 00083 /* Allocate storage for the histogram */ 00084 histo_data = calloc (HISTOGRAM_SIZE, sizeof (int)); 00085 histo = malloc (HISTOGRAM_SIZE * sizeof (double)); 00086 if ((histo == NULL) || (histo_data == NULL)) 00087 { 00088 DBG (5, "sanei_ir_create_norm_histo: no buffers\n"); 00089 free (histo); 00090 free (histo_data); 00091 return NULL; 00092 } 00093 00094 num_pixels = params->pixels_per_line * params->lines; 00095 00096 /* Populate the histogram */ 00097 is = params->depth - HISTOGRAM_SHIFT; 00098 if (params->depth > 8) 00099 { 00100 img_data16 = img_data.b16; 00101 if (is == 8) 00102 for (i = num_pixels; i > 0; i--) 00103 histo_data[*img_data16++ >> 8]++; 00104 else 00105 for (i = num_pixels; i > 0; i--) 00106 histo_data[*img_data16++ >> is]++; 00107 } 00108 else 00109 { 00110 img_data8 = img_data.b8; 00111 if (is == 0) 00112 for (i = num_pixels; i > 0; i--) 00113 histo_data[*img_data8++]++; 00114 else 00115 for (i = num_pixels; i > 0; i--) 00116 histo_data[*img_data8++ >> is]++; 00117 } 00118 00119 /* Calculate the normalized histogram */ 00120 term = 1.0 / (double) num_pixels; 00121 for (i = 0; i < HISTOGRAM_SIZE; i++) 00122 histo[i] = term * (double) histo_data[i]; 00123 00124 free (histo_data); 00125 return histo; 00126 } 00127 00128 00129 /* Create the normalized histogram of a grayscale image 00130 */ 00131 SANE_Status 00132 sanei_ir_create_norm_histogram (const SANE_Parameters * params, 00133 const SANEI_IR_bufptr img_data, 00134 double ** histogram) 00135 { 00136 double *histo; 00137 00138 DBG (10, "sanei_ir_create_histogram\n"); 00139 00140 histo = sanei_ir_create_norm_histo (params, img_data); 00141 if (!histo) 00142 return SANE_STATUS_NO_MEM; 00143 00144 *histogram = histo; 00145 return SANE_STATUS_GOOD; 00146 } 00147 00148 /* Accumulate a normalized histogram, internal 00149 */ 00150 double * 00151 sanei_ir_accumulate_norm_histo (double * histo_data) 00152 { 00153 int i; 00154 double *accum_data; 00155 00156 accum_data = malloc (HISTOGRAM_SIZE * sizeof (double)); 00157 if (accum_data == NULL) 00158 { 00159 DBG (5, "sanei_ir_accumulate_norm_histo: Insufficient memory !\n"); 00160 return NULL; 00161 } 00162 00163 accum_data[0] = histo_data[0]; 00164 for (i = 1; i < HISTOGRAM_SIZE; i++) 00165 accum_data[i] = accum_data[i - 1] + histo_data[i]; 00166 00167 return accum_data; 00168 } 00169 00170 /* Implements Yen's thresholding method 00171 */ 00172 SANE_Status 00173 sanei_ir_threshold_yen (const SANE_Parameters * params, 00174 double * norm_histo, int *thresh) 00175 { 00176 double *P1 = NULL; /* cumulative normalized histogram */ 00177 double *P1_sq = NULL; /* cumulative normalized histogram */ 00178 double *P2_sq = NULL; 00179 double crit, max_crit; 00180 int threshold, i; 00181 SANE_Status ret = SANE_STATUS_NO_MEM; 00182 00183 DBG (10, "sanei_ir_threshold_yen\n"); 00184 00185 P1 = sanei_ir_accumulate_norm_histo (norm_histo); 00186 P1_sq = malloc (HISTOGRAM_SIZE * sizeof (double)); 00187 P2_sq = malloc (HISTOGRAM_SIZE * sizeof (double)); 00188 if (!P1 || !P1_sq || !P2_sq) 00189 { 00190 DBG (5, "sanei_ir_threshold_yen: no buffers\n"); 00191 goto cleanup; 00192 } 00193 00194 /* calculate cumulative squares */ 00195 P1_sq[0] = norm_histo[0] * norm_histo[0]; 00196 for (i = 1; i < HISTOGRAM_SIZE; i++) 00197 P1_sq[i] = P1_sq[i - 1] + norm_histo[i] * norm_histo[i]; 00198 P2_sq[HISTOGRAM_SIZE - 1] = 0.0; 00199 for (i = HISTOGRAM_SIZE - 2; i >= 0; i--) 00200 P2_sq[i] = P2_sq[i + 1] + norm_histo[i + 1] * norm_histo[i + 1]; 00201 00202 /* Find the threshold that maximizes the criterion */ 00203 threshold = INT_MIN; 00204 max_crit = DBL_MIN; 00205 for (i = 0; i < HISTOGRAM_SIZE; i++) 00206 { 00207 crit = 00208 -1.0 * SAFE_LOG (P1_sq[i] * P2_sq[i]) + 00209 2 * SAFE_LOG (P1[i] * (1.0 - P1[i])); 00210 if (crit > max_crit) 00211 { 00212 max_crit = crit; 00213 threshold = i; 00214 } 00215 } 00216 00217 if (threshold == INT_MIN) 00218 { 00219 DBG (5, "sanei_ir_threshold_yen: no threshold found\n"); 00220 ret = SANE_STATUS_INVAL; 00221 } 00222 else 00223 { 00224 ret = SANE_STATUS_GOOD; 00225 if (params->depth > 8) 00226 { 00227 i = 1 << (params->depth - HISTOGRAM_SHIFT); 00228 *thresh = threshold * i + i / 2; 00229 } 00230 else 00231 *thresh = threshold; 00232 DBG (10, "sanei_ir_threshold_yen: threshold %d\n", *thresh); 00233 } 00234 00235 cleanup: 00236 if (P1) 00237 free (P1); 00238 if (P1_sq) 00239 free (P1_sq); 00240 if (P2_sq) 00241 free (P2_sq); 00242 return ret; 00243 } 00244 00245 00246 /* Implements Otsu's thresholding method 00247 */ 00248 SANE_Status 00249 sanei_ir_threshold_otsu (const SANE_Parameters * params, 00250 double * norm_histo, int *thresh) 00251 { 00252 double *cnh = NULL; 00253 double *mean = NULL; 00254 double total_mean; 00255 double bcv, max_bcv; 00256 int first_bin, last_bin; 00257 int threshold, i; 00258 SANE_Status ret = SANE_STATUS_NO_MEM; 00259 00260 DBG (10, "sanei_ir_threshold_otsu\n"); 00261 00262 cnh = sanei_ir_accumulate_norm_histo (norm_histo); 00263 mean = malloc (HISTOGRAM_SIZE * sizeof (double)); 00264 if (!cnh || !mean) 00265 { 00266 DBG (5, "sanei_ir_threshold_otsu: no buffers\n"); 00267 goto cleanup; 00268 } 00269 00270 mean[0] = 0.0; 00271 for (i = 1; i < HISTOGRAM_SIZE; i++) 00272 mean[i] = mean[i - 1] + i * norm_histo[i]; 00273 total_mean = mean[HISTOGRAM_SIZE - 1]; 00274 00275 first_bin = 0; 00276 for (i = 0; i < HISTOGRAM_SIZE; i++) 00277 if (cnh[i] != 0) 00278 { 00279 first_bin = i; 00280 break; 00281 } 00282 last_bin = HISTOGRAM_SIZE - 1; 00283 for (i = HISTOGRAM_SIZE - 1; i >= first_bin; i--) 00284 if (1.0 - cnh[i] != 0) 00285 { 00286 last_bin = i; 00287 break; 00288 } 00289 00290 threshold = INT_MIN; 00291 max_bcv = 0.0; 00292 for (i = first_bin; i <= last_bin; i++) 00293 { 00294 bcv = total_mean * cnh[i] - mean[i]; 00295 bcv *= bcv / (cnh[i] * (1.0 - cnh[i])); 00296 if (max_bcv < bcv) 00297 { 00298 max_bcv = bcv; 00299 threshold = i; 00300 } 00301 } 00302 00303 if (threshold == INT_MIN) 00304 { 00305 DBG (5, "sanei_ir_threshold_otsu: no threshold found\n"); 00306 ret = SANE_STATUS_INVAL; 00307 } 00308 else 00309 { 00310 ret = SANE_STATUS_GOOD; 00311 if (params->depth > 8) 00312 { 00313 i = 1 << (params->depth - HISTOGRAM_SHIFT); 00314 *thresh = threshold * i + i / 2; 00315 } 00316 else 00317 *thresh = threshold; 00318 DBG (10, "sanei_ir_threshold_otsu: threshold %d\n", *thresh); 00319 } 00320 cleanup: 00321 if (cnh) 00322 free (cnh); 00323 if (mean) 00324 free (mean); 00325 return ret; 00326 } 00327 00328 00329 /* Implements a Maximum Entropy thresholding method 00330 */ 00331 SANE_Status 00332 sanei_ir_threshold_maxentropy (const SANE_Parameters * params, 00333 double * norm_histo, int *thresh) 00334 { 00335 int ih, it; 00336 int threshold; 00337 int first_bin; 00338 int last_bin; 00339 double tot_ent, max_ent; /* entropies */ 00340 double ent_back, ent_obj; 00341 double *P1; /* cumulative normalized histogram */ 00342 double *P2; 00343 SANE_Status ret = SANE_STATUS_NO_MEM; 00344 00345 DBG (10, "sanei_ir_threshold_maxentropy\n"); 00346 00347 /* Calculate the cumulative normalized histogram */ 00348 P1 = sanei_ir_accumulate_norm_histo (norm_histo); 00349 P2 = malloc (HISTOGRAM_SIZE * sizeof (double)); 00350 if (!P1 || !P2) 00351 { 00352 DBG (5, "sanei_ir_threshold_maxentropy: no buffers\n"); 00353 goto cleanup; 00354 } 00355 00356 for ( ih = 0; ih < HISTOGRAM_SIZE; ih++ ) 00357 P2[ih] = 1.0 - P1[ih]; 00358 00359 first_bin = 0; 00360 for ( ih = 0; ih < HISTOGRAM_SIZE; ih++ ) 00361 if (P1[ih] != 0) 00362 { 00363 first_bin = ih; 00364 break; 00365 } 00366 last_bin = HISTOGRAM_SIZE - 1; 00367 for ( ih = HISTOGRAM_SIZE - 1; ih >= first_bin; ih-- ) 00368 if (P2[ih] != 0) 00369 { 00370 last_bin = ih; 00371 break; 00372 } 00373 00374 /* Calculate the total entropy each gray-level 00375 * and find the threshold that maximizes it 00376 */ 00377 threshold = INT_MIN; 00378 max_ent = DBL_MIN; 00379 for ( it = first_bin; it <= last_bin; it++ ) 00380 { 00381 /* Entropy of the background pixels */ 00382 ent_back = 0.0; 00383 for ( ih = 0; ih <= it; ih++ ) 00384 if (norm_histo[ih] != 0) 00385 ent_back -= ( norm_histo[ih] / P1[it] ) * log ( norm_histo[ih] / P1[it] ); 00386 00387 /* Entropy of the object pixels */ 00388 ent_obj = 0.0; 00389 for ( ih = it + 1; ih < HISTOGRAM_SIZE; ih++ ) 00390 if (norm_histo[ih] != 0) 00391 ent_obj -= ( norm_histo[ih] / P2[it] ) * log ( norm_histo[ih] / P2[it] ); 00392 00393 /* Total entropy */ 00394 tot_ent = ent_back + ent_obj; 00395 00396 if ( max_ent < tot_ent ) 00397 { 00398 max_ent = tot_ent; 00399 threshold = it; 00400 } 00401 } 00402 00403 if (threshold == INT_MIN) 00404 { 00405 DBG (5, "sanei_ir_threshold_maxentropy: no threshold found\n"); 00406 ret = SANE_STATUS_INVAL; 00407 } 00408 else 00409 { 00410 ret = SANE_STATUS_GOOD; 00411 if (params->depth > 8) 00412 { 00413 it = 1 << (params->depth - HISTOGRAM_SHIFT); 00414 *thresh = threshold * it + it / 2; 00415 } 00416 else 00417 *thresh = threshold; 00418 DBG (10, "sanei_ir_threshold_maxentropy: threshold %d\n", *thresh); 00419 } 00420 00421 cleanup: 00422 if (P1) 00423 free (P1); 00424 if (P2) 00425 free (P2); 00426 return ret; 00427 } 00428 00429 /* Generate gray scale luminance image from separate R, G, B images 00430 */ 00431 SANE_Status 00432 sane_ir_RGB_luminance (SANE_Parameters * params, const SANEI_IR_bufptr * in_img, 00433 SANEI_IR_bufptr * out_img, SANE_Bool scale8) 00434 { 00435 SANEI_IR_bufptr cplane[3]; /* R, G, B gray scale planes */ 00436 SANEI_IR_bufptr outi, dest; 00437 size_t ssize; 00438 int itop, is, i; 00439 00440 if ((params->depth < 8) || (params->depth > 16) || 00441 (params->format != SANE_FRAME_GRAY)) 00442 { 00443 DBG (5, "sane_ir_RGB_luminance: invalid format\n"); 00444 return SANE_STATUS_UNSUPPORTED; 00445 } 00446 00447 for (i = 0; i < 3; i++) 00448 cplane[i] = in_img[i]; 00449 itop = params->pixels_per_line * params->lines; 00450 ssize = itop; 00451 if ((params->depth > 8) && !scale8) 00452 ssize *= 2; 00453 outi.b8 = malloc (ssize); 00454 if (!outi.b8) 00455 { 00456 DBG (5, "sane_ir_to_8bit: can not allocate out_img\n"); 00457 return SANE_STATUS_NO_MEM; 00458 } 00459 dest = outi; 00460 00461 if (params->depth > 8) 00462 { 00463 if (scale8) 00464 { 00465 is = params->depth + 2; 00466 for (i = ssize; i > 0; i--) 00467 *(dest.b8)++ = (218 * (int) *(cplane[0].b16++) + 00468 732 * (int) *(cplane[1].b16++) + 00469 74 * (int) *(cplane[2].b16++)) >> is; 00470 params->depth = 8; 00471 params->bytes_per_line = params->pixels_per_line; 00472 } 00473 else 00474 for (i = ssize; i > 0; i--) 00475 *(dest.b16++) = (218 * (int) *(cplane[0].b16++) + 00476 732 * (int) *(cplane[1].b16++) + 00477 74 * (int) *(cplane[2].b16++)) >> 10; 00478 } 00479 else 00480 { 00481 for (i = ssize; i > 0; i--) 00482 *(dest.b8++) = (218 * (int) *(cplane[0].b8++) + 00483 732 * (int) *(cplane[1].b8++) + 00484 74 * (int) *(cplane[2].b8++)) >> 10; 00485 } 00486 00487 *out_img = outi; 00488 return SANE_STATUS_GOOD; 00489 } 00490 00491 /* Convert image from >8 bit depth to an 8 bit image 00492 */ 00493 SANE_Status 00494 sane_ir_to_8bit (SANE_Parameters * params, const SANEI_IR_bufptr in_img, 00495 SANE_Parameters * out_params, SANEI_IR_bufptr * out_img) 00496 { 00497 SANEI_IR_bufptr outi, src, dest; 00498 size_t ssize; 00499 int i, is; 00500 00501 if ((params->depth < 8) || (params->depth > 16)) 00502 { 00503 DBG (5, "sane_ir_to_8bit: invalid format\n"); 00504 return SANE_STATUS_UNSUPPORTED; 00505 } 00506 ssize = params->pixels_per_line * params->lines; 00507 if (params->format == SANE_FRAME_RGB) 00508 ssize *= 3; 00509 outi.b8 = malloc (ssize); 00510 if (!outi.b8) 00511 { 00512 DBG (5, "sane_ir_to_8bit: can not allocate out_img\n"); 00513 return SANE_STATUS_NO_MEM; 00514 } 00515 00516 if (out_params) 00517 { 00518 memmove (out_params, params, sizeof(SANE_Parameters)); 00519 out_params->bytes_per_line = out_params->pixels_per_line; 00520 if (params->format == SANE_FRAME_RGB) 00521 out_params->bytes_per_line *= 3; 00522 out_params->depth = 8; 00523 } 00524 if (params->depth == 8) 00525 memmove (outi.b8, in_img.b8, ssize); 00526 else 00527 { 00528 dest.b8 = outi.b8; 00529 src.b16 = in_img.b16; 00530 if (params->depth == 16) 00531 { 00532 for (i = ssize; i > 0; i--) 00533 *dest.b8++ = *src.b16++ >> 8; 00534 } 00535 else 00536 { 00537 is = params->depth - 8; 00538 for (i = ssize; i > 0; i--) 00539 *dest.b8++ = *src.b16++ >> is; 00540 } 00541 } 00542 00543 *out_img = outi; 00544 return SANE_STATUS_GOOD; 00545 } 00546 00547 /* allocate and initialize logarithmic lookup table 00548 */ 00549 SANE_Status 00550 sane_ir_ln_table (int len, double **lut_ln) 00551 { 00552 double *llut; 00553 int i; 00554 00555 DBG (10, "sane_ir_ln_table\n"); 00556 00557 llut = malloc (len * sizeof (double)); 00558 if (!llut) 00559 { 00560 DBG (5, "sane_ir_ln_table: no table\n"); 00561 return SANE_STATUS_NO_MEM; 00562 } 00563 llut[0] = 0; 00564 llut[1] = 0; 00565 for (i = 2; i < len; i++) 00566 llut[i] = log ((double) i); 00567 00568 *lut_ln = llut; 00569 return SANE_STATUS_GOOD; 00570 } 00571 00572 00573 /* Reduce red spectral overlap from an infrared image plane 00574 */ 00575 SANE_Status 00576 sane_ir_spectral_clean (const SANE_Parameters * params, double *lut_ln, 00577 const SANEI_IR_bufptr red_data, 00578 SANEI_IR_bufptr ir_data) 00579 { 00580 SANEI_IR_bufptr rptr, iptr; 00581 SANE_Int depth; 00582 double *llut; 00583 double rval, rsum, rrsum; 00584 double risum, rfac, radd; 00585 double *norm_histo; 00586 int64_t isum; 00587 int *calc_buf, *calc_ptr; 00588 int ival, imin, imax; 00589 int itop, len, ssize; 00590 int thresh_low, thresh; 00591 int irand, i; 00592 SANE_Status status; 00593 00594 DBG (10, "sane_ir_spectral_clean\n"); 00595 00596 itop = params->pixels_per_line * params->lines; 00597 calc_buf = malloc (itop * sizeof (int)); /* could save this */ 00598 if (!calc_buf) 00599 { 00600 DBG (5, "sane_ir_spectral_clean: no buffer\n"); 00601 return SANE_STATUS_NO_MEM; 00602 } 00603 00604 depth = params->depth; 00605 len = 1 << depth; 00606 if (lut_ln) 00607 llut = lut_ln; 00608 else 00609 { 00610 status = sane_ir_ln_table (len, &llut); 00611 if (status != SANE_STATUS_GOOD) 00612 return status; 00613 } 00614 00615 /* determine not transparent areas to exclude them later 00616 * TODO: this has not been tested for negatives 00617 */ 00618 thresh_low = INT_MAX; 00619 status = 00620 sanei_ir_create_norm_histogram (params, ir_data, &norm_histo); 00621 if (status != SANE_STATUS_GOOD) 00622 { 00623 DBG (5, "sane_ir_spectral_clean: no buffer\n"); 00624 return SANE_STATUS_NO_MEM; 00625 } 00626 00627 /* TODO: remember only needed if cropping is not ok */ 00628 status = sanei_ir_threshold_maxentropy (params, norm_histo, &thresh); 00629 if (status == SANE_STATUS_GOOD) 00630 thresh_low = thresh; 00631 status = sanei_ir_threshold_otsu (params, norm_histo, &thresh); 00632 if ((status == SANE_STATUS_GOOD) && (thresh < thresh_low)) 00633 thresh_low = thresh; 00634 status = sanei_ir_threshold_yen (params, norm_histo, &thresh); 00635 if ((status == SANE_STATUS_GOOD) && (thresh < thresh_low)) 00636 thresh_low = thresh; 00637 if (thresh_low == INT_MAX) 00638 thresh_low = 0; 00639 else 00640 thresh_low /= 2; 00641 DBG (10, "sane_ir_spectral_clean: low threshold %d\n", thresh_low); 00642 00643 /* calculate linear regression ired (red) from randomly chosen points */ 00644 ssize = itop / 2; 00645 if (SAMPLE_SIZE < ssize) 00646 ssize = SAMPLE_SIZE; 00647 isum = 0; 00648 rsum = rrsum = risum = 0.0; 00649 i = ssize; 00650 while (i > 0) 00651 { 00652 irand = rand () % itop; 00653 if (depth > 8) 00654 { 00655 rval = llut[red_data.b16[irand]]; 00656 ival = ir_data.b16[irand]; 00657 } 00658 else 00659 { 00660 rval = llut[red_data.b8[irand]]; 00661 ival = ir_data.b8[irand]; 00662 } 00663 if (ival > thresh_low) 00664 { 00665 isum += ival; 00666 rsum += rval; 00667 rrsum += rval * rval; 00668 risum += rval * (double) ival; 00669 i--; 00670 } 00671 } 00672 00673 /* "a" in ired = b + a * ln (red) */ 00674 rfac = 00675 ((double) ssize * risum - 00676 rsum * (double) isum) / ((double) ssize * rrsum - rsum * rsum); 00677 radd = ((double) isum - rfac * rsum) / (double) ssize; /* "b" unused */ 00678 00679 DBG (10, "sane_ir_spectral_clean: n = %d, ired(red) = %f * ln(red) + %f\n", 00680 ssize, rfac, radd); 00681 00682 /* now calculate ired' = ired - a * ln (red) */ 00683 imin = INT_MAX; 00684 imax = INT_MIN; 00685 rptr = red_data; 00686 iptr = ir_data; 00687 calc_ptr = calc_buf; 00688 if (depth > 8) 00689 for (i = itop; i > 0; i--) 00690 { 00691 ival = *iptr.b16++ - (int) (rfac * llut[*rptr.b16++] + 0.5); 00692 if (ival > imax) 00693 imax = ival; 00694 if (ival < imin) 00695 imin = ival; 00696 *calc_ptr++ = ival; 00697 } 00698 else 00699 for (i = itop; i > 0; i--) 00700 { 00701 ival = *iptr.b8++ - (int) (rfac * llut[*rptr.b8++] + 0.5); 00702 if (ival > imax) 00703 imax = ival; 00704 if (ival < imin) 00705 imin = ival; 00706 *calc_ptr++ = ival; 00707 } 00708 00709 /* scale the result back into the ired image */ 00710 calc_ptr = calc_buf; 00711 iptr = ir_data; 00712 rfac = (double) (len - 1) / (double) (imax - imin); 00713 if (depth > 8) 00714 for (i = itop; i > 0; i--) 00715 *iptr.b16++ = (double) (*calc_ptr++ - imin) * rfac; 00716 else 00717 for (i = itop; i > 0; i--) 00718 *iptr.b8++ = (double) (*calc_ptr++ - imin) * rfac; 00719 00720 if (!lut_ln) 00721 free (llut); 00722 free (calc_buf); 00723 free (norm_histo); 00724 return SANE_STATUS_GOOD; 00725 } 00726 00727 00728 /* Hopefully fast mean filter 00729 */ 00730 SANE_Status 00731 sanei_ir_filter_mean (const SANE_Parameters * params, 00732 const SANEI_IR_bufptr in_img, SANEI_IR_bufptr out_img, 00733 int win_rows, int win_cols) 00734 { 00735 SANEI_IR_bufptr src, dest; 00736 int num_cols, num_rows; 00737 int itop, iadd, isub; 00738 int ndiv, the_sum; 00739 int nrow, ncol; 00740 int hwr, hwc; 00741 int depth; 00742 int *sum; 00743 int i, j; 00744 00745 DBG (10, "sanei_ir_filter_mean, window: %d x%d\n", win_rows, win_cols); 00746 00747 if (((win_rows & 1) == 0) || ((win_cols & 1) == 0)) 00748 { 00749 DBG (5, "sanei_ir_filter_mean: window even sized\n"); 00750 return SANE_STATUS_INVAL; 00751 } 00752 00753 num_cols = params->pixels_per_line; 00754 num_rows = params->lines; 00755 depth = params->depth; 00756 00757 sum = malloc (num_cols * sizeof (int)); 00758 if (!sum) 00759 { 00760 DBG (5, "sanei_ir_filter_mean: no buffer for sums\n"); 00761 return SANE_STATUS_NO_MEM; 00762 } 00763 dest = out_img; 00764 00765 hwr = win_rows / 2; /* half window sizes */ 00766 hwc = win_cols / 2; 00767 00768 if (depth > 8) /* pre-pre calculation */ 00769 for (j = 0; j < num_cols; j++) 00770 { 00771 sum[j] = 0; 00772 src.b16 = in_img.b16 + j; 00773 for (i = 0; i < hwr; i++) 00774 { 00775 sum[j] += *src.b16; 00776 src.b16 += num_cols; 00777 } 00778 } 00779 else 00780 for (j = 0; j < num_cols; j++) 00781 { 00782 sum[j] = 0; 00783 src.b8 = in_img.b8 + j; 00784 for (i = 0; i < hwr; i++) 00785 { 00786 sum[j] += *src.b8; 00787 src.b8 += num_cols; 00788 } 00789 } 00790 00791 itop = num_rows * num_cols; 00792 iadd = hwr * num_cols; 00793 isub = (hwr - win_rows) * num_cols; 00794 nrow = hwr; 00795 00796 if (depth > 8) 00797 { 00798 for (i = 0; i < num_rows; i++) 00799 { 00800 /* update row sums if possible */ 00801 if (isub >= 0) /* subtract old row */ 00802 { 00803 nrow--; 00804 src.b16 = in_img.b16 + isub; 00805 for (j = 0; j < num_cols; j++) 00806 sum[j] -= *src.b16++; 00807 } 00808 isub += num_cols; 00809 00810 if (iadd < itop) /* add new row */ 00811 { 00812 nrow++; 00813 src.b16 = in_img.b16 + iadd; 00814 for (j = 0; j < num_cols; j++) 00815 sum[j] += *src.b16++; 00816 } 00817 iadd += num_cols; 00818 00819 /* now we do the image columns using only the precalculated sums */ 00820 00821 the_sum = 0; /* precalculation */ 00822 for (j = 0; j < hwc; j++) 00823 the_sum += sum[j]; 00824 ncol = hwc; 00825 00826 /* at the left margin, real index hwc lower */ 00827 for (j = hwc; j < win_cols; j++) 00828 { 00829 ncol++; 00830 the_sum += sum[j]; 00831 *dest.b16++ = the_sum / (ncol * nrow); 00832 } 00833 00834 ndiv = ncol * nrow; 00835 /* in the middle, real index hwc + 1 higher */ 00836 for (j = 0; j < num_cols - win_cols; j++) 00837 { 00838 the_sum -= sum[j]; 00839 the_sum += sum[j + win_cols]; 00840 *dest.b16++ = the_sum / ndiv; 00841 } 00842 00843 /* at the right margin, real index hwc + 1 higher */ 00844 for (j = num_cols - win_cols; j < num_cols - hwc - 1; j++) 00845 { 00846 ncol--; 00847 the_sum -= sum[j]; /* j - hwc - 1 */ 00848 *dest.b16++ = the_sum / (ncol * nrow); 00849 } 00850 } 00851 } 00852 else 00853 { 00854 for (i = 0; i < num_rows; i++) 00855 { 00856 /* update row sums if possible */ 00857 if (isub >= 0) /* subtract old row */ 00858 { 00859 nrow--; 00860 src.b8 = in_img.b8 + isub; 00861 for (j = 0; j < num_cols; j++) 00862 sum[j] -= *src.b8++; 00863 } 00864 isub += num_cols; 00865 00866 if (iadd < itop) /* add new row */ 00867 { 00868 nrow++; 00869 src.b8 = in_img.b8 + iadd; 00870 for (j = 0; j < num_cols; j++) 00871 sum[j] += *src.b8++; 00872 } 00873 iadd += num_cols; 00874 00875 /* now we do the image columns using only the precalculated sums */ 00876 00877 the_sum = 0; /* precalculation */ 00878 for (j = 0; j < hwc; j++) 00879 the_sum += sum[j]; 00880 ncol = hwc; 00881 00882 /* at the left margin, real index hwc lower */ 00883 for (j = hwc; j < win_cols; j++) 00884 { 00885 ncol++; 00886 the_sum += sum[j]; 00887 *dest.b8++ = the_sum / (ncol * nrow); 00888 } 00889 00890 ndiv = ncol * nrow; 00891 /* in the middle, real index hwc + 1 higher */ 00892 for (j = 0; j < num_cols - win_cols; j++) 00893 { 00894 the_sum -= sum[j]; 00895 the_sum += sum[j + win_cols]; 00896 *dest.b8++ = the_sum / ndiv; 00897 } 00898 00899 /* at the right margin, real index hwc + 1 higher */ 00900 for (j = num_cols - win_cols; j < num_cols - hwc - 1; j++) 00901 { 00902 ncol--; 00903 the_sum -= sum[j]; /* j - hwc - 1 */ 00904 *dest.b8++ = the_sum / (ncol * nrow); 00905 } 00906 } 00907 } 00908 return SANE_STATUS_GOOD; 00909 } 00910 00911 00912 /* Find noise by adaptive thresholding 00913 */ 00914 SANE_Status 00915 sanei_ir_filter_madmean (const SANE_Parameters * params, 00916 const SANEI_IR_bufptr in_img, 00917 SANE_Byte ** out_img, int win_size, 00918 int a_val, int b_val) 00919 { 00920 SANEI_IR_bufptr delta_ij, delta_ptr; 00921 SANEI_IR_bufptr mad_ij, mad_ptr; 00922 SANE_Byte *out_ij, *dest8; 00923 double ab_term; 00924 int num_rows, num_cols; 00925 int threshold, itop; 00926 size_t size; 00927 int ival, i; 00928 int depth; 00929 SANE_Status ret = SANE_STATUS_NO_MEM; 00930 00931 DBG (10, "sanei_ir_filter_madmean\n"); 00932 00933 depth = params->depth; 00934 if (depth != 8) 00935 { 00936 a_val = a_val << (depth - 8); 00937 b_val = b_val << (depth - 8); 00938 } 00939 num_cols = params->pixels_per_line; 00940 num_rows = params->lines; 00941 itop = num_rows * num_cols; 00942 00943 size = itop * sizeof (uint8_t); 00944 out_ij = malloc (size); 00945 if (depth > 8) 00946 size = itop * sizeof (uint16_t); 00947 delta_ij.b8 = malloc (size); 00948 mad_ij.b8 = malloc (size); 00949 00950 if (out_ij && delta_ij.b8 && mad_ij.b8) 00951 { 00952 /* get the differences to the local mean */ 00953 mad_ptr = in_img; 00954 if (sanei_ir_filter_mean (params, mad_ptr, delta_ij, win_size, win_size) 00955 == SANE_STATUS_GOOD) 00956 { 00957 delta_ptr = delta_ij; 00958 if (depth > 8) 00959 for (i = 0; i < itop; i++) 00960 { 00961 ival = *mad_ptr.b16++ - *delta_ptr.b16; 00962 *delta_ptr.b16++ = abs (ival); 00963 } 00964 else 00965 for (i = 0; i < itop; i++) 00966 { 00967 ival = *mad_ptr.b8++ - *delta_ptr.b8; 00968 *delta_ptr.b8++ = abs (ival); 00969 } 00970 /* make the second filtering window a bit larger */ 00971 win_size = MAD_WIN2_SIZE(win_size); 00972 /* and get the local mean differences */ 00973 if (sanei_ir_filter_mean 00974 (params, delta_ij, mad_ij, win_size, 00975 win_size) == SANE_STATUS_GOOD) 00976 { 00977 mad_ptr = mad_ij; 00978 delta_ptr = delta_ij; 00979 dest8 = out_ij; 00980 /* construct the noise map */ 00981 ab_term = (b_val - a_val) / (double) b_val; 00982 if (depth > 8) 00983 for (i = 0; i < itop; i++) 00984 { 00985 /* by calculating the threshold */ 00986 ival = *mad_ptr.b16++; 00987 if (ival >= b_val) /* outlier */ 00988 threshold = a_val; 00989 else 00990 threshold = a_val + (double) ival *ab_term; 00991 /* above threshold is noise, indicated by 0 */ 00992 if (*delta_ptr.b16++ >= threshold) 00993 *dest8++ = 0; 00994 else 00995 *dest8++ = 255; 00996 } 00997 else 00998 for (i = 0; i < itop; i++) 00999 { 01000 /* by calculating the threshold */ 01001 ival = *mad_ptr.b8++; 01002 if (ival >= b_val) /* outlier */ 01003 threshold = a_val; 01004 else 01005 threshold = a_val + (double) ival *ab_term; 01006 /* above threshold is noise, indicated by 0 */ 01007 if (*delta_ptr.b8++ >= threshold) 01008 *dest8++ = 0; 01009 else 01010 *dest8++ = 255; 01011 } 01012 *out_img = out_ij; 01013 ret = SANE_STATUS_GOOD; 01014 } 01015 } 01016 } 01017 else 01018 DBG (5, "sanei_ir_filter_madmean: Cannot allocate buffers\n"); 01019 01020 free (mad_ij.b8); 01021 free (delta_ij.b8); 01022 return ret; 01023 } 01024 01025 01026 /* Add dark pixels to mask from static threshold 01027 */ 01028 void 01029 sanei_ir_add_threshold (const SANE_Parameters * params, 01030 const SANEI_IR_bufptr in_img, 01031 SANE_Byte * mask_img, int threshold) 01032 { 01033 SANEI_IR_bufptr in_ptr; 01034 SANE_Byte *mask_ptr; 01035 int itop, i; 01036 01037 DBG (10, "sanei_ir_add_threshold\n"); 01038 01039 itop = params->pixels_per_line * params->lines; 01040 in_ptr = in_img; 01041 mask_ptr = mask_img; 01042 01043 if (params->depth > 8) 01044 for (i = itop; i > 0; i--) 01045 { 01046 if (*in_ptr.b16++ <= threshold) 01047 *mask_ptr = 0; 01048 mask_ptr++; 01049 } 01050 else 01051 for (i = itop; i > 0; i--) 01052 { 01053 if (*in_ptr.b8++ <= threshold) 01054 *mask_ptr = 0; 01055 mask_ptr++; 01056 } 01057 } 01058 01059 01060 /* Calculate minimal Manhattan distances for an image mask 01061 */ 01062 void 01063 sane_ir_manhattan_dist (const SANE_Parameters * params, 01064 const SANE_Byte * mask_img, unsigned int *dist_map, 01065 unsigned int *idx_map, unsigned int erode) 01066 { 01067 const SANE_Byte *mask; 01068 unsigned int *index, *manhattan; 01069 int rows, cols, itop; 01070 int i, j; 01071 01072 DBG (10, "sane_ir_manhattan_dist\n"); 01073 01074 if (erode != 0) 01075 erode = 255; 01076 01077 /* initialize maps */ 01078 cols = params->pixels_per_line; 01079 rows = params->lines; 01080 itop = rows * cols; 01081 mask = mask_img; 01082 manhattan = dist_map; 01083 index = idx_map; 01084 for (i = 0; i < itop; i++) 01085 { 01086 *manhattan++ = *mask++; 01087 *index++ = i; 01088 } 01089 01090 /* traverse from top left to bottom right */ 01091 manhattan = dist_map; 01092 index = idx_map; 01093 for (i = 0; i < rows; i++) 01094 for (j = 0; j < cols; j++) 01095 { 01096 if (*manhattan == erode) 01097 { 01098 /* take original, distance = 0, index stays the same */ 01099 *manhattan = 0; 01100 } 01101 else 01102 { 01103 /* assume maximal distance to clean pixel */ 01104 *manhattan = cols + rows; 01105 /* or one further away than pixel to the top */ 01106 if (i > 0) 01107 if (manhattan[-cols] + 1 < *manhattan) 01108 { 01109 *manhattan = manhattan[-cols] + 1; 01110 *index = index[-cols]; /* index follows */ 01111 } 01112 /* or one further away than pixel to the left */ 01113 if (j > 0) 01114 { 01115 if (manhattan[-1] + 1 < *manhattan) 01116 { 01117 *manhattan = manhattan[-1] + 1; 01118 *index = index[-1]; /* index follows */ 01119 } 01120 if (manhattan[-1] + 1 == *manhattan) 01121 if (rand () % 2 == 0) /* chose index */ 01122 *index = index[-1]; 01123 } 01124 } 01125 manhattan++; 01126 index++; 01127 } 01128 01129 /* traverse from bottom right to top left */ 01130 manhattan = dist_map + itop - 1; 01131 index = idx_map + itop - 1; 01132 for (i = rows - 1; i >= 0; i--) 01133 for (j = cols - 1; j >= 0; j--) 01134 { 01135 if (i < rows - 1) 01136 { 01137 /* either what we had on the first pass 01138 or one more than the pixel to the bottm */ 01139 if (manhattan[+cols] + 1 < *manhattan) 01140 { 01141 *manhattan = manhattan[+cols] + 1; 01142 *index = index[+cols]; /* index follows */ 01143 } 01144 if (manhattan[+cols] + 1 == *manhattan) 01145 if (rand () % 2 == 0) /* chose index */ 01146 *index = index[+cols]; 01147 } 01148 if (j < cols - 1) 01149 { 01150 /* or one more than pixel to the right */ 01151 if (manhattan[1] + 1 < *manhattan) 01152 { 01153 *manhattan = manhattan[1] + 1; 01154 *index = index[1]; /* index follows */ 01155 } 01156 if (manhattan[1] + 1 == *manhattan) 01157 if (rand () % 2 == 0) /* chose index */ 01158 *index = index[1]; 01159 } 01160 manhattan--; 01161 index--; 01162 } 01163 } 01164 01165 01166 /* dilate or erode a mask image */ 01167 01168 void 01169 sane_ir_dilate (const SANE_Parameters * params, SANE_Byte * mask_img, 01170 unsigned int *dist_map, unsigned int *idx_map, int by) 01171 { 01172 SANE_Byte *mask; 01173 unsigned int *manhattan; 01174 unsigned int erode; 01175 unsigned int thresh; 01176 int i, itop; 01177 01178 DBG (10, "sane_ir_dilate\n"); 01179 01180 if (by == 0) 01181 return; 01182 if (by > 0) 01183 { 01184 erode = 0; 01185 thresh = by; 01186 } 01187 else 01188 { 01189 erode = 1; 01190 thresh = -by; 01191 } 01192 01193 itop = params->pixels_per_line * params->lines; 01194 mask = mask_img; 01195 sane_ir_manhattan_dist (params, mask_img, dist_map, idx_map, erode); 01196 01197 manhattan = dist_map; 01198 for (i = 0; i < itop; i++) 01199 { 01200 if (*manhattan++ <= thresh) 01201 *mask++ = 0; 01202 else 01203 *mask++ = 255; 01204 } 01205 01206 return; 01207 } 01208 01209 01210 /* Suggest cropping for dark margins of positive film 01211 */ 01212 void 01213 sanei_ir_find_crop (const SANE_Parameters * params, 01214 unsigned int * dist_map, int inner, int * edges) 01215 { 01216 int width = params->pixels_per_line; 01217 int height = params->lines; 01218 uint64_t sum_x, sum_y, n; 01219 int64_t sum_xx, sum_xy; 01220 double a, b, mami; 01221 unsigned int *src; 01222 int off1, off2, inc, wh, i, j; 01223 01224 DBG (10, "sanei_ir_find_crop\n"); 01225 01226 /* loop through top, bottom, left, right */ 01227 for (j = 0; j < 4; j++) 01228 { 01229 if (j < 2) /* top, bottom */ 01230 { 01231 off1 = width / 8; /* only middle 3/4 */ 01232 off2 = width - off1; 01233 n = width - 2 * off1; 01234 src = dist_map + off1; /* first row */ 01235 inc = 1; 01236 wh = width; 01237 if (j == 1) /* last row */ 01238 src += (height - 1) * width; 01239 } 01240 else /* left, right */ 01241 { 01242 off1 = height / 8; /* only middle 3/4 */ 01243 off2 = height - off1; 01244 n = height - 2 * off1; 01245 src = dist_map + (off1 * width); /* first column */ 01246 inc = width; 01247 wh = height; 01248 if (j == 3) 01249 src += width - 1; /* last column */ 01250 } 01251 01252 /* calculate linear regression */ 01253 sum_x = 0; sum_y = 0; 01254 sum_xx = 0; sum_xy = 0; 01255 for (i = off1; i < off2; i++) 01256 { 01257 sum_x += i; 01258 sum_y += *src; 01259 sum_xx += i * i; 01260 sum_xy += i * (*src); 01261 src += inc; 01262 } 01263 b = ((double) n * (double) sum_xy - (double) sum_x * (double) sum_y) 01264 / ((double) n * (double) sum_xx - (double) sum_x * (double) sum_x); 01265 a = ((double) sum_y - b * (double) sum_x) / (double) n; 01266 01267 DBG (10, "sanei_ir_find_crop: y = %f + %f * x\n", a, b); 01268 01269 /* take maximal/minimal value from either side */ 01270 mami = a + b * (wh - 1); 01271 if (inner) 01272 { 01273 if (a > mami) 01274 mami = a; 01275 } 01276 else 01277 { 01278 if (a < mami) 01279 mami = a; 01280 } 01281 edges[j] = mami + 0.5; 01282 } 01283 edges[1] = height - edges[1]; 01284 edges[3] = width - edges[3]; 01285 01286 DBG (10, "sanei_ir_find_crop: would crop at top: %d, bot: %d, left %d, right %d\n", 01287 edges[0], edges[1], edges[2], edges[3]); 01288 01289 return; 01290 } 01291 01292 01293 /* Dilate clean image parts into dirty ones and smooth 01294 */ 01295 SANE_Status 01296 sanei_ir_dilate_mean (const SANE_Parameters * params, 01297 SANEI_IR_bufptr * in_img, 01298 SANE_Byte * mask_img, 01299 int dist_max, int expand, int win_size, 01300 SANE_Bool smooth, int inner, 01301 int *crop) 01302 { 01303 SANEI_IR_bufptr color; 01304 SANEI_IR_bufptr plane; 01305 unsigned int *dist_map, *manhattan; 01306 unsigned int *idx_map, *index; 01307 int depth, dist; 01308 int rows, cols; 01309 int k, i, itop; 01310 SANE_Status ret = SANE_STATUS_NO_MEM; 01311 01312 DBG (10, "sanei_ir_dilate_mean\n"); 01313 01314 depth = params->depth; 01315 cols = params->pixels_per_line; 01316 rows = params->lines; 01317 itop = rows * cols; 01318 idx_map = malloc (itop * sizeof (unsigned int)); 01319 dist_map = malloc (itop * sizeof (unsigned int)); 01320 if (depth > 8) 01321 plane.b16 = malloc (itop * sizeof (uint16_t)); 01322 else 01323 plane.b8 = malloc (itop * sizeof (uint8_t)); 01324 01325 if (!idx_map || !dist_map || !plane.b8) 01326 DBG (5, "sanei_ir_dilate_mean: Cannot allocate buffers\n"); 01327 else 01328 { 01329 /* expand dirty regions into their half dirty surround*/ 01330 if (expand > 0) 01331 sane_ir_dilate (params, mask_img, dist_map, idx_map, expand); 01332 /* for dirty pixels determine the closest clean ones */ 01333 sane_ir_manhattan_dist (params, mask_img, dist_map, idx_map, 1); 01334 01335 /* use the distance map to find how to crop dark edges */ 01336 if (crop) 01337 sanei_ir_find_crop (params, dist_map, inner, crop); 01338 01339 /* replace dirty pixels */ 01340 for (k = 0; k < 3; k++) 01341 { 01342 manhattan = dist_map; 01343 index = idx_map; 01344 color = in_img[k]; 01345 /* first replacement */ 01346 if (depth > 8) 01347 for (i = 0; i < itop; i++) 01348 { 01349 dist = *manhattan++; 01350 if ((dist != 0) && (dist <= dist_max)) 01351 color.b16[i] = color.b16[index[i]]; 01352 } 01353 else 01354 for (i = 0; i < itop; i++) 01355 { 01356 dist = *manhattan++; 01357 if ((dist != 0) && (dist <= dist_max)) 01358 color.b8[i] = color.b8[index[i]]; 01359 } 01360 /* adapt pixels to their new surround and 01361 * smooth the whole image or the replaced pixels only */ 01362 ret = 01363 sanei_ir_filter_mean (params, color, plane, win_size, win_size); 01364 if (ret != SANE_STATUS_GOOD) 01365 break; 01366 else 01367 if (smooth) 01368 { 01369 /* a second mean results in triangular blur */ 01370 ret = 01371 sanei_ir_filter_mean (params, plane, color, win_size, 01372 win_size); 01373 if (ret != SANE_STATUS_GOOD) 01374 break; 01375 } 01376 else 01377 { 01378 /* replace with smoothened pixels only */ 01379 manhattan = dist_map; 01380 if (depth > 8) 01381 for (i = 0; i < itop; i++) 01382 { 01383 dist = *manhattan++; 01384 if ((dist != 0) && (dist <= dist_max)) 01385 color.b16[i] = plane.b16[i]; 01386 } 01387 else 01388 for (i = 0; i < itop; i++) 01389 { 01390 dist = *manhattan++; 01391 if ((dist != 0) && (dist <= dist_max)) 01392 color.b8[i] = plane.b8[i]; 01393 } 01394 } 01395 } 01396 } 01397 free (plane.b8); 01398 free (dist_map); 01399 free (idx_map); 01400 01401 return ret; 01402 } 01403