OLD | NEW |
| 1 /* |
| 2 * Copyright 2013 Google Inc. |
| 3 * |
| 4 * Use of this source code is governed by a BSD-style license that can be |
| 5 * found in the LICENSE file. |
| 6 */ |
1 #include <cmath> | 7 #include <cmath> |
2 #include <math.h> | 8 #include <math.h> |
3 | 9 |
4 #include "SkBitmap.h" | 10 #include "SkBitmap.h" |
5 #include "skpdiff_util.h" | 11 #include "skpdiff_util.h" |
6 #include "SkPMetric.h" | 12 #include "SkPMetric.h" |
7 #include "SkPMetricUtil_generated.h" | 13 #include "SkPMetricUtil_generated.h" |
8 | 14 |
9 struct RGB { | 15 struct RGB { |
10 float r, g, b; | 16 float r, g, b; |
11 }; | 17 }; |
12 | 18 |
13 struct LAB { | 19 struct LAB { |
14 float l, a, b; | 20 float l, a, b; |
15 }; | 21 }; |
16 | 22 |
17 template<class T> | 23 template<class T> |
18 struct Image2D { | 24 struct Image2D { |
19 int width; | 25 int width; |
20 int height; | 26 int height; |
21 T* image; | 27 T* image; |
22 | 28 |
23 Image2D(int w, int h) | 29 Image2D(int w, int h) |
24 : width(w), | 30 : width(w), |
25 height(h) { | 31 height(h) { |
26 SkASSERT(w > 0); | 32 SkASSERT(w > 0); |
27 SkASSERT(h > 0); | 33 SkASSERT(h > 0); |
28 image = SkNEW_ARRAY(T, w * h); | 34 image = new T[w * h]; |
29 } | 35 } |
30 | 36 |
31 ~Image2D() { | 37 ~Image2D() { delete[] image; } |
32 SkDELETE_ARRAY(image); | |
33 } | |
34 | 38 |
35 void readPixel(int x, int y, T* pixel) const { | 39 void readPixel(int x, int y, T* pixel) const { |
36 SkASSERT(x >= 0); | 40 SkASSERT(x >= 0); |
37 SkASSERT(y >= 0); | 41 SkASSERT(y >= 0); |
38 SkASSERT(x < width); | 42 SkASSERT(x < width); |
39 SkASSERT(y < height); | 43 SkASSERT(y < height); |
40 *pixel = image[y * width + x]; | 44 *pixel = image[y * width + x]; |
41 } | 45 } |
42 | 46 |
43 T* getRow(int y) const { | 47 T* getRow(int y) const { |
(...skipping 15 matching lines...) Expand all Loading... |
59 | 63 |
60 template<class T> | 64 template<class T> |
61 struct ImageArray | 65 struct ImageArray |
62 { | 66 { |
63 int slices; | 67 int slices; |
64 Image2D<T>** image; | 68 Image2D<T>** image; |
65 | 69 |
66 ImageArray(int w, int h, int s) | 70 ImageArray(int w, int h, int s) |
67 : slices(s) { | 71 : slices(s) { |
68 SkASSERT(s > 0); | 72 SkASSERT(s > 0); |
69 image = SkNEW_ARRAY(Image2D<T>*, s); | 73 image = new Image2D<T>* [s]; |
70 for (int sliceIndex = 0; sliceIndex < slices; sliceIndex++) { | 74 for (int sliceIndex = 0; sliceIndex < slices; sliceIndex++) { |
71 image[sliceIndex] = SkNEW_ARGS(Image2D<T>, (w, h)); | 75 image[sliceIndex] = new Image2D<T>(w, h); |
72 } | 76 } |
73 } | 77 } |
74 | 78 |
75 ~ImageArray() { | 79 ~ImageArray() { |
76 for (int sliceIndex = 0; sliceIndex < slices; sliceIndex++) { | 80 for (int sliceIndex = 0; sliceIndex < slices; sliceIndex++) { |
77 SkDELETE(image[sliceIndex]); | 81 delete image[sliceIndex]; |
78 } | 82 } |
79 SkDELETE_ARRAY(image); | 83 delete[] image; |
80 } | 84 } |
81 | 85 |
82 Image2D<T>* getLayer(int z) const { | 86 Image2D<T>* getLayer(int z) const { |
83 SkASSERT(z >= 0); | 87 SkASSERT(z >= 0); |
84 SkASSERT(z < slices); | 88 SkASSERT(z < slices); |
85 return image[z]; | 89 return image[z]; |
86 } | 90 } |
87 }; | 91 }; |
88 | 92 |
89 typedef ImageArray<float> ImageL3D; | 93 typedef ImageArray<float> ImageL3D; |
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
289 return 0.0; | 293 return 0.0; |
290 } | 294 } |
291 | 295 |
292 const float fov = SK_ScalarPI / 180.0f * 45.0f; | 296 const float fov = SK_ScalarPI / 180.0f * 45.0f; |
293 float contrastSensitivityMax = contrast_sensitivity(3.248f, 100.0f); | 297 float contrastSensitivityMax = contrast_sensitivity(3.248f, 100.0f); |
294 float pixelsPerDegree = width / (2.0f * tanf(fov * 0.5f) * 180.0f / SK_Scala
rPI); | 298 float pixelsPerDegree = width / (2.0f * tanf(fov * 0.5f) * 180.0f / SK_Scala
rPI); |
295 | 299 |
296 ImageL3D baselineL(width, height, maxLevels); | 300 ImageL3D baselineL(width, height, maxLevels); |
297 ImageL3D testL(width, height, maxLevels); | 301 ImageL3D testL(width, height, maxLevels); |
298 ImageL scratchImageL(width, height); | 302 ImageL scratchImageL(width, height); |
299 float* cyclesPerDegree = SkNEW_ARRAY(float, maxLevels); | 303 float* cyclesPerDegree = new float[maxLevels]; |
300 float* thresholdFactorFrequency = SkNEW_ARRAY(float, maxLevels - 2); | 304 float* thresholdFactorFrequency = new float[maxLevels - 2]; |
301 float* contrast = SkNEW_ARRAY(float, maxLevels - 2); | 305 float* contrast = new float[maxLevels - 2]; |
302 | 306 |
303 lab_to_l(baselineLAB, baselineL.getLayer(0)); | 307 lab_to_l(baselineLAB, baselineL.getLayer(0)); |
304 lab_to_l(testLAB, testL.getLayer(0)); | 308 lab_to_l(testLAB, testL.getLayer(0)); |
305 | 309 |
306 // Compute cpd - Cycles per degree on the pyramid | 310 // Compute cpd - Cycles per degree on the pyramid |
307 cyclesPerDegree[0] = 0.5f * pixelsPerDegree; | 311 cyclesPerDegree[0] = 0.5f * pixelsPerDegree; |
308 for (int levelIndex = 1; levelIndex < maxLevels; levelIndex++) { | 312 for (int levelIndex = 1; levelIndex < maxLevels; levelIndex++) { |
309 cyclesPerDegree[levelIndex] = cyclesPerDegree[levelIndex - 1] * 0.5f; | 313 cyclesPerDegree[levelIndex] = cyclesPerDegree[levelIndex - 1] * 0.5f; |
310 } | 314 } |
311 | 315 |
312 // Contrast sensitivity is based on image dimensions. Therefore it cannot be
statically | 316 // Contrast sensitivity is based on image dimensions. Therefore it cannot be
statically |
313 // generated. | 317 // generated. |
314 float* contrastSensitivityTable = SkNEW_ARRAY(float, maxLevels * 1000); | 318 float* contrastSensitivityTable = new float[maxLevels * 1000]; |
315 for (int levelIndex = 0; levelIndex < maxLevels; levelIndex++) { | 319 for (int levelIndex = 0; levelIndex < maxLevels; levelIndex++) { |
316 for (int csLum = 0; csLum < 1000; csLum++) { | 320 for (int csLum = 0; csLum < 1000; csLum++) { |
317 contrastSensitivityTable[levelIndex * 1000 + csLum] = | 321 contrastSensitivityTable[levelIndex * 1000 + csLum] = |
318 contrast_sensitivity(cyclesPerDegree[levelIndex], (float)csLum / 10.0
f + 1e-5f); | 322 contrast_sensitivity(cyclesPerDegree[levelIndex], (float)csLum / 10.0
f + 1e-5f); |
319 } | 323 } |
320 } | 324 } |
321 | 325 |
322 // Compute G - The convolved lum for the baseline | 326 // Compute G - The convolved lum for the baseline |
323 for (int levelIndex = 1; levelIndex < maxLevels; levelIndex++) { | 327 for (int levelIndex = 1; levelIndex < maxLevels; levelIndex++) { |
324 convolve(baselineL.getLayer(levelIndex - 1), false, &scratchImageL); | 328 convolve(baselineL.getLayer(levelIndex - 1), false, &scratchImageL); |
(...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 isFailure = true; | 432 isFailure = true; |
429 } | 433 } |
430 } | 434 } |
431 | 435 |
432 if (isFailure) { | 436 if (isFailure) { |
433 (*poiCount)++; | 437 (*poiCount)++; |
434 } | 438 } |
435 } | 439 } |
436 } | 440 } |
437 | 441 |
438 SkDELETE_ARRAY(cyclesPerDegree); | 442 delete[] cyclesPerDegree; |
439 SkDELETE_ARRAY(contrast); | 443 delete[] contrast; |
440 SkDELETE_ARRAY(thresholdFactorFrequency); | 444 delete[] thresholdFactorFrequency; |
441 SkDELETE_ARRAY(contrastSensitivityTable); | 445 delete[] contrastSensitivityTable; |
442 return 1.0 - (double)(*poiCount) / (width * height); | 446 return 1.0 - (double)(*poiCount) / (width * height); |
443 } | 447 } |
444 | 448 |
445 bool SkPMetric::diff(SkBitmap* baseline, SkBitmap* test, const BitmapsToCreate&
bitmapsToCreate, | 449 bool SkPMetric::diff(SkBitmap* baseline, SkBitmap* test, const BitmapsToCreate&
bitmapsToCreate, |
446 Result* result) const { | 450 Result* result) const { |
447 double startTime = get_seconds(); | 451 double startTime = get_seconds(); |
448 | 452 |
449 // Ensure the images are comparable | 453 // Ensure the images are comparable |
450 if (baseline->width() != test->width() || baseline->height() != test->height
() || | 454 if (baseline->width() != test->width() || baseline->height() != test->height
() || |
451 baseline->width() <= 0 || baseline->height() <= 0) { | 455 baseline->width() <= 0 || baseline->height() <= 0) { |
452 return false; | 456 return false; |
453 } | 457 } |
454 | 458 |
455 ImageLAB baselineLAB(baseline->width(), baseline->height()); | 459 ImageLAB baselineLAB(baseline->width(), baseline->height()); |
456 ImageLAB testLAB(baseline->width(), baseline->height()); | 460 ImageLAB testLAB(baseline->width(), baseline->height()); |
457 | 461 |
458 if (!bitmap_to_cielab(baseline, &baselineLAB) || !bitmap_to_cielab(test, &te
stLAB)) { | 462 if (!bitmap_to_cielab(baseline, &baselineLAB) || !bitmap_to_cielab(test, &te
stLAB)) { |
459 return true; | 463 return true; |
460 } | 464 } |
461 | 465 |
462 result->poiCount = 0; | 466 result->poiCount = 0; |
463 result->result = pmetric(&baselineLAB, &testLAB, &result->poiCount); | 467 result->result = pmetric(&baselineLAB, &testLAB, &result->poiCount); |
464 result->timeElapsed = get_seconds() - startTime; | 468 result->timeElapsed = get_seconds() - startTime; |
465 | 469 |
466 return true; | 470 return true; |
467 } | 471 } |
OLD | NEW |