]> mj.ucw.cz Git - libucw.git/blobdiff - images/color.c
- use shape features in new comparision algorithm
[libucw.git] / images / color.c
index 457e2e2cda44313e1fa06bc8258bdd2c7f885b02..80f48294c86c0db14d7d5fe925a365c6469208ef 100644 (file)
@@ -5,23 +5,69 @@
  *
  *     This software may be freely distributed and used according to the terms
  *     of the GNU Lesser General Public License.
- *
- *     Reference:
- *     - http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html
  */
 
 #undef LOCAL_DEBUG
 
 #include "sherlock/sherlock.h"
 #include "lib/math.h"
+#include "images/images.h"
 #include "images/color.h"
 
-u16 srgb_to_luv_tab1[256];
-u16 srgb_to_luv_tab2[9 << SRGB_TO_LUV_TAB2_SIZE];
-u32 srgb_to_luv_tab3[20 << SRGB_TO_LUV_TAB3_SIZE];
+struct color color_black = { .color_space = COLOR_SPACE_GRAYSCALE };
+struct color color_white = { .c = { 255 }, .color_space = COLOR_SPACE_GRAYSCALE };
 
-struct color_grid_node *srgb_to_luv_grid;
-struct color_interpolation_node *color_interpolation_table;
+inline void
+color_put_grayscale(byte *dest, struct color *color)
+{
+  switch (color->color_space)
+    {
+      case COLOR_SPACE_GRAYSCALE:
+       dest[0] = color->c[0];
+       break;
+      case COLOR_SPACE_RGB:
+       dest[0] = rgb_to_gray_func(color->c[0], color->c[1], color->c[2]);
+       break;
+      default:
+       ASSERT(0);      
+    }
+}
+
+inline void
+color_put_rgb(byte *dest, struct color *color)
+{
+  switch (color->color_space)
+    {
+      case COLOR_SPACE_GRAYSCALE:
+       dest[0] = dest[1] = dest[2] = color->c[0];
+       break;
+      case COLOR_SPACE_RGB:
+       dest[0] = color->c[0];
+       dest[1] = color->c[1];
+       dest[2] = color->c[2];
+       break;
+      default:
+       ASSERT(0);      
+    }
+}
+
+void
+color_put_color_space(byte *dest, struct color *color, enum color_space color_space)
+{
+  switch (color_space)
+    {
+      case COLOR_SPACE_GRAYSCALE:
+       color_put_grayscale(dest, color);
+       break;  
+      case COLOR_SPACE_RGB:
+       color_put_rgb(dest, color);     
+       break;
+      default:
+       ASSERT(0);      
+    }
+}
+
+/********************* EXACT CONVERSION ROUTINES **********************/
 
 /* sRGB to XYZ */
 void
@@ -38,6 +84,21 @@ srgb_to_xyz_slow(double xyz[3], double srgb[3])
   xyz[2] = SRGB_XYZ_ZR * a[0] + SRGB_XYZ_ZG * a[1] + SRGB_XYZ_ZB * a[2];
 }
 
+/* XYZ to sRGB */
+void
+xyz_to_srgb_slow(double srgb[3], double xyz[3])
+{
+  double a[3];
+  a[0] =  3.2406 * xyz[0] + -1.5372 * xyz[1] + -0.4986 * xyz[2];
+  a[1] = -0.9689 * xyz[0] +  1.8758 * xyz[1] +  0.0415 * xyz[2];
+  a[2] =  0.0557 * xyz[0] + -0.2040 * xyz[1] +  1.0570 * xyz[2];
+  for (uns i = 0; i < 3; i++)
+    if (a[i] > 0.0031308)
+      srgb[i] = 1.055 * pow(a[i], 1 / 2.4) - 0.055;
+    else
+      srgb[i] = 12.92 * a[i];
+}
+
 /* XYZ to CIE-Luv */
 void
 xyz_to_luv_slow(double luv[3], double xyz[3])
@@ -59,6 +120,30 @@ xyz_to_luv_slow(double luv[3], double xyz[3])
    }
 }
 
+/* CIE-Luv to XYZ */
+void
+luv_to_xyz_slow(double xyz[3], double luv[3])
+{
+  double var_u = luv[1] / (13 * luv[0]) + (4 * REF_WHITE_X / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z));
+  double var_v = luv[2] / (13 * luv[0]) + (9 * REF_WHITE_Y / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z));
+  double var_y = (luv[0] + 16) / 116;
+  double pow_y = var_y * var_y * var_y;
+  if (pow_y > 0.008856)
+    var_y = pow_y;
+  else
+    var_y = (var_y - 16 / 116) / 7.787;
+  xyz[1] = var_y;
+  xyz[0] = -(9 * xyz[1] * var_u) / ((var_u - 4) * var_v - var_u * var_v);
+  xyz[2] = (9 * xyz[1] - 15 * var_v * xyz[1] - var_v * xyz[0]) / (3 * var_v);
+}
+
+
+/***************** OPTIMIZED SRGB -> LUV CONVERSION *********************/
+
+u16 srgb_to_luv_tab1[256];
+u16 srgb_to_luv_tab2[9 << SRGB_TO_LUV_TAB2_SIZE];
+u32 srgb_to_luv_tab3[20 << SRGB_TO_LUV_TAB3_SIZE];
+
 void
 srgb_to_luv_init(void)
 {
@@ -100,6 +185,12 @@ srgb_to_luv_pixels(byte *dest, byte *src, uns count)
     }
 }
 
+
+/************************ GRID INTERPOLATION ALGORITHM ************************/
+
+struct color_grid_node *srgb_to_luv_grid;
+struct color_interpolation_node *color_interpolation_table;
+
 /* Returns volume of a given tetrahedron multiplied by 6 */
 static inline uns
 tetrahedron_volume(uns *v1, uns *v2, uns *v3, uns *v4)
@@ -239,6 +330,9 @@ color_conv_pixels(byte *dest, byte *src, uns count, struct color_grid_node *grid
     }
 }
 
+
+/**************************** TESTS *******************************/
+
 #ifdef TEST
 #include <string.h>
 
@@ -321,19 +415,20 @@ main(void)
   test_grid("grid sRGB -> Luv", srgb_to_luv_grid, srgb_to_luv_func);
 #ifdef LOCAL_DEBUG
 #define CNT 1000000
+#define TESTS 10
   byte *a = xmalloc(3 * CNT), *b = xmalloc(3 * CNT);
+  for (uns i = 0; i < 3 * CNT; i++)
+    a[i] = random_max(256);
   init_timer();
-  for (uns i = 0; i < 20; i++)
+  for (uns i = 0; i < TESTS; i++)
     memcpy(b, a, CNT * 3);
   DBG("memcpy time=%d", (uns)get_timer());
-  for (uns i = 0; i < 3 * CNT; i++)
-    a[i] = random_max(256);
   init_timer();
-  for (uns i = 0; i < 20; i++)
+  for (uns i = 0; i < TESTS; i++)
     srgb_to_luv_pixels(b, a, CNT);
   DBG("direct time=%d", (uns)get_timer());
   init_timer();
-  for (uns i = 0; i < 20; i++)
+  for (uns i = 0; i < TESTS; i++)
     color_conv_pixels(b, a, CNT, srgb_to_luv_grid);
   DBG("grid time=%d", (uns)get_timer());
 #endif