1
/*
2
  Metric
3
  Copyright (C) 2006 Yangli Hector Yee
4

            
5
  This program is free software; you can redistribute it and/or modify it under the terms of the
6
  GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
7
  or (at your option) any later version.
8

            
9
  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
10
  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11
  See the GNU General Public License for more details.
12

            
13
  You should have received a copy of the GNU General Public License along with this program;
14
  if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
15
*/
16

            
17
#include "config.h"
18

            
19
#include "lpyramid.h"
20
#include <assert.h>
21
#include <math.h>
22
#include <stdio.h>
23
#include <stdlib.h>
24

            
25
#if   HAVE_STDINT_H
26
# include <stdint.h>
27
#elif HAVE_INTTYPES_H
28
# include <inttypes.h>
29
#elif HAVE_SYS_INT_TYPES_H
30
# include <sys/int_types.h>
31
#elif defined(_MSC_VER)
32
  typedef __int8 int8_t;
33
  typedef unsigned __int8 uint8_t;
34
  typedef __int16 int16_t;
35
  typedef unsigned __int16 uint16_t;
36
  typedef __int32 int32_t;
37
  typedef unsigned __int32 uint32_t;
38
  typedef __int64 int64_t;
39
  typedef unsigned __int64 uint64_t;
40
# ifndef HAVE_UINT64_T
41
#  define HAVE_UINT64_T 1
42
# endif
43
# ifndef INT16_MIN
44
#  define INT16_MIN	(-32767-1)
45
# endif
46
# ifndef INT16_MAX
47
#  define INT16_MAX	(32767)
48
# endif
49
# ifndef UINT16_MAX
50
#  define UINT16_MAX	(65535)
51
# endif
52
#else
53
#error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
54
#endif
55

            
56
#include "pdiff.h"
57

            
58
#ifndef M_PI
59
#define M_PI 3.14159265f
60
#endif
61

            
62
#ifndef __USE_ISOC99
63
#define expf	exp
64
#define powf	pow
65
#define fabsf	fabs
66
#define sqrtf	sqrt
67
#define log10f	log10
68
#endif
69

            
70
/*
71
 * Given the adaptation luminance, this function returns the
72
 * threshold of visibility in cd per m^2
73
 * TVI means Threshold vs Intensity function
74
 * This version comes from Ward Larson Siggraph 1997
75
 */
76
static float
77
58029316
tvi (float adaptation_luminance)
78
{
79
    /* returns the threshold luminance given the adaptation luminance
80
       units are candelas per meter squared
81
    */
82
    float log_a, r, result;
83
58029316
    log_a = log10f(adaptation_luminance);
84

            
85
58029316
    if (log_a < -3.94f) {
86
9139966
	r = -2.86f;
87
48889350
    } else if (log_a < -1.44f) {
88
1208173
	r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
89
47681177
    } else if (log_a < -0.0184f) {
90
1699554
	r = log_a - 0.395f;
91
45981623
    } else if (log_a < 1.9f) {
92
25155703
	r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
93
    } else {
94
20825920
	r = log_a - 1.255f;
95
    }
96

            
97
58029316
    result = powf(10.0f , r);
98

            
99
58029316
    return result;
100
}
101

            
102
/* computes the contrast sensitivity function (Barten SPIE 1989)
103
 * given the cycles per degree (cpd) and luminance (lum)
104
 */
105
static float
106
348181125
csf (float cpd, float lum)
107
{
108
    float a, b, result;
109

            
110
348181125
    a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
111
348181125
    b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
112

            
113
348181125
    result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
114

            
115
348181125
    return result;
116
}
117

            
118
/*
119
 * Visual Masking Function
120
 * from Daly 1993
121
 */
