1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393
|
/** @file sanei_ir.h
*
* This file provides an interface to the
* sanei_ir functions for utilizing the infrared plane
*
* Copyright (C) 2012 Michael Rickmann <mrickma@gwdg.de>
*
* This file is part of the SANE package.
*
* Essentially three things have to be done:
* - 1) reduce red spectral overlap from the infrared (ired) plane
* - 2) find the dirt
* - 3) replace the dirt
*
* - 1) is mainly addressed by sanei_ir_spectral_clean
* - 2) by sanei_ir_filter_madmean
* - 3) by sanei_ir_dilate_mean
*/
#ifndef SANEI_IR_H
#define SANEI_IR_H
#include <stdint.h>
#define SAMPLE_SIZE 40000 /**< maximal for random sampling */
#define HISTOGRAM_SHIFT 8 /**< standard histogram size */
#define HISTOGRAM_SIZE (1 << HISTOGRAM_SHIFT)
#define SAFE_LOG(x) ( ((x) > 0.0) ? log ((x)) : (0.0) ) /**< define log (0) = 0 */
#define MAD_WIN2_SIZE(x) ( (((x) * 4) / 3) | 1 ) /**< MAD filter: 2nd window size */
typedef uint16_t SANE_Uint;
/**
* @brief Pointer to access values of different bit depths
*/
typedef union
{
uint8_t *b8; /**< <= 8 bits */
uint16_t *b16; /**< > 8, <= 16 bits */
}
SANEI_IR_bufptr;
/** Initialize sanei_ir.
*
* Call this before any other sanei_ir function.
*/
extern void sanei_ir_init (void);
/**
* @brief Create the normalized histogram of a grayscale image
*
* @param[in] params describes image
* @param[in] img_data image pointer { grayscale }
* @param[out] histogram an array of double with histogram
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* @note
* histogram has to be freed by calling routine
*/
extern SANE_Status
sanei_ir_create_norm_histogram (const SANE_Parameters * params,
const SANE_Uint *img_data,
double ** histogram);
/**
* @brief Implements Yen's thresholding method
*
* @param[in] params describes image
* @param[in] norm_histo points to a normalized histogram
* @param[out] thresh found threshold
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* -# Yen J.C., Chang F.J., and Chang S. (1995) "A New Criterion
* for Automatic Multilevel Thresholding" IEEE Trans. on Image
* Processing, 4(3): 370-378
* -# Sezgin M. and Sankur B. (2004) "Survey over Image Thresholding
* Techniques and Quantitative Performance Evaluation" Journal of
* Electronic Imaging, 13(1): 146-165
* -# M. Emre Celebi, 06.15.2007, fourier_0.8,
* http://sourceforge.net/projects/fourier-ipal/
* -# ImageJ Multithresholder plugin,
* http://rsbweb.nih.gov/ij/plugins/download/AutoThresholder.java
*/
extern SANE_Status
sanei_ir_threshold_yen (const SANE_Parameters * params,
double * norm_histo, int *thresh);
/**
* @brief Implements Otsu's thresholding method
*
* @param[in] params describes image
* @param[in] norm_histo points to a normalized histogram
* @param[out] thresh found threshold
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* -# Otsu N. (1979) "A Threshold Selection Method from Gray Level Histograms"
* IEEE Trans. on Systems, Man and Cybernetics, 9(1): 62-66
* -# M. Emre Celebi, 06.15.2007, fourier_0.8
* http://sourceforge.net/projects/fourier-ipal/
*/
extern SANE_Status
sanei_ir_threshold_otsu (const SANE_Parameters * params,
double * norm_histo, int *thresh);
/**
* @brief Implements a Maximum Entropy thresholding method
*
* @param[in] params describes image
* @param[in] norm_histo points to a normalized histogram
* @param[out] thresh found threshold
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* -# Kapur J.N., Sahoo P.K., and Wong A.K.C. (1985) "A New Method for
* Gray-Level Picture Thresholding Using the Entropy of the Histogram"
* Graphical Models and Image Processing, 29(3): 273-285
* -# M. Emre Celebi, 06.15.2007, fourier_0.8
* http://sourceforge.net/projects/fourier-ipal/
* -# ImageJ Multithresholder plugin,
* http://rsbweb.nih.gov/ij/plugins/download/AutoThresholder.java
*/
extern SANE_Status
sanei_ir_threshold_maxentropy (const SANE_Parameters * params,
double * norm_histo, int *thresh);
/**
* @brief Generate gray scale luminance image from separate R, G, B images
*
* @param params points to image description
* @param[in] in_img pointer to at least 3 planes of image data
* @param[out] out_img newly allocated image
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
* - SANE_STATUS_UNSUPPORTED - wrong input bit depth
*
* @note out_img has to be freed by the calling routine.
* @note on input params describe a single color plane,
* on output params are updated if image depth is scaled
*/
SANE_Status
sanei_ir_RGB_luminance (SANE_Parameters * params, const SANE_Uint **in_img,
SANE_Uint **out_img);
/**
* @brief Convert image from >8 bit depth to an 8 bit image.
*
* @param[in] params pimage description
* @param[in] in_img points to input image data
* @param[out] out_params if != NULL
* receives description of new image
* @param[out] out_img newly allocated 8-bit image
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
* - SANE_STATUS_UNSUPPORTED - wrong input bit depth
*
* @note
* out_img has to be freed by the calling routine,
*/
extern SANE_Status
sanei_ir_to_8bit (SANE_Parameters * params, const SANE_Uint *in_img,
SANE_Parameters * out_params, SANE_Uint **out_img);
/**
* @brief Allocate and initialize logarithmic lookup table
*
* @param[in] len length of table, usually 1 << depth
* @param[out] lut_ln address of pointer to allocated table
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* @note natural logarithms are provided
*/
SANE_Status sanei_ir_ln_table (int len, double **lut_ln);
/**
* @brief Reduces red spectral overlap from an infrared image plane
*
* @param[in] params pointer to image description
* @param[in] lut_ln pointer lookup table
* if NULL it is dynamically handled
* @param[in] red_data pointer to red image plane
* @param ir_data pointer to ir image plane
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* This routine is based on the observation that the relation between the infrared value
* ired and the red value red of an image point can be described by ired = b + a * ln (red).
* First points are randomly sampled to calculate the linear regression coefficient a.
* Then ired' = ired - a * ln (red) is calculated for each pixel. Finally, the ir' image
* is scaled between 0 and maximal value. For the logarithms a lookup table is used.
* Negative films show very little spectral overlap but positive film usually has to be
* cleaned. As we do a statistical measure of the film here dark margins and lumps of
* dirt have to be excluded.
*
* @note original ired data are replaced by the cleaned ones
*/
extern SANE_Status
sanei_ir_spectral_clean (const SANE_Parameters * params, double *lut_ln,
const SANE_Uint *red_data,
SANE_Uint *ir_data);
/**
* @brief Optimized mean filter
*
* @param[in] params pointer to image description
* @param[in] in_img Pointer to grey scale image data
* @param[out] out_img Pointer to grey scale image data
* @param[in] win_rows Height of filtering window, odd
* @param[in] win_cols Width of filtering window, odd
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
* - SANE_STATUS_INVAL - wrong window size
*
* @note At the image margins the size of the filtering window
* is adapted. So there is no need to pad the image.
* @note Memory for the output image has to be allocated before
*/
extern SANE_Status
sanei_ir_filter_mean (const SANE_Parameters * params,
const SANE_Uint *in_img, SANE_Uint *out_img,
int win_rows, int win_cols);
/**
* @brief Find noise by adaptive thresholding
*
* @param[in] params pointer to image description
* @param[in] in_img pointer to grey scale image
* @param[out] out_img address of pointer to newly allocated binary image
* @param[in] win_size Size of filtering window
* @param[in] a_val Parameter, below is definitely clean
* @param[in] b_val Parameter, above is definitely noisy
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* This routine follows the concept of Crnojevic's MAD (median of the absolute deviations
* from the median) filter. The first median filter step is replaced with a mean filter.
* The dirty pixels which we wish to remove are always darker than the real signal. But
* at high resolutions the scanner may generate some noise and the ired cleaning step can
* reverse things. So a maximum filter will not do.
* The second median is replaced by a mean filter to reduce computation time. In spite of
* these changes Crnojevic's recommendations for the choice of the parameters "a" and "b"
* are still valid when scaled to the color depth.
*
* @reco Crnojevic recommends 10 < a_val < 30 and 50 < b_val < 100 for 8 bit color depth
*
* @note a_val, b_val are scaled by the routine according to bit depth
* @note "0" in the mask output is regarded "dirty", 255 "clean"
*
* -# Crnojevic V. (2005) "Impulse Noise Filter with Adaptive Mad-Based Threshold"
* Proc. of the IEEE Int. Conf. on Image Processing, 3: 337-340
*/
extern SANE_Status
sanei_ir_filter_madmean (const SANE_Parameters * params,
const SANE_Uint *in_img,
SANE_Uint ** out_img, int win_size,
int a_val, int b_val);
/**
* @brief Add dark pixels to mask from static threshold
*
* @param[in] params pointer to image description
* @param[in] in_img pointer to grey scale image
* @param mask_img pointer to binary image (0, 255)
* @param[in] threshold below which the pixel is set 0
*/
void
sanei_ir_add_threshold (const SANE_Parameters * params,
const SANE_Uint *in_img,
SANE_Uint * mask_img, int threshold);
/**
* @brief Calculates minimal Manhattan distances for an image mask
*
* @param[in] params pointer to image description
* @param[in] mask_img pointer to binary image (0, 255)
* @param[out] dist_map integer pointer to map of closest distances
* @param[out] idx_map integer pointer to indices of closest pixels
* @param[in] erode == 0: closest pixel has value 0, != 0: is 255
*
* manhattan_dist takes a mask image consisting of 0 or 255 values. Given that
* a 0 represents a dirty pixel and erode != 0, manhattan_dist will calculate the
* shortest distance to a clean (255) pixel and record which pixel that was so
* that the clean parts of the image can be dilated into the dirty ones. Thresholding
* can be done on the distance. Conversely, if erode == 0 the distance of a clean
* pixel to the closest dirty one is calculated which can be used to dilate the mask.
*
* @ref extended and C version of
* http://ostermiller.org/dilate_and_erode.html
*/
void
sanei_ir_manhattan_dist (const SANE_Parameters * params,
const SANE_Uint * mask_img, unsigned int *dist_map,
unsigned int *idx_map, unsigned int erode);
/**
* @brief Dilate or erode a mask image
*
* @param[in] params pointer to image description
* @param mask_img pointer to binary image (0, 255)
* @param dist_map integer pointer to map of closest distances
* @param idx_map integer pointer to indices of closest pixels
* @param[in] by number of pixels, > 0 dilate, < 0 erode
*
* @note by > 0 will enlarge the 0 valued area
*/
void
sanei_ir_dilate (const SANE_Parameters * params, SANE_Uint * mask_img,
unsigned int *dist_map, unsigned int *idx_map, int by);
/**
* @brief Suggest cropping for dark margins of positive film
*
* @param[in] params pointer to image description
* @param[in] dist_map integer pointer to map of closest distances
* @param[in] inner crop within (!=0) or outside (==0) the image's edges
* @param[out] edges pointer to array holding top, bottom, left
* and right edges
*
* The distance map as calculated by sanei_ir_manhattan_dist contains
* distances to the next clean pixel. Dark margins are detected as dirt.
* So the first/last rows/columns tell us how to crop. This is rather
* fast if the distance map has been calculated anyhow.
*/
void
sanei_ir_find_crop (const SANE_Parameters * params,
unsigned int * dist_map, int inner, int * edges);
/**
* @brief Dilate clean image parts into dirty ones and smooth int inner,
*
* @param[in] params pointer to image description
* @param in_img array of pointers to color planes of image
* @param[in] mask_img pointer to dirt mask image
* @param[in] dist_max threshold up to which dilation is done
* @param[in] expand the dirt mask before replacing the pixels
* @param[in] win_size size of adaptive mean filtering window
* @param[in] smooth triangular filter whole image for grain removal
* @param[in] inner find crop within or outside the image's edges
* @param[out] crop array of 4 integers, if non-NULL, top, bottom,
* left and right values for cropping are returned.
*
* @return
* - SANE_STATUS_GOOD - success
* - SANE_STATUS_NO_MEM - if out of memory
*
* The main purpose of this routine is to replace dirty pixels.
* As spin-off it obtains half of what is needed for film grain
* smoothening and most of how to crop positive film.
* To speed things up these functions are also implemented.
*/
SANE_Status
sanei_ir_dilate_mean (const SANE_Parameters * params,
SANE_Uint **in_img,
SANE_Uint *mask_img,
int dist_max, int expand, int win_size,
SANE_Bool smooth, int inner,
int *crop);
#endif /* not SANEI_IR_H */
|