]> mj.ucw.cz Git - libucw.git/blob - images/image-sig.c
cc159fce6a02fe3fe14a4c116c8050699b173245
[libucw.git] / images / image-sig.c
1 #define LOCAL_DEBUG
2
3 #include "sherlock/sherlock.h"
4 #include "lib/math.h"
5 #include "lib/fastbuf.h"
6 #include "images/images.h"
7 #include "images/image-obj.h"
8 #include "images/image-sig.h"
9
10 #include <alloca.h>
11 #include <magick/api.h>
12
13 /*
14  * Color spaces
15  * 
16  * http://www.tecgraf.puc-rio.br/~mgattass/color/ColorIndex.html
17  * 
18  */
19
20 #define REF_WHITE_X 0.96422
21 #define REF_WHITE_Y 1.
22 #define REF_WHITE_Z 0.82521
23
24 /* sRGB to XYZ */
25 static void
26 srgb_to_xyz_slow(double srgb[3], double xyz[3])
27 {
28   double a[3];
29   for (uns i = 0; i < 3; i++)
30     if (srgb[i] > 0.04045)
31       a[i] = pow((srgb[i] + 0.055) * (1 / 1.055), 2.4);
32     else
33       a[i] = srgb[i] * (1 / 12.92);
34   xyz[0] = 0.412424 * a[0] + 0.357579 * a[1] + 0.180464 * a[2];
35   xyz[1] = 0.212656 * a[0] + 0.715158 * a[1] + 0.072186 * a[2];
36   xyz[2] = 0.019332 * a[0] + 0.119193 * a[1] + 0.950444 * a[2];
37 }
38
39 /* XYZ to CIE-Luv */
40 static void
41 xyz_to_luv_slow(double xyz[3], double luv[3])
42 {
43   double sum = xyz[0] + 15 * xyz[1] + 3 * xyz[2];
44   if (sum < 0.000001)
45     luv[0] = luv[1] = luv[2] = 0;
46   else
47     {
48       double var_u = 4 * xyz[0] / sum;
49       double var_v = 9 * xyz[1] / sum;
50       if (xyz[1] > 0.008856)
51         luv[0] = 116 * pow(xyz[1], 1 / 3.) - 16;
52       else
53         luv[0] = (116 * 7.787) * xyz[1];
54       luv[1] = luv[0] * (13 * (var_u - 4 * REF_WHITE_X / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z)));
55       luv[2] = luv[0] * (13 * (var_v - 9 * REF_WHITE_Y / (REF_WHITE_X + 15 * REF_WHITE_Y + 3 * REF_WHITE_Z)));
56       /* intervals [0..100], [-134..220], [-140..122] */
57     }
58 }
59
60 struct block {
61   uns l, u, v;          /* average Luv coefficients */
62   uns lh, hl, hh;       /* energies in Daubechies wavelet bands */
63 };
64
65 int
66 compute_image_signature(struct image *image, struct image_signature *sig)
67 {
68   uns width = image->width;
69   uns height = image->height;
70
71   if (width < 4 || height < 4)
72     {
73       DBG("Image too small... %dx%d", width, height);
74       return 0;
75     }
76   
77   uns w = width >> 2;
78   uns h = height >> 2;
79   DBG("Computing signature for image %dx%d... %dx%d blocks", width, height, w, h);
80   uns blocks_count = w * h;
81   struct block *blocks = xmalloc(blocks_count * sizeof(struct block)), *block = blocks; /* FIXME: use mempool */
82   
83   /* Every 4x4 block (FIXME: deal with smaller blocks near the edges) */
84   struct pixel *p = image->pixels;
85   for (uns block_y = 0; block_y < h; block_y++, p +=  (width & 3) + width * 3)
86     for (uns block_x = 0; block_x < w; block_x++, p -= 4 * width - 4, block++)
87       {
88         int t[16], s[16], *tp = t;
89
90         /* Convert pixels to Luv color space and compute average coefficients 
91          * FIXME:
92          * - could be MUCH faster with precomputed tables and integer arithmetic... 
93          *   I will propably use interpolation in 3-dim array */
94         uns l_sum = 0;
95         uns u_sum = 0;
96         uns v_sum = 0;
97         for (uns y = 0; y < 4; y++, p += width - 4)
98           for (uns x = 0; x < 4; x++, p += 1)
99             {
100               double rgb[3], luv[3], xyz[3];
101               rgb[0] = p->r / 255.;
102               rgb[1] = p->g / 255.;
103               rgb[2] = p->b / 255.;
104               srgb_to_xyz_slow(rgb, xyz);
105               xyz_to_luv_slow(xyz, luv);
106               l_sum += *tp++ = luv[0];
107               u_sum += luv[1] + 150;
108               v_sum += luv[2] + 150;
109             }
110
111         block->l = l_sum;
112         block->u = u_sum;
113         block->v = v_sum;
114
115         /* Apply Daubechies wavelet transformation 
116          * FIXME:
117          * - MMX/SSE instructions or tables could be faster 
118          * - maybe it would be better to compute Luv and wavelet separately because of processor cache or MMX/SSE 
119          * - eliminate slow square roots 
120          * - what about Haar transformation? */
121
122 #define DAUB_0  31651 /* (1 + sqrt 3) / (4 * sqrt 2) */
123 #define DAUB_1  54822 /* (3 + sqrt 3) / (4 * sqrt 2) */
124 #define DAUB_2  14689 /* (3 - sqrt 3) / (4 * sqrt 2) */
125 #define DAUB_3  -8481 /* (1 - sqrt 3) / (4 * sqrt 2) */
126
127         /* ... to the rows */
128         uns i;
129         for (i = 0; i < 16; i += 4)
130           {
131             s[i + 0] = (DAUB_0 * t[i + 2] + DAUB_1 * t[i + 3] + DAUB_2 * t[i + 0] + DAUB_3 * t[i + 1]) / 0x10000;
132             s[i + 1] = (DAUB_0 * t[i + 0] + DAUB_1 * t[i + 1] + DAUB_2 * t[i + 2] + DAUB_3 * t[i + 3]) / 0x10000;
133             s[i + 2] = (DAUB_3 * t[i + 2] - DAUB_2 * t[i + 3] + DAUB_1 * t[i + 0] - DAUB_0 * t[i + 1]) / 0x10000;
134             s[i + 3] = (DAUB_3 * t[i + 0] - DAUB_2 * t[i + 1] + DAUB_1 * t[i + 2] - DAUB_0 * t[i + 3]) / 0x10000;
135           }
136
137         /* ... and to the columns... skip LL band */
138         for (i = 0; i < 2; i++)
139           {
140             t[i + 8] = (DAUB_3 * s[i + 8] - DAUB_2 * s[i +12] + DAUB_1 * s[i + 0] - DAUB_0 * s[i + 4]) / 0x1000;
141             t[i +12] = (DAUB_3 * s[i + 0] - DAUB_2 * s[i + 4] + DAUB_1 * s[i + 8] - DAUB_0 * s[i +12]) / 0x1000;
142           }
143         for (; i < 4; i++)
144           {
145             t[i + 0] = (DAUB_0 * s[i + 8] + DAUB_1 * s[i +12] + DAUB_2 * s[i + 0] + DAUB_3 * s[i + 4]) / 0x1000;
146             t[i + 4] = (DAUB_0 * s[i + 0] + DAUB_1 * s[i + 4] + DAUB_2 * s[i + 8] + DAUB_3 * s[i +12]) / 0x1000;
147             t[i + 8] = (DAUB_3 * s[i + 8] - DAUB_2 * s[i +12] + DAUB_1 * s[i + 0] - DAUB_0 * s[i + 4]) / 0x1000;
148             t[i +12] = (DAUB_3 * s[i + 0] - DAUB_2 * s[i + 4] + DAUB_1 * s[i + 8] - DAUB_0 * s[i +12]) / 0x1000;
149           }
150
151         /* Extract energies in LH, HL and HH bands */
152         block->lh = sqrt(t[8] * t[8] + t[9] * t[9] + t[12] * t[12] + t[13] * t[13]);
153         block->hl = sqrt(t[2] * t[2] + t[3] * t[3] + t[6] * t[6] + t[7] * t[7]);
154         block->hh = sqrt(t[10] * t[10] + t[11] * t[11] + t[14] * t[14] + t[15] * t[15]);
155       }
156
157   /* FIXME: simple average is for testing pusposes only */
158   uns l_sum = 0;
159   uns u_sum = 0;
160   uns v_sum = 0;
161   uns lh_sum = 0;
162   uns hl_sum = 0;
163   uns hh_sum = 0;
164   for (uns i = 0; i < blocks_count; i++)
165     {
166       l_sum += blocks[i].l;
167       u_sum += blocks[i].u;
168       v_sum += blocks[i].v;
169       lh_sum += blocks[i].lh;
170       hl_sum += blocks[i].hl;
171       hh_sum += blocks[i].hh;
172     }
173
174   sig->vec.f[0] = l_sum / blocks_count;
175   sig->vec.f[1] = u_sum / blocks_count;
176   sig->vec.f[2] = v_sum / blocks_count;
177   sig->vec.f[3] = lh_sum / blocks_count;
178   sig->vec.f[4] = hl_sum / blocks_count;
179   sig->vec.f[5] = hh_sum / blocks_count;
180
181   sig->len = 0;
182
183   xfree(blocks);
184
185   DBG("Resulting signature is (%s)", stk_print_image_vector(&sig->vec));
186   return 1;
187 }
188