122
static float
123
348175896
mask (float contrast)
124
{
125
    float a, b, result;
126
348175896
    a = powf(392.498f * contrast,  0.7f);
127
348175896
    b = powf(0.0153f * a, 4.0f);
128
348175896
    result = powf(1.0f + b, 0.25f);
129

            
130
348175896
    return result;
131
}
132

            
133
/* convert Adobe RGB (1998) with reference white D65 to XYZ */
134
static void
135
116059225
AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
136
{
137
    /* matrix is from http://www.brucelindbloom.com/ */
138
116059225
    *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
139
116059225
    *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
140
116059225
    *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
141
116059225
}
142

            
143
static void
144
116058632
XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
145
{
146
    static float xw = -1;
147
    static float yw;
148
    static float zw;
149
116058632
    const float epsilon  = 216.0f / 24389.0f;
150
116058632
    const float kappa = 24389.0f / 27.0f;
151
    float f[3];
152
    float r[3];
153
    int i;
154

            
155
    /* reference white */
156
116058632
    if (xw < 0) {
157
593
	AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
158
    }
159
116058632
    r[0] = x / xw;
160
116058632
    r[1] = y / yw;
161
116058632
    r[2] = z / zw;
162
464234528
    for (i = 0; i < 3; i++) {
163
348175896
	if (r[i] > epsilon) {
164
258644715
	    f[i] = powf(r[i], 1.0f / 3.0f);
165
	} else {
166
89531181
	    f[i] = (kappa * r[i] + 16.0f) / 116.0f;
167
	}
168
    }
169
116058632
    *L = 116.0f * f[1] - 16.0f;
170
116058632
    *A = 500.0f * (f[0] - f[1]);
171
116058632
    *B = 200.0f * (f[1] - f[2]);
172
116058632
}
173

            
174
static uint32_t
175
348175896
_get_pixel (const uint32_t *data, int i, cairo_format_t format)
176
{
177
348175896
    if (format == CAIRO_FORMAT_ARGB32)
178
43428267
	return data[i];
179
    else
180
304747629
	return data[i] | 0xff000000;
181
}
182

            
183
static unsigned char
184
116058632
_get_red (const uint32_t *data, int i, cairo_format_t format)
185
{
186
    uint32_t pixel;
187
    uint8_t alpha;
188

            
189
116058632
    pixel = _get_pixel (data, i, format);
190
116058632
    alpha = (pixel & 0xff000000) >> 24;
191
116058632
    if (alpha == 0)
192
172074
	return 0;
193
    else
194
115886558
	return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
195
}
196

            
197
static unsigned char
198
116058632
_get_green (const uint32_t *data, int i, cairo_format_t format)
199
{
200
    uint32_t pixel;
201
    uint8_t alpha;
202

            
203
116058632
    pixel = _get_pixel (data, i, format);
204
116058632
    alpha = (pixel & 0xff000000) >> 24;
205
116058632
    if (alpha == 0)
206
172074
	return 0;
207
    else
208
115886558
	return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
209
}
210

            
211
static unsigned char
212
116058632
_get_blue (const uint32_t *data, int i, cairo_format_t format)
213
{
214
    uint32_t pixel;
215
    uint8_t alpha;
216

            
217
116058632
    pixel = _get_pixel (data, i, format);
218
116058632
    alpha = (pixel & 0xff000000) >> 24;
219
116058632
    if (alpha == 0)
220
172074
	return 0;
221
    else
222
115886558
	return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
223
}
224

            
225
static void *
226
8964
xmalloc (size_t size)
227
{
228
    void *buf;
229

            
230
8964
    buf = malloc (size);
231
8964
    if (buf == NULL) {
232
	fprintf (stderr, "Out of memory.\n");
233
	exit (1);
234
    }
235

            
236
8964
    return buf;
237
}
238

            
239
int
240
755
pdiff_compare (cairo_surface_t *surface_a,
241
	       cairo_surface_t *surface_b,
242
	       double gamma,
243
	       double luminance,
244
	       double field_of_view)
