Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(3809)

Unified Diff: cc/test/image_comparator.cc

Issue 12558003: cc: Made image comparison for pixel tests error tolerant. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: cc/test/image_comparator.cc
diff --git a/cc/test/image_comparator.cc b/cc/test/image_comparator.cc
new file mode 100644
index 0000000000000000000000000000000000000000..844a22a53ea03ff2a10a98b43d8378b7438e8a98
--- /dev/null
+++ b/cc/test/image_comparator.cc
@@ -0,0 +1,179 @@
+// 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/image_comparator.h"
+
+#include <algorithm>
+
+namespace cc {
+
+ImageComparator::ImageComparator() {
+ thresholds_ = ErrorMetrics();
+}
+
+ImageComparator::ImageComparator(const ErrorMetrics& thresholds)
+ : thresholds_(thresholds)
+{ }
+
+ImageComparator::ErrorMetrics::ErrorMetrics(float error_pixels_percentage,
+ float small_error_pixels_percentage,
+ float avg_abs_error_r,
+ float avg_abs_error_g,
+ float avg_abs_error_b,
+ unsigned int max_abs_error_r,
+ unsigned int max_abs_error_g,
+ unsigned int max_abs_error_b,
+ unsigned int small_error_threshold)
+ : error_pixels_percentage(error_pixels_percentage),
+ small_error_pixels_percentage(small_error_pixels_percentage),
+ avg_abs_error_r(avg_abs_error_r),
+ avg_abs_error_g(avg_abs_error_g),
+ avg_abs_error_b(avg_abs_error_b),
+ max_abs_error_r(max_abs_error_r),
+ max_abs_error_g(max_abs_error_g),
+ max_abs_error_b(max_abs_error_b),
+ small_error_threshold(small_error_threshold)
+{ }
+
+void ImageComparator::AllowOffByOneErrors(float off_by_one_pixels_percentage) {
+ thresholds_.error_pixels_percentage = off_by_one_pixels_percentage;
+ thresholds_.small_error_pixels_percentage = off_by_one_pixels_percentage;
+ thresholds_.avg_abs_error_r = 1.0f;
+ thresholds_.avg_abs_error_g = 1.0f;
+ thresholds_.avg_abs_error_b = 1.0f;
+ thresholds_.max_abs_error_r = 1.0f;
+ thresholds_.max_abs_error_g = 1.0f;
+ thresholds_.max_abs_error_b = 1.0f;
+ thresholds_.small_error_threshold = 1;
+}
+
+bool ImageComparator::Compare(const SkBitmap& bitmap_a,
+ const SkBitmap& bitmap_b,
+ ErrorMetrics* return_metrics) const {
+ ErrorMetrics metrics;
+ metrics.small_error_threshold = thresholds_.small_error_threshold;
+
+ // Number of pixels that are different.
+ unsigned int error_pixels_count = 0;
+ // Number of pixels that are at most off by small_error_threshold per color
+ // channel
+ unsigned int small_error_pixels_count = 0;
+ // The per channel sum of absolute errors over all pixels.
+ unsigned long long sum_abs_error_r = 0;
+ unsigned long long sum_abs_error_g = 0;
+ unsigned long long sum_abs_error_b = 0;
+
+ // A meaningful comparison is not possible if the size does not match
+ // (alignment? background color?). Return maximum error values in that case.
+ if (bitmap_a.width() != bitmap_b.width() ||
+ bitmap_a.height() != bitmap_b.height()) {
reveman 2013/03/07 07:50:44 MatchesPNGFile already check the size. DCHECK is e
ernstm 2013/03/07 19:30:07 Moved all dimension checking into Compare function
+ if (return_metrics != NULL) {
+ return_metrics->error_pixels_percentage = 100.0f;
+ return_metrics->small_error_pixels_percentage = 0.0f;
+ return_metrics->avg_abs_error_r = 255.0f;
+ return_metrics->avg_abs_error_g = 255.0f;
+ return_metrics->avg_abs_error_b = 255.0f;
+ return_metrics->max_abs_error_r = 255;
+ return_metrics->max_abs_error_g = 255;
+ return_metrics->max_abs_error_b = 255;
+ return_metrics->small_error_threshold = thresholds_.small_error_threshold;
+ }
+ return false;
+ }
+
+ // Empty bitmaps are always considered to be equal.
+ if (bitmap_a.width() == 0 || bitmap_a.height() == 0) {
reveman 2013/03/07 07:50:44 move this to MatchesPNGFile if needed. DCHECK at m
ernstm 2013/03/07 19:30:07 This got much simpler in the refactored code. On 2
+ if (return_metrics != NULL) {
+ return_metrics->error_pixels_percentage = 0.0f;
+ return_metrics->small_error_pixels_percentage = 0.0f;
+ return_metrics->avg_abs_error_r = 0.0f;
+ return_metrics->avg_abs_error_g = 0.0f;
+ return_metrics->avg_abs_error_b = 0.0f;
+ return_metrics->max_abs_error_r = 0;
+ return_metrics->max_abs_error_g = 0;
+ return_metrics->max_abs_error_b = 0;
+ return_metrics->small_error_threshold = thresholds_.small_error_threshold;
+ }
+ return true;
+ }
+
+ SkAutoLockPixels lock_bitmap_a(bitmap_a);
+ SkAutoLockPixels lock_bitmap_b(bitmap_b);
+
+ // 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 < bitmap_a.width(); ++x) {
+ for (int y = 0; y < bitmap_a.height(); ++y) {
+ if ((*bitmap_a.getAddr32(x, y) & kAlphaMask) !=
+ (*bitmap_b.getAddr32(x, y) & kAlphaMask)) {
+ ++error_pixels_count;
+
+ SkColor color_a = bitmap_a.getColor(x, y);
+ SkColor color_b = bitmap_b.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 <= thresholds_.small_error_threshold &&
+ abs_error_g <= thresholds_.small_error_threshold &&
+ abs_error_b <= thresholds_.small_error_threshold)
+ ++small_error_pixels_count;
+
+ // Update per channel maximum absolute errors
+ if (abs_error_r > metrics.max_abs_error_r)
+ metrics.max_abs_error_r = abs_error_r;
+ if (abs_error_g > metrics.max_abs_error_g)
+ metrics.max_abs_error_g = abs_error_g;
+ if (abs_error_b > metrics.max_abs_error_b)
+ metrics.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;
+ }
+ }
+ }
+
+ // Fill error metrics with collected data
+ unsigned int pixels_count = bitmap_a.width() * bitmap_a.height();
+ metrics.error_pixels_percentage = static_cast<float>(error_pixels_count) /
+ pixels_count * 100.0f;
+ metrics.small_error_pixels_percentage = static_cast<float>(small_error_pixels_count) /
+ pixels_count * 100.0f;
+ if (error_pixels_count > 0) {
+ metrics.avg_abs_error_r = static_cast<float>(sum_abs_error_r) / error_pixels_count;
+ metrics.avg_abs_error_g = static_cast<float>(sum_abs_error_g) / error_pixels_count;
+ metrics.avg_abs_error_b = static_cast<float>(sum_abs_error_b) / error_pixels_count;
+ } else {
+ metrics.avg_abs_error_r = 0;
+ metrics.avg_abs_error_g = 0;
+ metrics.avg_abs_error_b = 0;
+ }
+
+ // Return error_ etrics using passed in pointer if not NULL
+ if (return_metrics != NULL) *return_metrics = metrics;
+
+ // Return true if all collected error metrics are below the comparator's thresholds.
+ return (metrics.error_pixels_percentage <= thresholds_.error_pixels_percentage &&
+ metrics.small_error_pixels_percentage <= thresholds_.small_error_pixels_percentage &&
+ metrics.avg_abs_error_r <= thresholds_.avg_abs_error_r &&
+ metrics.avg_abs_error_g <= thresholds_.avg_abs_error_g &&
+ metrics.avg_abs_error_b <= thresholds_.avg_abs_error_b &&
+ metrics.max_abs_error_r <= thresholds_.max_abs_error_r &&
+ metrics.max_abs_error_g <= thresholds_.max_abs_error_g &&
+ metrics.max_abs_error_b <= thresholds_.max_abs_error_b);
+}
+
+} // namespace cc

Powered by Google App Engine
This is Rietveld 408576698