Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "cc/test/image_comparator.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 | |
| 9 namespace cc { | |
| 10 | |
| 11 ImageComparator::ImageComparator() { | |
| 12 thresholds_ = ErrorMetrics(); | |
| 13 } | |
| 14 | |
| 15 ImageComparator::ImageComparator(const ErrorMetrics& thresholds) | |
| 16 : thresholds_(thresholds) | |
| 17 { } | |
| 18 | |
| 19 ImageComparator::ErrorMetrics::ErrorMetrics(float error_pixels_percentage, | |
| 20 float small_error_pixels_percentage, | |
| 21 float avg_abs_error_r, | |
| 22 float avg_abs_error_g, | |
| 23 float avg_abs_error_b, | |
| 24 unsigned int max_abs_error_r, | |
| 25 unsigned int max_abs_error_g, | |
| 26 unsigned int max_abs_error_b, | |
| 27 unsigned int small_error_threshold) | |
| 28 : error_pixels_percentage(error_pixels_percentage), | |
| 29 small_error_pixels_percentage(small_error_pixels_percentage), | |
| 30 avg_abs_error_r(avg_abs_error_r), | |
| 31 avg_abs_error_g(avg_abs_error_g), | |
| 32 avg_abs_error_b(avg_abs_error_b), | |
| 33 max_abs_error_r(max_abs_error_r), | |
| 34 max_abs_error_g(max_abs_error_g), | |
| 35 max_abs_error_b(max_abs_error_b), | |
| 36 small_error_threshold(small_error_threshold) | |
| 37 { } | |
| 38 | |
| 39 void ImageComparator::AllowOffByOneErrors(float off_by_one_pixels_percentage) { | |
| 40 thresholds_.error_pixels_percentage = off_by_one_pixels_percentage; | |
| 41 thresholds_.small_error_pixels_percentage = off_by_one_pixels_percentage; | |
| 42 thresholds_.avg_abs_error_r = 1.0f; | |
| 43 thresholds_.avg_abs_error_g = 1.0f; | |
| 44 thresholds_.avg_abs_error_b = 1.0f; | |
| 45 thresholds_.max_abs_error_r = 1.0f; | |
| 46 thresholds_.max_abs_error_g = 1.0f; | |
| 47 thresholds_.max_abs_error_b = 1.0f; | |
| 48 thresholds_.small_error_threshold = 1; | |
| 49 } | |
| 50 | |
| 51 bool ImageComparator::Compare(const SkBitmap& bitmap_a, | |
| 52 const SkBitmap& bitmap_b, | |
| 53 ErrorMetrics* return_metrics) const { | |
| 54 ErrorMetrics metrics; | |
| 55 metrics.small_error_threshold = thresholds_.small_error_threshold; | |
| 56 | |
| 57 // Number of pixels that are different. | |
| 58 unsigned int error_pixels_count = 0; | |
| 59 // Number of pixels that are at most off by small_error_threshold per color | |
| 60 // channel | |
| 61 unsigned int small_error_pixels_count = 0; | |
| 62 // The per channel sum of absolute errors over all pixels. | |
| 63 unsigned long long sum_abs_error_r = 0; | |
| 64 unsigned long long sum_abs_error_g = 0; | |
| 65 unsigned long long sum_abs_error_b = 0; | |
| 66 | |
| 67 // A meaningful comparison is not possible if the size does not match | |
| 68 // (alignment? background color?). Return maximum error values in that case. | |
| 69 if (bitmap_a.width() != bitmap_b.width() || | |
| 70 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
| |
| 71 if (return_metrics != NULL) { | |
| 72 return_metrics->error_pixels_percentage = 100.0f; | |
| 73 return_metrics->small_error_pixels_percentage = 0.0f; | |
| 74 return_metrics->avg_abs_error_r = 255.0f; | |
| 75 return_metrics->avg_abs_error_g = 255.0f; | |
| 76 return_metrics->avg_abs_error_b = 255.0f; | |
| 77 return_metrics->max_abs_error_r = 255; | |
| 78 return_metrics->max_abs_error_g = 255; | |
| 79 return_metrics->max_abs_error_b = 255; | |
| 80 return_metrics->small_error_threshold = thresholds_.small_error_threshold; | |
| 81 } | |
| 82 return false; | |
| 83 } | |
| 84 | |
| 85 // Empty bitmaps are always considered to be equal. | |
| 86 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
| |
| 87 if (return_metrics != NULL) { | |
| 88 return_metrics->error_pixels_percentage = 0.0f; | |
| 89 return_metrics->small_error_pixels_percentage = 0.0f; | |
| 90 return_metrics->avg_abs_error_r = 0.0f; | |
| 91 return_metrics->avg_abs_error_g = 0.0f; | |
| 92 return_metrics->avg_abs_error_b = 0.0f; | |
| 93 return_metrics->max_abs_error_r = 0; | |
| 94 return_metrics->max_abs_error_g = 0; | |
| 95 return_metrics->max_abs_error_b = 0; | |
| 96 return_metrics->small_error_threshold = thresholds_.small_error_threshold; | |
| 97 } | |
| 98 return true; | |
| 99 } | |
| 100 | |
| 101 SkAutoLockPixels lock_bitmap_a(bitmap_a); | |
| 102 SkAutoLockPixels lock_bitmap_b(bitmap_b); | |
| 103 | |
| 104 // The reference images were saved with no alpha channel. Use the mask to | |
| 105 // set alpha to 0. | |
| 106 uint32_t kAlphaMask = 0x00FFFFFF; | |
| 107 for (int x = 0; x < bitmap_a.width(); ++x) { | |
| 108 for (int y = 0; y < bitmap_a.height(); ++y) { | |
| 109 if ((*bitmap_a.getAddr32(x, y) & kAlphaMask) != | |
| 110 (*bitmap_b.getAddr32(x, y) & kAlphaMask)) { | |
| 111 ++error_pixels_count; | |
| 112 | |
| 113 SkColor color_a = bitmap_a.getColor(x, y); | |
| 114 SkColor color_b = bitmap_b.getColor(x, y); | |
| 115 | |
| 116 // Compute per channel absolute errors | |
| 117 unsigned int abs_error_r = | |
| 118 std::max(SkColorGetR(color_a), SkColorGetR(color_b)) - | |
| 119 std::min(SkColorGetR(color_a), SkColorGetR(color_b)); | |
| 120 unsigned int abs_error_g = | |
| 121 std::max(SkColorGetG(color_a), SkColorGetG(color_b)) - | |
| 122 std::min(SkColorGetG(color_a), SkColorGetG(color_b)); | |
| 123 unsigned int abs_error_b = | |
| 124 std::max(SkColorGetB(color_a), SkColorGetB(color_b)) - | |
| 125 std::min(SkColorGetB(color_a), SkColorGetB(color_b)); | |
| 126 | |
| 127 // Increment small error counter if error is below threshold | |
| 128 if (abs_error_r <= thresholds_.small_error_threshold && | |
| 129 abs_error_g <= thresholds_.small_error_threshold && | |
| 130 abs_error_b <= thresholds_.small_error_threshold) | |
| 131 ++small_error_pixels_count; | |
| 132 | |
| 133 // Update per channel maximum absolute errors | |
| 134 if (abs_error_r > metrics.max_abs_error_r) | |
| 135 metrics.max_abs_error_r = abs_error_r; | |
| 136 if (abs_error_g > metrics.max_abs_error_g) | |
| 137 metrics.max_abs_error_g = abs_error_g; | |
| 138 if (abs_error_b > metrics.max_abs_error_b) | |
| 139 metrics.max_abs_error_b = abs_error_b; | |
| 140 | |
| 141 // Update per channel absolute error sums | |
| 142 sum_abs_error_r += abs_error_r; | |
| 143 sum_abs_error_g += abs_error_g; | |
| 144 sum_abs_error_b += abs_error_b; | |
| 145 } | |
| 146 } | |
| 147 } | |
| 148 | |
| 149 // Fill error metrics with collected data | |
| 150 unsigned int pixels_count = bitmap_a.width() * bitmap_a.height(); | |
| 151 metrics.error_pixels_percentage = static_cast<float>(error_pixels_count) / | |
| 152 pixels_count * 100.0f; | |
| 153 metrics.small_error_pixels_percentage = static_cast<float>(small_error_pixels_ count) / | |
| 154 pixels_count * 100.0f; | |
| 155 if (error_pixels_count > 0) { | |
| 156 metrics.avg_abs_error_r = static_cast<float>(sum_abs_error_r) / error_pixels _count; | |
| 157 metrics.avg_abs_error_g = static_cast<float>(sum_abs_error_g) / error_pixels _count; | |
| 158 metrics.avg_abs_error_b = static_cast<float>(sum_abs_error_b) / error_pixels _count; | |
| 159 } else { | |
| 160 metrics.avg_abs_error_r = 0; | |
| 161 metrics.avg_abs_error_g = 0; | |
| 162 metrics.avg_abs_error_b = 0; | |
| 163 } | |
| 164 | |
| 165 // Return error_ etrics using passed in pointer if not NULL | |
| 166 if (return_metrics != NULL) *return_metrics = metrics; | |
| 167 | |
| 168 // Return true if all collected error metrics are below the comparator's thres holds. | |
| 169 return (metrics.error_pixels_percentage <= thresholds_.error_pixels_percentage && | |
| 170 metrics.small_error_pixels_percentage <= thresholds_.small_error_pixel s_percentage && | |
| 171 metrics.avg_abs_error_r <= thresholds_.avg_abs_error_r && | |
| 172 metrics.avg_abs_error_g <= thresholds_.avg_abs_error_g && | |
| 173 metrics.avg_abs_error_b <= thresholds_.avg_abs_error_b && | |
| 174 metrics.max_abs_error_r <= thresholds_.max_abs_error_r && | |
| 175 metrics.max_abs_error_g <= thresholds_.max_abs_error_g && | |
| 176 metrics.max_abs_error_b <= thresholds_.max_abs_error_b); | |
| 177 } | |
| 178 | |
| 179 } // namespace cc | |
| OLD | NEW |