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 |