245
{
246
755
    unsigned int dim = (cairo_image_surface_get_width (surface_a)
247
755
			* cairo_image_surface_get_height (surface_a));
248
    unsigned int i;
249

            
250
    /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
251
    float *aX;
252
    float *aY;
253
    float *aZ;
254
    float *bX;
255
    float *bY;
256
    float *bZ;
257
    float *aLum;
258
    float *bLum;
259

            
260
    float *aA;
261
    float *bA;
262
    float *aB;
263
    float *bB;
264

            
265
    unsigned int x, y, w, h;
266

            
267
    lpyramid_t *la, *lb;
268

            
269
    float num_one_degree_pixels, pixels_per_degree, num_pixels;
270
    unsigned int adaptation_level;
271

            
272
    float cpd[MAX_PYR_LEVELS];
273
    float F_freq[MAX_PYR_LEVELS - 2];
274
    float csf_max;
275
    const uint32_t *data_a, *data_b;
276
    cairo_format_t format_a, format_b;
277

            
278
    unsigned int pixels_failed;
279

            
280
755
    w = cairo_image_surface_get_width (surface_a);
281
755
    h = cairo_image_surface_get_height (surface_a);
282
755
    if (w < 3 || h < 3) /* too small for the Laplacian convolution */
283
8
	return -1;
284

            
285
747
    format_a = cairo_image_surface_get_format (surface_a);
286
747
    format_b = cairo_image_surface_get_format (surface_b);
287
747
    assert (format_a == CAIRO_FORMAT_RGB24 || format_a == CAIRO_FORMAT_ARGB32);
288
747
    assert (format_b == CAIRO_FORMAT_RGB24 || format_b == CAIRO_FORMAT_ARGB32);
289

            
290
747
    aX = xmalloc (dim * sizeof (float));
291
747
    aY = xmalloc (dim * sizeof (float));
292
747
    aZ = xmalloc (dim * sizeof (float));
293
747
    bX = xmalloc (dim * sizeof (float));
294
747
    bY = xmalloc (dim * sizeof (float));
295
747
    bZ = xmalloc (dim * sizeof (float));
296
747
    aLum = xmalloc (dim * sizeof (float));
297
747
    bLum = xmalloc (dim * sizeof (float));
298

            
299
747
    aA = xmalloc (dim * sizeof (float));
300
747
    bA = xmalloc (dim * sizeof (float));
301
747
    aB = xmalloc (dim * sizeof (float));
302
747
    bB = xmalloc (dim * sizeof (float));
303

            
304
747
    data_a = (uint32_t *) cairo_image_surface_get_data (surface_a);
305
747
    data_b = (uint32_t *) cairo_image_surface_get_data (surface_b);
306
120590
    for (y = 0; y < h; y++) {
307
58149159
	for (x = 0; x < w; x++) {
308
	    float r, g, b, l;
309
58029316
	    i = x + y * w;
310
58029316
	    r = powf(_get_red (data_a, i, format_a) / 255.0f, gamma);
311
58029316
	    g = powf(_get_green (data_a, i, format_a) / 255.0f, gamma);
312
58029316
	    b = powf(_get_blue (data_a, i, format_a) / 255.0f, gamma);
313

            
314
58029316
	    AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
315
58029316
	    XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
316
58029316
	    r = powf(_get_red (data_b, i, format_b) / 255.0f, gamma);
317
58029316
	    g = powf(_get_green (data_b, i, format_b) / 255.0f, gamma);
318
58029316
	    b = powf(_get_blue (data_b, i, format_b) / 255.0f, gamma);
319

            
320
58029316
	    AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
321
58029316
	    XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
322
58029316
	    aLum[i] = aY[i] * luminance;
323
58029316
	    bLum[i] = bY[i] * luminance;
324
	}
325
    }
326

            
327
747
    la = lpyramid_create (aLum, w, h);
328
747
    lb = lpyramid_create (bLum, w, h);
329

            
330
747
    num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
331
747
    pixels_per_degree = w / num_one_degree_pixels;
332

            
333
747
    num_pixels = 1;
334
747
    adaptation_level = 0;
335
5229
    for (i = 0; i < MAX_PYR_LEVELS; i++) {
336
5229
	adaptation_level = i;
337
5229
	if (num_pixels > num_one_degree_pixels) break;
338
4482
	num_pixels *= 2;
339
    }
340

            
341
747
    cpd[0] = 0.5f * pixels_per_degree;
342
5976
    for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
343
747
    csf_max = csf(3.248f, 100.0f);
344

            
345
5229
    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
346

            
347
747
    pixels_failed = 0;
348
120590
    for (y = 0; y < h; y++) {
349
58149159
	for (x = 0; x < w; x++) {
350
58029316
	    int index = x + y * w;
351
	    float contrast[MAX_PYR_LEVELS - 2];
352
	    float F_mask[MAX_PYR_LEVELS - 2];
353
	    float factor;
354
	    float delta;
355
	    float adapt;
356
	    bool pass;
357
58029316
	    float sum_contrast = 0;
358
406205212
	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
359
348175896
		float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
360
348175896
		float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
361
348175896
		float numerator = (n1 > n2) ? n1 : n2;
362
348175896
		float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
363
348175896
		float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
364
348175896
		float denominator = (d1 > d2) ? d1 : d2;
365
348175896
		if (denominator < 1e-5f) denominator = 1e-5f;
366
348175896
		contrast[i] = numerator / denominator;
367
348175896
		sum_contrast += contrast[i];
368
	    }
369
58029316
	    if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
370
58029316
	    adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
371
58029316
	    adapt *= 0.5f;
372
58029316
	    if (adapt < 1e-5) adapt = 1e-5f;
373
406205212
	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
374
348175896
		F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
375
	    }
376
58029316
	    factor = 0;
377
406205212
	    for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
378
348175896
		factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
379
	    }
380
58029316
	    if (factor < 1) factor = 1;
381
58029316
	    if (factor > 10) factor = 10;
382
58029316
	    delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
383
58029316
	    pass = true;
384
	    /* pure luminance test */
385
58029316
	    if (delta > factor * tvi(adapt)) {
386
62894
		pass = false;
387
	    } else {
388
		/* CIE delta E test with modifications */
389
57966422
		float color_scale = 1.0f;
390
57966422
		float da = aA[index] - bA[index];
391
57966422
		float db = aB[index] - bB[index];
392
		float delta_e;
393
		/* ramp down the color test in scotopic regions */
394
57966422
		if (adapt < 10.0f) {
395
16073776
		    color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
396
16073776
		    color_scale = color_scale * color_scale;
397
		}
398
57966422
		da = da * da;
399
57966422
		db = db * db;
400
57966422
		delta_e = (da + db) * color_scale;
401
57966422
		if (delta_e > factor) {
402
1912718
		    pass = false;
403
		}
404
	    }
405
58029316
	    if (!pass)
406
1975612
		pixels_failed++;
407
	}
408
    }
409

            
410
747
    free (aX);
411
747
    free (aY);
412
747
    free (aZ);
413
747
    free (bX);
414
747
    free (bY);
415
747
    free (bZ);
416
747
    free (aLum);
417
747
    free (bLum);
418
747
    lpyramid_destroy (la);
419
747
    lpyramid_destroy (lb);
420
747
    free (aA);
421
747
    free (bA);
422
747
    free (aB);
423
747
    free (bB);
424

            
425
747
    return pixels_failed;
426
}