Chromium Code Reviews| Index: cc/test/pixel_comparator.cc |
| diff --git a/cc/test/pixel_comparator.cc b/cc/test/pixel_comparator.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..35c4f6b60ebe38a1a9acd59067f5ab36115f2e91 |
| --- /dev/null |
| +++ b/cc/test/pixel_comparator.cc |
| @@ -0,0 +1,183 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "cc/test/pixel_comparator.h" |
| + |
| +#include <algorithm> |
| + |
| +#include "base/logging.h" |
| + |
| +namespace cc { |
| + |
| +bool PixelComparator::CompareSize(const SkBitmap& actual_bmp, |
| + const SkBitmap& expected_bmp) const |
| +{ |
|
reveman
2013/03/07 21:41:25
{ should be on previous line
ernstm
2013/03/08 00:14:46
Done.
|
| + if (actual_bmp.width() != expected_bmp.width() || |
| + actual_bmp.height() != expected_bmp.height()) { |
| + LOG(ERROR) |
| + << "Dimensions do not match! " |
| + << "Actual: " << actual_bmp.width() << "x" << actual_bmp.height() << "; " |
|
reveman
2013/03/07 21:41:25
line too long
ernstm
2013/03/08 00:14:46
Done.
|
| + << "Expected: " << expected_bmp.width() << "x" << expected_bmp.height() << ""; |
|
reveman
2013/03/07 21:41:25
line too long
ernstm
2013/03/08 00:14:46
Done.
|
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool ExactPixelComparator::Compare(const SkBitmap& actual_bmp, |
| + const SkBitmap& expected_bmp) const { |
| + // Number of pixels with an error |
| + unsigned int error_pixels_count = 0; |
| + |
| + // Bitmaps must have same dimensions |
| + if (!CompareSize(actual_bmp, expected_bmp)) return false; |
| + |
| + SkAutoLockPixels lock_actual_bmp(actual_bmp); |
| + SkAutoLockPixels lock_expected_bmp(expected_bmp); |
| + |
| + // The reference images were saved with no alpha channel. Use the mask to |
| + // set alpha to 0. |
| + uint32_t kAlphaMask = 0x00FFFFFF; |
| + for (int x = 0; x < actual_bmp.width(); ++x) { |
| + for (int y = 0; y < actual_bmp.height(); ++y) { |
| + if ((*actual_bmp.getAddr32(x, y) & kAlphaMask) != |
| + (*expected_bmp.getAddr32(x, y) & kAlphaMask)) { |
| + ++error_pixels_count; |
| + } |
| + } |
| + } |
| + |
| + if (error_pixels_count != 0) { |
| + LOG(ERROR) << "Number of pixel with an error: " << error_pixels_count; |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +FuzzyPixelComparator::FuzzyPixelComparator( |
| + const float error_pixels_percentage_limit, |
| + const float small_error_pixels_percentage_limit, |
| + const float avg_abs_error_limit, |
| + const unsigned int max_abs_error_limit, |
| + const unsigned int small_error_threshold) |
| + : error_pixels_percentage_limit_(error_pixels_percentage_limit), |
| + small_error_pixels_percentage_limit_(small_error_pixels_percentage_limit), |
| + avg_abs_error_limit_(avg_abs_error_limit), |
| + max_abs_error_limit_(max_abs_error_limit), |
| + small_error_threshold_(small_error_threshold) { |
| +} |
| + |
| +bool FuzzyPixelComparator::Compare(const SkBitmap& actual_bmp, |
| + const SkBitmap& expected_bmp) const { |
| + // Number of pixels with an error |
| + unsigned int error_pixels_count = 0; |
| + // Number of pixels with a small error |
| + unsigned int small_error_pixels_count = 0; |
| + // The per channel sums of absolute errors over all pixels. |
| + unsigned long long sum_abs_error_r = 0; |
|
reveman
2013/03/07 21:41:25
I think you should use int64/uint64 instead of lon
ernstm
2013/03/08 00:14:46
Done.
|
| + unsigned long long sum_abs_error_g = 0; |
| + unsigned long long sum_abs_error_b = 0; |
| + // The per channel maximum absolute errors over all pixels. |
| + unsigned int max_abs_error_r = 0; |
| + unsigned int max_abs_error_g = 0; |
| + unsigned int max_abs_error_b = 0; |
| + |
| + // Bitmaps must have same dimensions |
| + if (!CompareSize(actual_bmp, expected_bmp)) return false; |
| + |
| + // Empty bitmaps are always considered to be equal. |
| + if (actual_bmp.width() == 0 || actual_bmp.height() == 0) return true; |
| + |
| + SkAutoLockPixels lock_actual_bmp(actual_bmp); |
| + SkAutoLockPixels lock_expected_bmp(expected_bmp); |
| + |
| + // The reference images were saved with no alpha channel. Use the mask to |
| + // set alpha to 0. |
| + uint32_t kAlphaMask = 0x00FFFFFF; |
|
reveman
2013/03/07 21:41:25
This makes assumptions about the pixel format used
ernstm
2013/03/08 00:14:46
Modified to use SkColorSetA instead instead of dir
|
| + for (int x = 0; x < actual_bmp.width(); ++x) { |
| + for (int y = 0; y < actual_bmp.height(); ++y) { |
| + if ((*actual_bmp.getAddr32(x, y) & kAlphaMask) != |
| + (*expected_bmp.getAddr32(x, y) & kAlphaMask)) { |
| + ++error_pixels_count; |
| + |
| + SkColor color_a = actual_bmp.getColor(x, y); |
| + SkColor color_b = expected_bmp.getColor(x, y); |
| + |
| + // Compute per channel absolute errors |
| + unsigned int abs_error_r = |
| + std::max(SkColorGetR(color_a), SkColorGetR(color_b)) - |
| + std::min(SkColorGetR(color_a), SkColorGetR(color_b)); |
| + unsigned int abs_error_g = |
| + std::max(SkColorGetG(color_a), SkColorGetG(color_b)) - |
| + std::min(SkColorGetG(color_a), SkColorGetG(color_b)); |
| + unsigned int abs_error_b = |
| + std::max(SkColorGetB(color_a), SkColorGetB(color_b)) - |
| + std::min(SkColorGetB(color_a), SkColorGetB(color_b)); |
| + |
| + // Increment small error counter if error is below threshold |
| + if (abs_error_r <= small_error_threshold_ && |
| + abs_error_g <= small_error_threshold_ && |
| + abs_error_b <= small_error_threshold_) |
| + ++small_error_pixels_count; |
| + |
| + // Update per channel maximum absolute errors |
| + if (abs_error_r > max_abs_error_r) max_abs_error_r = abs_error_r; |
| + if (abs_error_g > max_abs_error_g) max_abs_error_g = abs_error_g; |
| + if (abs_error_b > max_abs_error_b) max_abs_error_b = abs_error_b; |
| + |
| + // Update per channel absolute error sums |
| + sum_abs_error_r += abs_error_r; |
| + sum_abs_error_g += abs_error_g; |
| + sum_abs_error_b += abs_error_b; |
| + } |
| + } |
| + } |
| + |
| + // Compute error metrics from collected data |
| + unsigned int pixels_count = actual_bmp.width() * actual_bmp.height(); |
| + float error_pixels_percentage = static_cast<float>(error_pixels_count) / |
| + pixels_count * 100.0f; |
| + float small_error_pixels_percentage = static_cast<float>(small_error_pixels_count) / |
|
reveman
2013/03/07 21:41:25
line too long
ernstm
2013/03/08 00:14:46
Done.
|
| + pixels_count * 100.0f; |
| + float avg_abs_error_r; |
| + float avg_abs_error_g; |
| + float avg_abs_error_b; |
| + if (error_pixels_count > 0) { |
| + avg_abs_error_r = static_cast<float>(sum_abs_error_r) / error_pixels_count; |
| + avg_abs_error_g = static_cast<float>(sum_abs_error_g) / error_pixels_count; |
| + avg_abs_error_b = static_cast<float>(sum_abs_error_b) / error_pixels_count; |
| + } else { |
| + avg_abs_error_r = 0; |
| + avg_abs_error_g = 0; |
| + avg_abs_error_b = 0; |
| + } |
| + |
| + if (error_pixels_percentage > error_pixels_percentage_limit_ || |
| + small_error_pixels_percentage > small_error_pixels_percentage_limit_ || |
| + avg_abs_error_r > avg_abs_error_limit_ || |
| + avg_abs_error_g > avg_abs_error_limit_ || |
| + avg_abs_error_b > avg_abs_error_limit_ || |
| + max_abs_error_r > max_abs_error_limit_ || |
| + max_abs_error_g > max_abs_error_limit_ || |
| + max_abs_error_b > max_abs_error_limit_) { |
| + LOG(ERROR) << "Percentage of pixels with an error: " |
| + << error_pixels_percentage << "; " |
| + << "Percentage of pixels with errors not greater than " |
| + << small_error_threshold_ << ": " |
| + << small_error_pixels_percentage << "; " |
| + << "Average absolute error (excluding identical pixels): " |
| + << "R=" << avg_abs_error_r << " " |
| + << "G=" << avg_abs_error_g << " " |
| + << "B=" << avg_abs_error_b << "; " |
| + << "Largest absolute error: " |
| + << "R=" << max_abs_error_r << " " |
| + << "G=" << max_abs_error_g << " " |
| + << "B=" << max_abs_error_b; |
| + return false; |
| + } else { |
| + return true; |
| + } |
| +} |
| + |
| +} // namespace cc |