| 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 |