pdiff.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. /*
  2. Metric
  3. Copyright (C) 2006 Yangli Hector Yee
  4. This program is free software; you can redistribute it and/or modify it under the terms of the
  5. GNU General Public License as published by the Free Software Foundation; either version 2 of the License,
  6. or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
  8. without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. See the GNU General Public License for more details.
  10. You should have received a copy of the GNU General Public License along with this program;
  11. if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
  12. */
  13. #define _GNU_SOURCE
  14. #if HAVE_CONFIG_H
  15. #include "config.h"
  16. #endif
  17. #include "lpyramid.h"
  18. #include <math.h>
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #if HAVE_STDINT_H
  22. # include <stdint.h>
  23. #elif HAVE_INTTYPES_H
  24. # include <inttypes.h>
  25. #elif HAVE_SYS_INT_TYPES_H
  26. # include <sys/int_types.h>
  27. #elif defined(_MSC_VER)
  28. typedef __int8 int8_t;
  29. typedef unsigned __int8 uint8_t;
  30. typedef __int16 int16_t;
  31. typedef unsigned __int16 uint16_t;
  32. typedef __int32 int32_t;
  33. typedef unsigned __int32 uint32_t;
  34. typedef __int64 int64_t;
  35. typedef unsigned __int64 uint64_t;
  36. # ifndef HAVE_UINT64_T
  37. # define HAVE_UINT64_T 1
  38. # endif
  39. # ifndef INT16_MIN
  40. # define INT16_MIN (-32767-1)
  41. # endif
  42. # ifndef INT16_MAX
  43. # define INT16_MAX (32767)
  44. # endif
  45. # ifndef UINT16_MAX
  46. # define UINT16_MAX (65535)
  47. # endif
  48. #else
  49. #error Cannot find definitions for fixed-width integral types (uint8_t, uint32_t, etc.)
  50. #endif
  51. #include "pdiff.h"
  52. #ifndef M_PI
  53. #define M_PI 3.14159265f
  54. #endif
  55. #ifndef __USE_ISOC99
  56. #define expf exp
  57. #define powf pow
  58. #define fabsf fabs
  59. #define sqrtf sqrt
  60. #define log10f log10
  61. #endif
  62. /*
  63. * Given the adaptation luminance, this function returns the
  64. * threshold of visibility in cd per m^2
  65. * TVI means Threshold vs Intensity function
  66. * This version comes from Ward Larson Siggraph 1997
  67. */
  68. static float
  69. tvi (float adaptation_luminance)
  70. {
  71. /* returns the threshold luminance given the adaptation luminance
  72. units are candelas per meter squared
  73. */
  74. float log_a, r, result;
  75. log_a = log10f(adaptation_luminance);
  76. if (log_a < -3.94f) {
  77. r = -2.86f;
  78. } else if (log_a < -1.44f) {
  79. r = powf(0.405f * log_a + 1.6f , 2.18f) - 2.86f;
  80. } else if (log_a < -0.0184f) {
  81. r = log_a - 0.395f;
  82. } else if (log_a < 1.9f) {
  83. r = powf(0.249f * log_a + 0.65f, 2.7f) - 0.72f;
  84. } else {
  85. r = log_a - 1.255f;
  86. }
  87. result = powf(10.0f , r);
  88. return result;
  89. }
  90. /* computes the contrast sensitivity function (Barten SPIE 1989)
  91. * given the cycles per degree (cpd) and luminance (lum)
  92. */
  93. static float
  94. csf (float cpd, float lum)
  95. {
  96. float a, b, result;
  97. a = 440.0f * powf((1.0f + 0.7f / lum), -0.2f);
  98. b = 0.3f * powf((1.0f + 100.0f / lum), 0.15f);
  99. result = a * cpd * expf(-b * cpd) * sqrtf(1.0f + 0.06f * expf(b * cpd));
  100. return result;
  101. }
  102. /*
  103. * Visual Masking Function
  104. * from Daly 1993
  105. */
  106. static float
  107. mask (float contrast)
  108. {
  109. float a, b, result;
  110. a = powf(392.498f * contrast, 0.7f);
  111. b = powf(0.0153f * a, 4.0f);
  112. result = powf(1.0f + b, 0.25f);
  113. return result;
  114. }
  115. /* convert Adobe RGB (1998) with reference white D65 to XYZ */
  116. static void
  117. AdobeRGBToXYZ (float r, float g, float b, float *x, float *y, float *z)
  118. {
  119. /* matrix is from http://www.brucelindbloom.com/ */
  120. *x = r * 0.576700f + g * 0.185556f + b * 0.188212f;
  121. *y = r * 0.297361f + g * 0.627355f + b * 0.0752847f;
  122. *z = r * 0.0270328f + g * 0.0706879f + b * 0.991248f;
  123. }
  124. static void
  125. XYZToLAB (float x, float y, float z, float *L, float *A, float *B)
  126. {
  127. static float xw = -1;
  128. static float yw;
  129. static float zw;
  130. const float epsilon = 216.0f / 24389.0f;
  131. const float kappa = 24389.0f / 27.0f;
  132. float f[3];
  133. float r[3];
  134. int i;
  135. /* reference white */
  136. if (xw < 0) {
  137. AdobeRGBToXYZ(1, 1, 1, &xw, &yw, &zw);
  138. }
  139. r[0] = x / xw;
  140. r[1] = y / yw;
  141. r[2] = z / zw;
  142. for (i = 0; i < 3; i++) {
  143. if (r[i] > epsilon) {
  144. f[i] = powf(r[i], 1.0f / 3.0f);
  145. } else {
  146. f[i] = (kappa * r[i] + 16.0f) / 116.0f;
  147. }
  148. }
  149. *L = 116.0f * f[1] - 16.0f;
  150. *A = 500.0f * (f[0] - f[1]);
  151. *B = 200.0f * (f[1] - f[2]);
  152. }
  153. static uint32_t
  154. _get_pixel (const uint32_t *data, int i)
  155. {
  156. return data[i];
  157. }
  158. static unsigned char
  159. _get_red (const uint32_t *data, int i)
  160. {
  161. uint32_t pixel;
  162. uint8_t alpha;
  163. pixel = _get_pixel (data, i);
  164. alpha = (pixel & 0xff000000) >> 24;
  165. if (alpha == 0)
  166. return 0;
  167. else
  168. return (((pixel & 0x00ff0000) >> 16) * 255 + alpha / 2) / alpha;
  169. }
  170. static unsigned char
  171. _get_green (const uint32_t *data, int i)
  172. {
  173. uint32_t pixel;
  174. uint8_t alpha;
  175. pixel = _get_pixel (data, i);
  176. alpha = (pixel & 0xff000000) >> 24;
  177. if (alpha == 0)
  178. return 0;
  179. else
  180. return (((pixel & 0x0000ff00) >> 8) * 255 + alpha / 2) / alpha;
  181. }
  182. static unsigned char
  183. _get_blue (const uint32_t *data, int i)
  184. {
  185. uint32_t pixel;
  186. uint8_t alpha;
  187. pixel = _get_pixel (data, i);
  188. alpha = (pixel & 0xff000000) >> 24;
  189. if (alpha == 0)
  190. return 0;
  191. else
  192. return (((pixel & 0x000000ff) >> 0) * 255 + alpha / 2) / alpha;
  193. }
  194. static void *
  195. xmalloc (size_t size)
  196. {
  197. void *buf;
  198. buf = malloc (size);
  199. if (buf == NULL) {
  200. fprintf (stderr, "Out of memory.\n");
  201. exit (1);
  202. }
  203. return buf;
  204. }
  205. int
  206. pdiff_compare (cairo_surface_t *surface_a,
  207. cairo_surface_t *surface_b,
  208. double gamma,
  209. double luminance,
  210. double field_of_view)
  211. {
  212. unsigned int dim = (cairo_image_surface_get_width (surface_a)
  213. * cairo_image_surface_get_height (surface_a));
  214. unsigned int i;
  215. /* assuming colorspaces are in Adobe RGB (1998) convert to XYZ */
  216. float *aX;
  217. float *aY;
  218. float *aZ;
  219. float *bX;
  220. float *bY;
  221. float *bZ;
  222. float *aLum;
  223. float *bLum;
  224. float *aA;
  225. float *bA;
  226. float *aB;
  227. float *bB;
  228. unsigned int x, y, w, h;
  229. lpyramid_t *la, *lb;
  230. float num_one_degree_pixels, pixels_per_degree, num_pixels;
  231. unsigned int adaptation_level;
  232. float cpd[MAX_PYR_LEVELS];
  233. float F_freq[MAX_PYR_LEVELS - 2];
  234. float csf_max;
  235. const uint32_t *data_a, *data_b;
  236. unsigned int pixels_failed;
  237. w = cairo_image_surface_get_width (surface_a);
  238. h = cairo_image_surface_get_height (surface_a);
  239. if (w < 3 || h < 3) /* too small for the Laplacian convolution */
  240. return -1;
  241. aX = xmalloc (dim * sizeof (float));
  242. aY = xmalloc (dim * sizeof (float));
  243. aZ = xmalloc (dim * sizeof (float));
  244. bX = xmalloc (dim * sizeof (float));
  245. bY = xmalloc (dim * sizeof (float));
  246. bZ = xmalloc (dim * sizeof (float));
  247. aLum = xmalloc (dim * sizeof (float));
  248. bLum = xmalloc (dim * sizeof (float));
  249. aA = xmalloc (dim * sizeof (float));
  250. bA = xmalloc (dim * sizeof (float));
  251. aB = xmalloc (dim * sizeof (float));
  252. bB = xmalloc (dim * sizeof (float));
  253. data_a = (uint32_t *) cairo_image_surface_get_data (surface_a);
  254. data_b = (uint32_t *) cairo_image_surface_get_data (surface_b);
  255. for (y = 0; y < h; y++) {
  256. for (x = 0; x < w; x++) {
  257. float r, g, b, l;
  258. i = x + y * w;
  259. r = powf(_get_red (data_a, i) / 255.0f, gamma);
  260. g = powf(_get_green (data_a, i) / 255.0f, gamma);
  261. b = powf(_get_blue (data_a, i) / 255.0f, gamma);
  262. AdobeRGBToXYZ(r,g,b,&aX[i],&aY[i],&aZ[i]);
  263. XYZToLAB(aX[i], aY[i], aZ[i], &l, &aA[i], &aB[i]);
  264. r = powf(_get_red (data_b, i) / 255.0f, gamma);
  265. g = powf(_get_green (data_b, i) / 255.0f, gamma);
  266. b = powf(_get_blue (data_b, i) / 255.0f, gamma);
  267. AdobeRGBToXYZ(r,g,b,&bX[i],&bY[i],&bZ[i]);
  268. XYZToLAB(bX[i], bY[i], bZ[i], &l, &bA[i], &bB[i]);
  269. aLum[i] = aY[i] * luminance;
  270. bLum[i] = bY[i] * luminance;
  271. }
  272. }
  273. la = lpyramid_create (aLum, w, h);
  274. lb = lpyramid_create (bLum, w, h);
  275. num_one_degree_pixels = (float) (2 * tan(field_of_view * 0.5 * M_PI / 180) * 180 / M_PI);
  276. pixels_per_degree = w / num_one_degree_pixels;
  277. num_pixels = 1;
  278. adaptation_level = 0;
  279. for (i = 0; i < MAX_PYR_LEVELS; i++) {
  280. adaptation_level = i;
  281. if (num_pixels > num_one_degree_pixels) break;
  282. num_pixels *= 2;
  283. }
  284. cpd[0] = 0.5f * pixels_per_degree;
  285. for (i = 1; i < MAX_PYR_LEVELS; i++) cpd[i] = 0.5f * cpd[i - 1];
  286. csf_max = csf(3.248f, 100.0f);
  287. for (i = 0; i < MAX_PYR_LEVELS - 2; i++) F_freq[i] = csf_max / csf( cpd[i], 100.0f);
  288. pixels_failed = 0;
  289. for (y = 0; y < h; y++) {
  290. for (x = 0; x < w; x++) {
  291. int index = x + y * w;
  292. float contrast[MAX_PYR_LEVELS - 2];
  293. float F_mask[MAX_PYR_LEVELS - 2];
  294. float factor;
  295. float delta;
  296. float adapt;
  297. bool pass;
  298. float sum_contrast = 0;
  299. for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
  300. float n1 = fabsf(lpyramid_get_value (la,x,y,i) - lpyramid_get_value (la,x,y,i + 1));
  301. float n2 = fabsf(lpyramid_get_value (lb,x,y,i) - lpyramid_get_value (lb,x,y,i + 1));
  302. float numerator = (n1 > n2) ? n1 : n2;
  303. float d1 = fabsf(lpyramid_get_value(la,x,y,i+2));
  304. float d2 = fabsf(lpyramid_get_value(lb,x,y,i+2));
  305. float denominator = (d1 > d2) ? d1 : d2;
  306. if (denominator < 1e-5f) denominator = 1e-5f;
  307. contrast[i] = numerator / denominator;
  308. sum_contrast += contrast[i];
  309. }
  310. if (sum_contrast < 1e-5) sum_contrast = 1e-5f;
  311. adapt = lpyramid_get_value(la,x,y,adaptation_level) + lpyramid_get_value(lb,x,y,adaptation_level);
  312. adapt *= 0.5f;
  313. if (adapt < 1e-5) adapt = 1e-5f;
  314. for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
  315. F_mask[i] = mask(contrast[i] * csf(cpd[i], adapt));
  316. }
  317. factor = 0;
  318. for (i = 0; i < MAX_PYR_LEVELS - 2; i++) {
  319. factor += contrast[i] * F_freq[i] * F_mask[i] / sum_contrast;
  320. }
  321. if (factor < 1) factor = 1;
  322. if (factor > 10) factor = 10;
  323. delta = fabsf(lpyramid_get_value(la,x,y,0) - lpyramid_get_value(lb,x,y,0));
  324. pass = true;
  325. /* pure luminance test */
  326. if (delta > factor * tvi(adapt)) {
  327. pass = false;
  328. } else {
  329. /* CIE delta E test with modifications */
  330. float color_scale = 1.0f;
  331. float da = aA[index] - bA[index];
  332. float db = aB[index] - bB[index];
  333. float delta_e;
  334. /* ramp down the color test in scotopic regions */
  335. if (adapt < 10.0f) {
  336. color_scale = 1.0f - (10.0f - color_scale) / 10.0f;
  337. color_scale = color_scale * color_scale;
  338. }
  339. da = da * da;
  340. db = db * db;
  341. delta_e = (da + db) * color_scale;
  342. if (delta_e > factor) {
  343. pass = false;
  344. }
  345. }
  346. if (!pass)
  347. pixels_failed++;
  348. }
  349. }
  350. free (aX);
  351. free (aY);
  352. free (aZ);
  353. free (bX);
  354. free (bY);
  355. free (bZ);
  356. free (aLum);
  357. free (bLum);
  358. lpyramid_destroy (la);
  359. lpyramid_destroy (lb);
  360. free (aA);
  361. free (bA);
  362. free (aB);
  363. free (bB);
  364. return pixels_failed;
  365. }