/* * For each i in [0, HISTSIZE), hist[i] is the number of occurrences of the * value i. Return a value in [0, HISTSIZE) weighted heavily toward the * most frequent values in the histogram. * * Assuming that hist_max is the maximum number of occurrences for any * one value in the histogram, the weight given to each value i is * * weight = (hist[i] / hist_max)^exponent * * (i.e. the normalized histogram frequency raised to some power) */ static inline guchar weighted_average_value (gint hist[HISTSIZE], gfloat exponent) { gint i; gint hist_max = 1; gint exponent_int = 0; gfloat sum = 0.0; gfloat div = 1.0e-6; gint value; for (i = 0; i < HISTSIZE; i++) hist_max = MAX (hist_max, hist[i]); if ((exponent - floor (exponent)) < 0.001 && exponent <= 255.0) exponent_int = (gint) exponent; for (i = 0; i < HISTSIZE; i++) { gfloat ratio = (gfloat) hist[i] / (gfloat) hist_max; gfloat weight; if (exponent_int) weight = fast_powf (ratio, exponent_int); else weight = pow (ratio, exponent); sum += weight * (gfloat) i; div += weight; } value = (gint) (sum / div); return (guchar) CLAMP0255 (value); }
/* * For each i in [0, HISTSIZE), hist[i] is the number of occurrences of * pixels with intensity i. hist_rgb[][i] is the average color of those * pixels with intensity i, but with each channel multiplied by hist[i]. * Write to dest a pixel whose color is a weighted average of all the * colors in hist_rgb[][], biased heavily toward those with the most * frequently-occurring intensities (as noted in hist[]). * * The weight formula is the same as in weighted_average_value(). */ static inline void weighted_average_color (gint hist[HISTSIZE], gint hist_rgb[4][HISTSIZE], gfloat exponent, guchar *dest, gint bpp) { gint i, b; gint hist_max = 1; gint exponent_int = 0; gfloat div = 1.0e-6; gfloat color[4] = { 0.0, 0.0, 0.0, 0.0 }; for (i = 0; i < HISTSIZE; i++) hist_max = MAX (hist_max, hist[i]); if ((exponent - floor (exponent)) < 0.001 && exponent <= 255.0) exponent_int = (gint) exponent; for (i = 0; i < HISTSIZE; i++) { gfloat ratio = (gfloat) hist[i] / (gfloat) hist_max; gfloat weight; if (exponent_int) weight = fast_powf (ratio, exponent_int); else weight = pow (ratio, exponent); if (hist[i] > 0) for (b = 0; b < bpp; b++) color[b] += weight * (gfloat) hist_rgb[b][i] / (gfloat) hist[i]; div += weight; } for (b = 0; b < bpp; b++) { gint c = (gint) (color[b] / div); dest[b] = (guchar) CLAMP0255 (c); } }
void imlib_gamma_corr(image_t *img, float gamma, float contrast, float brightness) { gamma = IM_DIV(1.0, gamma); switch(img->bpp) { case IMAGE_BPP_BINARY: { float pScale = COLOR_BINARY_MAX - COLOR_BINARY_MIN; float pDiv = 1 / pScale; int *p_lut = fb_alloc((COLOR_BINARY_MAX - COLOR_BINARY_MIN + 1) * sizeof(int)); for (int i = COLOR_BINARY_MIN; i <= COLOR_BINARY_MAX; i++) { int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale; p_lut[i] = IM_MIN(IM_MAX(p , COLOR_BINARY_MIN), COLOR_BINARY_MAX); } for (int y = 0, yy = img->h; y < yy; y++) { uint32_t *data = IMAGE_COMPUTE_BINARY_PIXEL_ROW_PTR(img, y); for (int x = 0, xx = img->w; x < xx; x++) { int dataPixel = IMAGE_GET_BINARY_PIXEL_FAST(data, x); int p = p_lut[dataPixel]; IMAGE_PUT_BINARY_PIXEL_FAST(data, x, p); } } fb_free(); break; } case IMAGE_BPP_GRAYSCALE: { float pScale = COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN; float pDiv = 1 / pScale; int *p_lut = fb_alloc((COLOR_GRAYSCALE_MAX - COLOR_GRAYSCALE_MIN + 1) * sizeof(int)); for (int i = COLOR_GRAYSCALE_MIN; i <= COLOR_GRAYSCALE_MAX; i++) { int p = ((fast_powf(i * pDiv, gamma) * contrast) + brightness) * pScale; p_lut[i] = IM_MIN(IM_MAX(p , COLOR_GRAYSCALE_MIN), COLOR_GRAYSCALE_MAX); } for (int y = 0, yy = img->h; y < yy; y++) { uint8_t *data = IMAGE_COMPUTE_GRAYSCALE_PIXEL_ROW_PTR(img, y); for (int x = 0, xx = img->w; x < xx; x++) { int dataPixel = IMAGE_GET_GRAYSCALE_PIXEL_FAST(data, x); int p = p_lut[dataPixel]; IMAGE_PUT_GRAYSCALE_PIXEL_FAST(data, x, p); } } fb_free(); break; } case IMAGE_BPP_RGB565: { float rScale = COLOR_R5_MAX - COLOR_R5_MIN; float gScale = COLOR_G6_MAX - COLOR_G6_MIN; float bScale = COLOR_B5_MAX - COLOR_B5_MIN; float rDiv = 1 / rScale; float gDiv = 1 / gScale; float bDiv = 1 / bScale; int *r_lut = fb_alloc((COLOR_R5_MAX - COLOR_R5_MIN + 1) * sizeof(int)); int *g_lut = fb_alloc((COLOR_G6_MAX - COLOR_G6_MIN + 1) * sizeof(int)); int *b_lut = fb_alloc((COLOR_B5_MAX - COLOR_B5_MIN + 1) * sizeof(int)); for (int i = COLOR_R5_MIN; i <= COLOR_R5_MAX; i++) { int r = ((fast_powf(i * rDiv, gamma) * contrast) + brightness) * rScale; r_lut[i] = IM_MIN(IM_MAX(r , COLOR_R5_MIN), COLOR_R5_MAX); } for (int i = COLOR_G6_MIN; i <= COLOR_G6_MAX; i++) { int g = ((fast_powf(i * gDiv, gamma) * contrast) + brightness) * gScale; g_lut[i] = IM_MIN(IM_MAX(g , COLOR_G6_MIN), COLOR_G6_MAX); } for (int i = COLOR_B5_MIN; i <= COLOR_B5_MAX; i++) { int b = ((fast_powf(i * bDiv, gamma) * contrast) + brightness) * bScale; b_lut[i] = IM_MIN(IM_MAX(b , COLOR_B5_MIN), COLOR_B5_MAX); } for (int y = 0, yy = img->h; y < yy; y++) { uint16_t *data = IMAGE_COMPUTE_RGB565_PIXEL_ROW_PTR(img, y); for (int x = 0, xx = img->w; x < xx; x++) { int dataPixel = IMAGE_GET_RGB565_PIXEL_FAST(data, x); int r = r_lut[COLOR_RGB565_TO_R5(dataPixel)]; int g = g_lut[COLOR_RGB565_TO_G6(dataPixel)]; int b = b_lut[COLOR_RGB565_TO_B5(dataPixel)]; IMAGE_PUT_RGB565_PIXEL_FAST(data, x, COLOR_R5_G6_B5_TO_RGB565(r, g, b)); } } fb_free(); fb_free(); fb_free(); break; } default: { break; } } }