Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/python | 1 #!/usr/bin/python |
| 2 | 2 |
| 3 """ | 3 """ |
| 4 Copyright 2013 Google Inc. | 4 Copyright 2013 Google Inc. |
| 5 | 5 |
| 6 Use of this source code is governed by a BSD-style license that can be | 6 Use of this source code is governed by a BSD-style license that can be |
| 7 found in the LICENSE file. | 7 found in the LICENSE file. |
| 8 | 8 |
| 9 Calulate differences between image pairs, and store them in a database. | 9 Calulate differences between image pairs, and store them in a database. |
| 10 """ | 10 """ |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 118 # Return early if we do not need to generate diffs. | 118 # Return early if we do not need to generate diffs. |
| 119 if (expected_image_url == actual_image_url or | 119 if (expected_image_url == actual_image_url or |
| 120 not expected_image_url or not actual_image_url): | 120 not expected_image_url or not actual_image_url): |
| 121 return | 121 return |
| 122 | 122 |
| 123 # Get all diff images and values using the skpdiff binary. | 123 # Get all diff images and values using the skpdiff binary. |
| 124 skpdiff_output_dir = tempfile.mkdtemp() | 124 skpdiff_output_dir = tempfile.mkdtemp() |
| 125 try: | 125 try: |
| 126 skpdiff_summary_file = os.path.join(skpdiff_output_dir, | 126 skpdiff_summary_file = os.path.join(skpdiff_output_dir, |
| 127 'skpdiff-output.json') | 127 'skpdiff-output.json') |
| 128 skpdiff_rgbdiff_dir = os.path.join(skpdiff_output_dir, 'rgbDiff') | 128 skpdiff_rgbdiff_dir = os.path.join(storage_root, RGBDIFFS_SUBDIR) |
| 129 skpdiff_whitediff_dir = os.path.join(skpdiff_output_dir, 'whiteDiff') | 129 skpdiff_whitediff_dir = os.path.join(storage_root, WHITEDIFFS_SUBDIR) |
| 130 _mkdir_unless_exists(skpdiff_rgbdiff_dir) | |
| 131 _mkdir_unless_exists(skpdiff_rgbdiff_dir) | |
| 130 | 132 |
| 131 # TODO(epoger): Consider calling skpdiff ONCE for all image pairs, | 133 # TODO(epoger): Consider calling skpdiff ONCE for all image pairs, |
| 132 # instead of calling it separately for each image pair. | 134 # instead of calling it separately for each image pair. |
| 133 # Pro: we'll incur less overhead from making repeated system calls, | 135 # Pro: we'll incur less overhead from making repeated system calls, |
| 134 # spinning up the skpdiff binary, etc. | 136 # spinning up the skpdiff binary, etc. |
| 135 # Con: we would have to wait until all image pairs were loaded before | 137 # Con: we would have to wait until all image pairs were loaded before |
| 136 # generating any of the diffs? | 138 # generating any of the diffs? |
| 139 # Note(stephana): '--longnames' was added to allow for this | |
| 140 # case (multiple files at once) versus specifying output diffs | |
| 141 # directly. | |
| 137 find_run_binary.run_command( | 142 find_run_binary.run_command( |
| 138 [SKPDIFF_BINARY, '-p', expected_image_file, actual_image_file, | 143 [SKPDIFF_BINARY, '-p', expected_image_file, actual_image_file, |
| 139 '--jsonp', 'false', | 144 '--jsonp', 'false', |
| 145 '--longnames', 'true', | |
| 140 '--output', skpdiff_summary_file, | 146 '--output', skpdiff_summary_file, |
| 141 '--differs', 'perceptual', 'different_pixels', | 147 '--differs', 'perceptual', 'different_pixels', |
| 142 '--rgbDiffDir', skpdiff_rgbdiff_dir, | 148 '--rgbDiffDir', skpdiff_rgbdiff_dir, |
| 143 '--whiteDiffDir', skpdiff_whitediff_dir, | 149 '--whiteDiffDir', skpdiff_whitediff_dir, |
| 144 ]) | 150 ]) |
| 145 | 151 |
| 146 # Get information out of the skpdiff_summary_file. | 152 # Get information out of the skpdiff_summary_file. |
| 147 with contextlib.closing(open(skpdiff_summary_file)) as fp: | 153 with contextlib.closing(open(skpdiff_summary_file)) as fp: |
| 148 data = json.load(fp) | 154 data = json.load(fp) |
| 149 | 155 |
| 150 # For now, we can assume there is only one record in the output summary, | 156 # For now, we can assume there is only one record in the output summary, |
| 151 # since we passed skpdiff only one pair of images. | 157 # since we passed skpdiff only one pair of images. |
| 152 record = data['records'][0] | 158 record = data['records'][0] |
| 153 self._width = record['width'] | 159 self._width = record['width'] |
| 154 self._height = record['height'] | 160 self._height = record['height'] |
| 155 # TODO: make max_diff_per_channel a tuple instead of a list, because the | 161 # TODO: make max_diff_per_channel a tuple instead of a list, because the |
| 156 # structure is meaningful (first element is red, second is green, etc.) | 162 # structure is meaningful (first element is red, second is green, etc.) |
| 157 # See http://stackoverflow.com/a/626871 | 163 # See http://stackoverflow.com/a/626871 |
| 158 self._max_diff_per_channel = [ | 164 self._max_diff_per_channel = [ |
| 159 record['maxRedDiff'], record['maxGreenDiff'], record['maxBlueDiff']] | 165 record['maxRedDiff'], record['maxGreenDiff'], record['maxBlueDiff']] |
| 160 rgb_diff_path = record['rgbDiffPath'] | |
| 161 white_diff_path = record['whiteDiffPath'] | |
| 162 per_differ_stats = record['diffs'] | 166 per_differ_stats = record['diffs'] |
| 163 for stats in per_differ_stats: | 167 for stats in per_differ_stats: |
| 164 differ_name = stats['differName'] | 168 differ_name = stats['differName'] |
| 165 if differ_name == 'different_pixels': | 169 if differ_name == 'different_pixels': |
| 166 self._num_pixels_differing = stats['pointsOfInterest'] | 170 self._num_pixels_differing = stats['pointsOfInterest'] |
| 167 elif differ_name == 'perceptual': | 171 elif differ_name == 'perceptual': |
| 168 perceptual_similarity = stats['result'] | 172 perceptual_similarity = stats['result'] |
| 169 | 173 |
| 170 # skpdiff returns the perceptual similarity; convert it to get the | 174 # skpdiff returns the perceptual similarity; convert it to get the |
| 171 # perceptual difference percentage. | 175 # perceptual difference percentage. |
| 172 # skpdiff outputs -1 if the images are different sizes. Treat any | 176 # skpdiff outputs -1 if the images are different sizes. Treat any |
| 173 # output that does not lie in [0, 1] as having 0% perceptual | 177 # output that does not lie in [0, 1] as having 0% perceptual |
| 174 # similarity. | 178 # similarity. |
| 175 if not 0 <= perceptual_similarity <= 1: | 179 if not 0 <= perceptual_similarity <= 1: |
| 176 perceptual_similarity = 0 | 180 perceptual_similarity = 0 |
| 177 self._perceptual_difference = 100 - (perceptual_similarity * 100) | 181 self._perceptual_difference = 100 - (perceptual_similarity * 100) |
| 178 | |
| 179 # Store the rgbdiff and whitediff images generated above. | |
| 180 diff_image_locator = _get_difference_locator( | |
| 181 expected_image_locator=expected_image_locator, | |
| 182 actual_image_locator=actual_image_locator) | |
| 183 basename = str(diff_image_locator) + image_suffix | |
| 184 _mkdir_unless_exists(os.path.join(storage_root, RGBDIFFS_SUBDIR)) | |
| 185 _mkdir_unless_exists(os.path.join(storage_root, WHITEDIFFS_SUBDIR)) | |
| 186 # TODO: Modify skpdiff's behavior so we can tell it exactly where to | |
| 187 # write the image files into, rather than having to move them around | |
| 188 # after skpdiff writes them out. | |
| 189 shutil.copyfile(rgb_diff_path, | |
| 190 os.path.join(storage_root, RGBDIFFS_SUBDIR, basename)) | |
| 191 shutil.copyfile(white_diff_path, | |
| 192 os.path.join(storage_root, WHITEDIFFS_SUBDIR, basename)) | |
| 193 | |
| 194 finally: | 182 finally: |
| 195 shutil.rmtree(skpdiff_output_dir) | 183 shutil.rmtree(skpdiff_output_dir) |
| 196 | 184 |
| 185 | |
| 186 | |
| 187 @staticmethod | |
| 188 def get_diff_records(gs, storage_root, | |
| 189 images_to_compare, | |
| 190 expected_images_subdir=DEFAULT_IMAGES_SUBDIR, | |
| 191 actual_images_subdir=DEFAULT_IMAGES_SUBDIR, | |
| 192 image_suffix=DEFAULT_IMAGE_SUFFIX): | |
| 193 # TODO: stub method to be filled in | |
|
epoger
2014/08/12 18:03:40
Do you intend to fill in this method before commit
stephana
2014/08/12 19:25:13
No. That's an artifact. Will remove it.
On 2014/
| |
| 194 diff_records = [] | |
| 195 return diff_records | |
| 196 | |
| 197 | |
| 197 # TODO(epoger): Use properties instead of getters throughout. | 198 # TODO(epoger): Use properties instead of getters throughout. |
| 198 # See http://stackoverflow.com/a/6618176 | 199 # See http://stackoverflow.com/a/6618176 |
| 199 def get_num_pixels_differing(self): | 200 def get_num_pixels_differing(self): |
| 200 """Returns the absolute number of pixels that differ.""" | 201 """Returns the absolute number of pixels that differ.""" |
| 201 return self._num_pixels_differing | 202 return self._num_pixels_differing |
| 202 | 203 |
| 203 def get_percent_pixels_differing(self): | 204 def get_percent_pixels_differing(self): |
| 204 """Returns the percentage of pixels that differ, as a float between | 205 """Returns the percentage of pixels that differ, as a float between |
| 205 0 and 100 (inclusive).""" | 206 0 and 100 (inclusive).""" |
| 206 return ((float(self._num_pixels_differing) * 100) / | 207 return ((float(self._num_pixels_differing) * 100) / |
| (...skipping 282 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 489 | 490 |
| 490 Args: | 491 Args: |
| 491 expected_image_locator: locator string pointing at expected image | 492 expected_image_locator: locator string pointing at expected image |
| 492 actual_image_locator: locator string pointing at actual image | 493 actual_image_locator: locator string pointing at actual image |
| 493 | 494 |
| 494 Returns: already-sanitized locator where the diffs between expected and | 495 Returns: already-sanitized locator where the diffs between expected and |
| 495 actual images can be found | 496 actual images can be found |
| 496 """ | 497 """ |
| 497 return "%s-vs-%s" % (_sanitize_locator(expected_image_locator), | 498 return "%s-vs-%s" % (_sanitize_locator(expected_image_locator), |
| 498 _sanitize_locator(actual_image_locator)) | 499 _sanitize_locator(actual_image_locator)) |
| OLD | NEW |