2 * Image Library -- Color Spaces
4 * (c) 2006 Pavel Charvat <pchar@ucw.cz>
6 * This software may be freely distributed and used according to the terms
7 * of the GNU Lesser General Public License.
12 #include "sherlock/sherlock.h"
14 #include "images/images.h"
15 #include "images/color.h"
17 struct color color_black = { .color_space = COLOR_SPACE_GRAYSCALE };
18 struct color color_white = { .c = { 255 }, .color_space = COLOR_SPACE_GRAYSCALE };
21 color_put_grayscale(byte *dest, struct color *color)
23 switch (color->color_space)
25 case COLOR_SPACE_GRAYSCALE:
26 dest[0] = color->c[0];
29 dest[0] = rgb_to_gray_func(color->c[0], color->c[1], color->c[2]);
37 color_put_rgb(byte *dest, struct color *color)
39 switch (color->color_space)
41 case COLOR_SPACE_GRAYSCALE:
42 dest[0] = dest[1] = dest[2] = color->c[0];
45 dest[0] = color->c[0];
46 dest[1] = color->c[1];
47 dest[2] = color->c[2];
55 color_put_color_space(byte *dest, struct color *color, enum color_space color_space)
59 case COLOR_SPACE_GRAYSCALE:
60 color_put_grayscale(dest, color);
63 color_put_rgb(dest, color);
70 /********************* EXACT CONVERSION ROUTINES **********************/
74 srgb_to_xyz_slow(double xyz[3], double srgb[3])
77 for (uns i = 0; i < 3; i++)
78 if (srgb[i] > 0.04045)
79 a[i] = pow((srgb[i] + 0.055) * (1 / 1.055), 2.4);
81 a[i] = srgb[i] * (1 / 12.92);
82 xyz[0] = SRGB_XYZ_XR * a[0] + SRGB_XYZ_XG * a[1] + SRGB_XYZ_XB * a[2];
83 xyz[1] = SRGB_XYZ_YR * a[0] + SRGB_XYZ_YG * a[1] + SRGB_XYZ_YB * a[2];
84 xyz[2] = SRGB_XYZ_ZR * a[0] + SRGB_XYZ_ZG * a[1] + SRGB_XYZ_ZB * a[2];
89 xyz_to_luv_slow(double luv[3], double xyz[3])
91 double sum = xyz[0] + 15 * xyz[1] + 3 * xyz[2];
93 luv[0] = luv[1] = luv[2] = 0;
96 double var_u = 4 * xyz[0] / sum;
97 double var_v = 9 * xyz[1] / sum;
98 if (xyz[1] > 0.008856)
99 luv[0] = 116 * pow(xyz[1], 1 / 3.) - 16;
101 luv[0] = (116 * 7.787) * xyz[1];
102 luv[1] = luv[0] * (13 * (var_u - 4 * REF_WHITE_X / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z)));
103 luv[2] = luv[0] * (13 * (var_v - 9 * REF_WHITE_Y / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z)));
104 /* intervals [0..100], [-134..220], [-140..122] */
109 /***************** OPTIMIZED SRGB -> LUV CONVERSION *********************/
111 u16 srgb_to_luv_tab1[256];
112 u16 srgb_to_luv_tab2[9 << SRGB_TO_LUV_TAB2_SIZE];
113 u32 srgb_to_luv_tab3[20 << SRGB_TO_LUV_TAB3_SIZE];
116 srgb_to_luv_init(void)
118 DBG("Initializing sRGB -> Luv table");
119 for (uns i = 0; i < 256; i++)
123 t = pow((t + 0.055) * (1 / 1.055), 2.4);
126 srgb_to_luv_tab1[i] = CLAMP(t * 0xfff + 0.5, 0, 0xfff);
128 for (uns i = 0; i < (9 << SRGB_TO_LUV_TAB2_SIZE); i++)
130 double t = i / (double)((9 << SRGB_TO_LUV_TAB2_SIZE) - 1);
132 t = 1.16 * pow(t, 1 / 3.) - 0.16;
134 t = (1.16 * 7.787) * t;
135 srgb_to_luv_tab2[i] =
136 CLAMP(t * ((1 << SRGB_TO_LUV_TAB2_SCALE) - 1) + 0.5,
137 0, (1 << SRGB_TO_LUV_TAB2_SCALE) - 1);
139 for (uns i = 0; i < (20 << SRGB_TO_LUV_TAB3_SIZE); i++)
141 srgb_to_luv_tab3[i] = i ? (13 << (SRGB_TO_LUV_TAB3_SCALE + SRGB_TO_LUV_TAB3_SIZE)) / i : 0;
146 srgb_to_luv_pixels(byte *dest, byte *src, uns count)
150 srgb_to_luv_pixel(dest, src);
157 /************************ GRID INTERPOLATION ALGORITHM ************************/
159 struct color_grid_node *srgb_to_luv_grid;
160 struct color_interpolation_node *color_interpolation_table;
162 /* Returns volume of a given tetrahedron multiplied by 6 */
164 tetrahedron_volume(uns *v1, uns *v2, uns *v3, uns *v4)
166 int a[3], b[3], c[3];
167 for (uns i = 0; i < 3; i++)
169 a[i] = v2[i] - v1[i];
170 b[i] = v3[i] - v1[i];
171 c[i] = v4[i] - v1[i];
174 a[0] * (b[1] * c[2] - b[2] * c[1]) -
175 a[1] * (b[0] * c[2] - b[2] * c[0]) +
176 a[2] * (b[0] * c[1] - b[1] * c[0]);
177 return (result > 0) ? result : -result;
181 interpolate_tetrahedron(struct color_interpolation_node *n, uns *p, const uns *c)
184 for (uns i = 0; i < 4; i++)
186 v[i][0] = (c[i] & 0001) ? (1 << COLOR_CONV_OFS) : 0;
187 v[i][1] = (c[i] & 0010) ? (1 << COLOR_CONV_OFS) : 0;
188 v[i][2] = (c[i] & 0100) ? (1 << COLOR_CONV_OFS) : 0;
190 ((c[i] & 0001) ? 1 : 0) +
191 ((c[i] & 0010) ? (1 << COLOR_CONV_SIZE) : 0) +
192 ((c[i] & 0100) ? (1 << (COLOR_CONV_SIZE * 2)) : 0);
194 uns vol = tetrahedron_volume(v[0], v[1], v[2], v[3]);
195 n->mul[0] = ((tetrahedron_volume(p, v[1], v[2], v[3]) << 8) + (vol >> 1)) / vol;
196 n->mul[1] = ((tetrahedron_volume(v[0], p, v[2], v[3]) << 8) + (vol >> 1)) / vol;
197 n->mul[2] = ((tetrahedron_volume(v[0], v[1], p, v[3]) << 8) + (vol >> 1)) / vol;
198 n->mul[3] = ((tetrahedron_volume(v[0], v[1], v[2], p) << 8) + (vol >> 1)) / vol;
200 for (j = 0; j < 4; j++)
203 for (uns i = 0; i < 4; i++)
205 n->ofs[i] = n->ofs[j];
209 interpolation_table_init(void)
211 DBG("Initializing color interpolation table");
212 struct color_interpolation_node *n = color_interpolation_table =
213 xmalloc(sizeof(struct color_interpolation_node) << (COLOR_CONV_OFS * 3));
215 for (p[2] = 0; p[2] < (1 << COLOR_CONV_OFS); p[2]++)
216 for (p[1] = 0; p[1] < (1 << COLOR_CONV_OFS); p[1]++)
217 for (p[0] = 0; p[0] < (1 << COLOR_CONV_OFS); p[0]++)
220 static const uns tetrahedrons[5][4] = {
221 {0000, 0001, 0010, 0100},
222 {0110, 0111, 0100, 0010},
223 {0101, 0100, 0111, 0001},
224 {0011, 0010, 0001, 0111},
225 {0111, 0001, 0010, 0100}};
226 if (p[0] + p[1] + p[2] <= (1 << COLOR_CONV_OFS))
228 else if ((1 << COLOR_CONV_OFS) + p[0] <= p[1] + p[2])
230 else if ((1 << COLOR_CONV_OFS) + p[1] <= p[0] + p[2])
232 else if ((1 << COLOR_CONV_OFS) + p[2] <= p[0] + p[1])
236 interpolate_tetrahedron(n, p, tetrahedrons[index]);
241 typedef void color_conv_func(double dest[3], double src[3]);
244 conv_grid_init(struct color_grid_node **grid, color_conv_func func)
248 struct color_grid_node *g = *grid = xmalloc((sizeof(struct color_grid_node)) << (COLOR_CONV_SIZE * 3));
249 double src[3], dest[3];
250 for (uns k = 0; k < (1 << COLOR_CONV_SIZE); k++)
252 src[2] = k * (255 / (double)((1 << COLOR_CONV_SIZE) - 1));
253 for (uns j = 0; j < (1 << COLOR_CONV_SIZE); j++)
255 src[1] = j * (255/ (double)((1 << COLOR_CONV_SIZE) - 1));
256 for (uns i = 0; i < (1 << COLOR_CONV_SIZE); i++)
258 src[0] = i * (255 / (double)((1 << COLOR_CONV_SIZE) - 1));
260 g->val[0] = CLAMP(dest[0] + 0.5, 0, 255);
261 g->val[1] = CLAMP(dest[1] + 0.5, 0, 255);
262 g->val[2] = CLAMP(dest[2] + 0.5, 0, 255);
270 srgb_to_luv_func(double dest[3], double src[3])
272 double srgb[3], xyz[3], luv[3];
273 srgb[0] = src[0] / 255.;
274 srgb[1] = src[1] / 255.;
275 srgb[2] = src[2] / 255.;
276 srgb_to_xyz_slow(xyz, srgb);
277 xyz_to_luv_slow(luv, xyz);
278 dest[0] = luv[0] * 2.55;
279 dest[1] = luv[1] * (2.55 / 4) + 128;
280 dest[2] = luv[2] * (2.55 / 4) + 128;
284 color_conv_init(void)
286 interpolation_table_init();
287 conv_grid_init(&srgb_to_luv_grid, srgb_to_luv_func);
291 color_conv_pixels(byte *dest, byte *src, uns count, struct color_grid_node *grid)
295 color_conv_pixel(dest, src, grid);
302 /**************************** TESTS *******************************/
308 conv_error(u32 color, struct color_grid_node *grid, color_conv_func func)
310 byte src[3], dest[3];
311 src[0] = color & 255;
312 src[1] = (color >> 8) & 255;
313 src[2] = (color >> 16) & 255;
314 color_conv_pixel(dest, src, grid);
315 double src2[3], dest2[3];
316 for (uns i = 0; i < 3; i++)
320 for (uns i = 0; i < 3; i++)
321 err += (dest[i] - dest2[i]) * (dest[i] - dest2[i]);
325 typedef void test_fn(byte *dest, byte *src);
328 func_error(u32 color, test_fn test, color_conv_func func)
330 byte src[3], dest[3];
331 src[0] = color & 255;
332 src[1] = (color >> 8) & 255;
333 src[2] = (color >> 16) & 255;
335 double src2[3], dest2[3];
336 for (uns i = 0; i < 3; i++)
340 for (uns i = 0; i < 3; i++)
341 err += (dest[i] - dest2[i]) * (dest[i] - dest2[i]);
346 test_grid(byte *name, struct color_grid_node *grid, color_conv_func func)
348 double max_err = 0, sum_err = 0;
350 for (uns i = 0; i < count; i++)
352 double err = conv_error(random_max(0x1000000), grid, func);
353 max_err = MAX(err, max_err);
356 DBG("%s: error max=%f avg=%f", name, max_err, sum_err / count);
358 die("Too large error in %s conversion", name);
362 test_func(byte *name, test_fn test, color_conv_func func)
364 double max_err = 0, sum_err = 0;
366 for (uns i = 0; i < count; i++)
368 double err = func_error(random_max(0x1000000), test, func);
369 max_err = MAX(err, max_err);
372 DBG("%s: error max=%f avg=%f", name, max_err, sum_err / count);
374 die("Too large error in %s conversion", name);
381 test_func("func sRGB -> Luv", srgb_to_luv_pixel, srgb_to_luv_func);
383 test_grid("grid sRGB -> Luv", srgb_to_luv_grid, srgb_to_luv_func);
387 byte *a = xmalloc(3 * CNT), *b = xmalloc(3 * CNT);
388 for (uns i = 0; i < 3 * CNT; i++)
389 a[i] = random_max(256);
391 for (uns i = 0; i < TESTS; i++)
392 memcpy(b, a, CNT * 3);
393 DBG("memcpy time=%d", (uns)get_timer());
395 for (uns i = 0; i < TESTS; i++)
396 srgb_to_luv_pixels(b, a, CNT);
397 DBG("direct time=%d", (uns)get_timer());
399 for (uns i = 0; i < TESTS; i++)
400 color_conv_pixels(b, a, CNT, srgb_to_luv_grid);
401 DBG("grid time=%d", (uns)get_timer());