Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. | 2 # Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is governed by a BSD-style license that can be | 3 # Use of this source code is governed by a BSD-style license that can be |
| 4 # found in the LICENSE file. | 4 # found in the LICENSE file. |
| 5 | 5 |
| 6 """Module that outputs an JSON summary containing the comparision of images.""" | 6 """Module that outputs an JSON summary containing the comparision of images.""" |
| 7 | 7 |
| 8 import csv | 8 import csv |
| 9 import imp | 9 import imp |
| 10 import json | 10 import json |
| 11 import optparse | 11 import optparse |
| 12 import os | 12 import os |
| 13 import posixpath | 13 import posixpath |
| 14 import sys | 14 import sys |
| 15 | 15 |
| 16 sys.path.append( | 16 sys.path.append( |
| 17 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) | 17 os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) |
| 18 import json_summary_constants | 18 import json_summary_constants |
| 19 | 19 |
| 20 | 20 |
| 21 def WriteJsonSummary(img_root, nopatch_json, nopatch_img_dir_name, | 21 def WriteJsonSummary(img_root, nopatch_json, nopatch_images_base_url, |
| 22 withpatch_json, withpatch_img_dir_name, output_file_path, | 22 withpatch_json, withpatch_images_base_url, |
| 23 gs_output_dir, gs_skp_dir, slave_num, gm_json_path, | 23 output_file_path, gs_output_dir, gs_skp_dir, slave_num, |
| 24 imagediffdb_path, skpdiff_output_csv): | 24 gm_json_path, imagediffdb_path): |
| 25 """Outputs the JSON summary of image comparisions. | 25 """Outputs the JSON summary of image comparisions. |
| 26 | 26 |
| 27 Args: | 27 Args: |
| 28 img_root: (str) The root directory on local disk where we store all images. | 28 img_root: (str) The root directory on local disk where we store all images. |
| 29 nopatch_json: (str) Location of the nopatch render_pictures JSON summary | 29 nopatch_json: (str) Location of the nopatch render_pictures JSON summary |
| 30 file. | 30 file. |
| 31 nopatch_img_dir_name: (str) Name of the directory within img_root that | 31 nopatch_images_base_url: (str) URL of directory containing all nopatch |
|
epoger
2014/03/03 21:51:05
This changes because ImageDiffDB expects a URL fro
rmistry
2014/03/04 13:14:19
Acknowledged.
| |
| 32 contains all nopatch images. | 32 images. |
| 33 withpatch_json: (str) Location of the withpatch render_pictures JSON summary | 33 withpatch_json: (str) Location of the withpatch render_pictures JSON summary |
| 34 file. | 34 file. |
| 35 withpatch_img_dir_name: (str) Name of the directory within img_root that | 35 withpatch_images_base_url: (str) URL of directory containing all withpatch |
| 36 contains all withpatch images. | 36 images. |
| 37 output_file_path: (str) The local path to the JSON file that will be | 37 output_file_path: (str) The local path to the JSON file that will be |
| 38 created by this function which will contain a summary of all file | 38 created by this function which will contain a summary of all file |
| 39 differences for this slave. | 39 differences for this slave. |
| 40 gs_output_dir: (str) The directory the JSON summary file and images will be | 40 gs_output_dir: (str) The directory the JSON summary file and images will be |
| 41 outputted to in Google Storage. | 41 outputted to in Google Storage. |
| 42 gs_skp_dir: (str) The Google Storage directory that contains the SKPs of | 42 gs_skp_dir: (str) The Google Storage directory that contains the SKPs of |
| 43 this cluster telemetry slave. | 43 this cluster telemetry slave. |
| 44 slave_num: (str) The number of the cluster telemetry slave that is running | 44 slave_num: (str) The number of the cluster telemetry slave that is running |
| 45 this script. | 45 this script. |
| 46 gm_json_path: (str) Local complete path to gm_json.py in Skia trunk. | 46 gm_json_path: (str) Local complete path to gm_json.py in Skia trunk. |
| 47 imagediffdb_path: (str) Local complete path to imagediffdb.py in Skia trunk. | 47 imagediffdb_path: (str) Local complete path to imagediffdb.py in Skia trunk. |
| 48 skpdiff_output_csv: (str) Local complete path to the CSV output of skpdiff. | |
| 49 """ | 48 """ |
| 50 | 49 |
| 51 assert os.path.isfile(gm_json_path), 'Must specify a valid path to gm_json.py' | 50 assert os.path.isfile(gm_json_path), 'Must specify a valid path to gm_json.py' |
| 52 gm_json_mod = imp.load_source(gm_json_path, gm_json_path) | 51 gm_json_mod = imp.load_source(gm_json_path, gm_json_path) |
| 53 assert os.path.isfile(imagediffdb_path), ( | 52 assert os.path.isfile(imagediffdb_path), ( |
| 54 'Must specify a valid path to imagediffdb.py') | 53 'Must specify a valid path to imagediffdb.py') |
| 55 imagediffdb_mod = imp.load_source(imagediffdb_path, imagediffdb_path) | 54 imagediffdb_mod = imp.load_source(imagediffdb_path, imagediffdb_path) |
| 56 | 55 |
| 57 files_to_checksums1 = GetFilesAndChecksums(nopatch_json, gm_json_mod) | 56 files_to_checksums_nopatch = GetFilesAndChecksums(nopatch_json, gm_json_mod) |
| 58 files_to_checksums2 = GetFilesAndChecksums(withpatch_json, gm_json_mod) | 57 files_to_checksums_withpatch = GetFilesAndChecksums( |
| 58 withpatch_json, gm_json_mod) | |
| 59 | 59 |
| 60 assert len(files_to_checksums1) == len(files_to_checksums2), ( | 60 assert len(files_to_checksums_nopatch) == len(files_to_checksums_withpatch), ( |
| 61 'Number of images in both JSON summary files are different') | 61 'Number of images in both JSON summary files are different') |
| 62 assert files_to_checksums1.keys() == files_to_checksums2.keys(), ( | 62 assert (files_to_checksums_nopatch.keys() == |
| 63 'File names in both JSON summary files are different') | 63 files_to_checksums_withpatch.keys(), |
| 64 'File names in both JSON summary files are different') | |
| 64 | 65 |
| 65 # Compare checksums in both directories and output differences. | 66 # Compare checksums in both directories and output differences. |
| 66 file_differences = [] | 67 file_differences = [] |
| 67 slave_dict = { | 68 slave_dict = { |
| 68 json_summary_constants.JSONKEY_SKPS_LOCATION: gs_skp_dir, | 69 json_summary_constants.JSONKEY_SKPS_LOCATION: gs_skp_dir, |
| 69 json_summary_constants.JSONKEY_FAILED_FILES: file_differences, | 70 json_summary_constants.JSONKEY_FAILED_FILES: file_differences, |
| 70 json_summary_constants.JSONKEY_FILES_LOCATION_NOPATCH: posixpath.join( | 71 json_summary_constants.JSONKEY_FILES_LOCATION_NOPATCH: posixpath.join( |
| 71 gs_output_dir, 'slave%s' % slave_num, 'nopatch-images'), | 72 gs_output_dir, 'slave%s' % slave_num, 'nopatch-images'), |
| 72 json_summary_constants.JSONKEY_FILES_LOCATION_WITHPATCH: posixpath.join( | 73 json_summary_constants.JSONKEY_FILES_LOCATION_WITHPATCH: posixpath.join( |
| 73 gs_output_dir, 'slave%s' % slave_num, 'withpatch-images'), | 74 gs_output_dir, 'slave%s' % slave_num, 'withpatch-images'), |
| 74 json_summary_constants.JSONKEY_FILES_LOCATION_DIFFS: posixpath.join( | 75 json_summary_constants.JSONKEY_FILES_LOCATION_DIFFS: posixpath.join( |
| 75 gs_output_dir, 'slave%s' % slave_num, 'diffs'), | 76 gs_output_dir, 'slave%s' % slave_num, 'diffs'), |
| 76 json_summary_constants.JSONKEY_FILES_LOCATION_WHITE_DIFFS: posixpath.join( | 77 json_summary_constants.JSONKEY_FILES_LOCATION_WHITE_DIFFS: posixpath.join( |
| 77 gs_output_dir, 'slave%s' % slave_num, 'whitediffs') | 78 gs_output_dir, 'slave%s' % slave_num, 'whitediffs') |
| 78 } | 79 } |
| 79 json_summary = { | 80 json_summary = { |
| 80 'slave%s' % slave_num: slave_dict | 81 'slave%s' % slave_num: slave_dict |
| 81 } | 82 } |
| 82 # Read the skpdiff CSV output. | |
| 83 page_to_perceptual_similarity = {} | |
| 84 for row in csv.DictReader(open(skpdiff_output_csv, 'r')): | |
| 85 page_to_perceptual_similarity[row['key']] = float( | |
| 86 row[' perceptual'].strip()) | |
| 87 | 83 |
| 88 for file1 in files_to_checksums1: | 84 image_diff_db = imagediffdb_mod.ImageDiffDB(storage_root=img_root) |
| 89 algo1, checksum1 = files_to_checksums1[file1] | 85 for filename in files_to_checksums_nopatch: |
| 90 algo2, checksum2 = files_to_checksums2[file1] | 86 algo_nopatch, checksum_nopatch = files_to_checksums_nopatch[filename] |
| 91 assert algo1 == algo2, 'Different algorithms found' | 87 algo_withpatch, checksum_withpatch = files_to_checksums_withpatch[filename] |
| 92 if checksum1 != checksum2: | 88 assert algo_nopatch == algo_withpatch, 'Different checksum algorithms found' |
| 93 # Call imagediffdb and then the diffs and metrics. | 89 if checksum_nopatch != checksum_withpatch: |
| 94 image_diff = imagediffdb_mod.DiffRecord( | 90 # TODO(epoger): It seems silly that we add this DiffRecord to ImageDiffDB |
| 95 storage_root=img_root, | 91 # and then pull it out again right away, but this is a stepping-stone |
| 96 expected_image_url=None, # Do not need to download any img. | 92 # to using ImagePairSet instead of replicating its behavior here. |
| 97 expected_image_locator=os.path.splitext(file1)[0], | 93 image_diff_db.add_image_pair( |
| 98 actual_image_url=None, # Do not need to download any img. | 94 expected_image_url=posixpath.join(nopatch_images_base_url, filename), |
| 99 actual_image_locator=os.path.splitext(file1)[0], | 95 expected_image_locator=checksum_nopatch, |
| 100 expected_images_subdir=nopatch_img_dir_name, | 96 actual_image_url=posixpath.join(withpatch_images_base_url, filename), |
| 101 actual_images_subdir=withpatch_img_dir_name) | 97 actual_image_locator=checksum_withpatch) |
| 98 diff_record = image_diff_db.get_diff_record( | |
| 99 expected_image_locator=checksum_nopatch, | |
| 100 actual_image_locator=checksum_withpatch) | |
| 102 file_differences.append({ | 101 file_differences.append({ |
| 103 json_summary_constants.JSONKEY_FILE_NAME: file1, | 102 json_summary_constants.JSONKEY_FILE_NAME: filename, |
| 104 json_summary_constants.JSONKEY_SKP_LOCATION: posixpath.join( | 103 json_summary_constants.JSONKEY_SKP_LOCATION: posixpath.join( |
| 105 gs_skp_dir, GetSkpFileName(file1)), | 104 gs_skp_dir, GetSkpFileName(filename)), |
| 106 json_summary_constants.JSONKEY_NUM_PIXELS_DIFFERING: | 105 json_summary_constants.JSONKEY_NUM_PIXELS_DIFFERING: |
| 107 image_diff.get_num_pixels_differing(), | 106 diff_record.get_num_pixels_differing(), |
| 108 json_summary_constants.JSONKEY_PERCENT_PIXELS_DIFFERING: | 107 json_summary_constants.JSONKEY_PERCENT_PIXELS_DIFFERING: |
| 109 image_diff.get_percent_pixels_differing(), | 108 diff_record.get_percent_pixels_differing(), |
| 110 json_summary_constants.JSONKEY_WEIGHTED_DIFF_MEASURE: | 109 json_summary_constants.JSONKEY_WEIGHTED_DIFF_MEASURE: |
| 111 image_diff.get_weighted_diff_measure(), | 110 diff_record.get_weighted_diff_measure(), |
| 112 json_summary_constants.JSONKEY_MAX_DIFF_PER_CHANNEL: | 111 json_summary_constants.JSONKEY_MAX_DIFF_PER_CHANNEL: |
| 113 image_diff.get_max_diff_per_channel(), | 112 diff_record.get_max_diff_per_channel(), |
| 114 json_summary_constants.JSONKEY_PERCEPTUAL_SIMILARITY: | 113 json_summary_constants.JSONKEY_PERCEPTUAL_SIMILARITY: |
| 115 page_to_perceptual_similarity[file1], | 114 diff_record.get_perceptual_difference(), |
| 116 }) | 115 }) |
| 117 if file_differences: | 116 if file_differences: |
| 118 slave_dict[json_summary_constants.JSONKEY_FAILED_FILES_COUNT] = len( | 117 slave_dict[json_summary_constants.JSONKEY_FAILED_FILES_COUNT] = len( |
| 119 file_differences) | 118 file_differences) |
| 120 with open(output_file_path, 'w') as f: | 119 with open(output_file_path, 'w') as f: |
| 121 f.write(json.dumps(json_summary, indent=4, sort_keys=True)) | 120 f.write(json.dumps(json_summary, indent=4, sort_keys=True)) |
| 122 | 121 |
| 123 | 122 |
| 124 def GetSkpFileName(img_file_name): | 123 def GetSkpFileName(img_file_name): |
| 125 """Determine the SKP file name from the image's file name.""" | 124 """Determine the SKP file name from the image's file name.""" |
| (...skipping 14 matching lines...) Expand all Loading... | |
| 140 | 139 |
| 141 if '__main__' == __name__: | 140 if '__main__' == __name__: |
| 142 option_parser = optparse.OptionParser() | 141 option_parser = optparse.OptionParser() |
| 143 option_parser.add_option( | 142 option_parser.add_option( |
| 144 '', '--img_root', | 143 '', '--img_root', |
| 145 help='The root directory on local disk where we store all images.') | 144 help='The root directory on local disk where we store all images.') |
| 146 option_parser.add_option( | 145 option_parser.add_option( |
| 147 '', '--nopatch_json', | 146 '', '--nopatch_json', |
| 148 help='Location of the nopatch render_pictures JSON summary file.') | 147 help='Location of the nopatch render_pictures JSON summary file.') |
| 149 option_parser.add_option( | 148 option_parser.add_option( |
| 150 '', '--nopatch_img_dir_name', | 149 '', '--nopatch_images_base_url', |
| 151 help='Name of the directory within img_root that contains all nopatch ' | 150 help='URL of directory containing all nopatch images.') |
| 152 'images.') | |
| 153 option_parser.add_option( | 151 option_parser.add_option( |
| 154 '', '--withpatch_json', | 152 '', '--withpatch_json', |
| 155 help='Location of the withpatch render_pictures JSON summary file.') | 153 help='Location of the withpatch render_pictures JSON summary file.') |
| 156 option_parser.add_option( | 154 option_parser.add_option( |
| 157 '', '--withpatch_img_dir_name', | 155 '', '--withpatch_images_base_url', |
| 158 help='Name of the directory within img_root that contains all withpatch ' | 156 help='URL of directory containing all withpatch images.') |
| 159 'images.') | |
| 160 option_parser.add_option( | 157 option_parser.add_option( |
| 161 '', '--output_file_path', | 158 '', '--output_file_path', |
| 162 help='The local path to the JSON file that will be created by this ' | 159 help='The local path to the JSON file that will be created by this ' |
| 163 'script which will contain a summary of all file differences for ' | 160 'script which will contain a summary of all file differences for ' |
| 164 'this slave.') | 161 'this slave.') |
| 165 option_parser.add_option( | 162 option_parser.add_option( |
| 166 '', '--gs_output_dir', | 163 '', '--gs_output_dir', |
| 167 help='The directory the JSON summary file and images will be outputted ' | 164 help='The directory the JSON summary file and images will be outputted ' |
| 168 'to in Google Storage.') | 165 'to in Google Storage.') |
| 169 option_parser.add_option( | 166 option_parser.add_option( |
| 170 '', '--gs_skp_dir', | 167 '', '--gs_skp_dir', |
| 171 help='The Google Storage directory that contains the SKPs of this ' | 168 help='The Google Storage directory that contains the SKPs of this ' |
| 172 'cluster telemetry slave.') | 169 'cluster telemetry slave.') |
| 173 option_parser.add_option( | 170 option_parser.add_option( |
| 174 '', '--slave_num', | 171 '', '--slave_num', |
| 175 help='The number of the cluster telemetry slave that is running this ' | 172 help='The number of the cluster telemetry slave that is running this ' |
| 176 'script.') | 173 'script.') |
| 177 option_parser.add_option( | 174 option_parser.add_option( |
| 178 '', '--gm_json_path', | 175 '', '--gm_json_path', |
| 179 help='Local complete path to gm_json.py in Skia trunk.') | 176 help='Local complete path to gm_json.py in Skia trunk.') |
| 180 option_parser.add_option( | 177 option_parser.add_option( |
| 181 '', '--imagediffdb_path', | 178 '', '--imagediffdb_path', |
| 182 help='Local complete path to imagediffdb.py in Skia trunk.') | 179 help='Local complete path to imagediffdb.py in Skia trunk.') |
| 183 option_parser.add_option( | |
| 184 '', '--skpdiff_output_csv', | |
| 185 help='Local complete path to the CSV output of skpdiff.') | |
| 186 options, unused_args = option_parser.parse_args() | 180 options, unused_args = option_parser.parse_args() |
| 187 if (not options.nopatch_json or not options.withpatch_json | 181 if (not options.nopatch_json or not options.withpatch_json |
| 188 or not options.output_file_path or not options.gs_output_dir | 182 or not options.output_file_path or not options.gs_output_dir |
| 189 or not options.gs_skp_dir or not options.slave_num | 183 or not options.gs_skp_dir or not options.slave_num |
| 190 or not options.gm_json_path or not options.img_root | 184 or not options.gm_json_path or not options.img_root |
| 191 or not options.nopatch_img_dir_name or not options.withpatch_img_dir_name | 185 or not options.nopatch_images_base_url |
| 192 or not options.imagediffdb_path or not options.skpdiff_output_csv): | 186 or not options.withpatch_images_base_url |
| 187 or not options.imagediffdb_path): | |
| 193 option_parser.error( | 188 option_parser.error( |
| 194 'Must specify img_root, nopatch_json, nopatch_img_dir_name, ' | 189 'Must specify img_root, nopatch_json, nopatch_images_base_url, ' |
| 195 'withpatch_json, withpatch_img_dir_name, output_file_path, ' | 190 'withpatch_json, withpatch_images_base_url, output_file_path, ' |
| 196 'gs_output_dir, gs_skp_dir, slave_num, gm_json_path, ' | 191 'gs_output_dir, gs_skp_dir, slave_num, gm_json_path, ' |
| 197 'imagediffdb_path and skpdiff_output_csv.') | 192 'and imagediffdb_path.') |
| 198 | 193 |
| 199 WriteJsonSummary(options.img_root, options.nopatch_json, | 194 WriteJsonSummary(options.img_root, options.nopatch_json, |
| 200 options.nopatch_img_dir_name, options.withpatch_json, | 195 options.nopatch_images_base_url, options.withpatch_json, |
| 201 options.withpatch_img_dir_name, options.output_file_path, | 196 options.withpatch_images_base_url, options.output_file_path, |
| 202 options.gs_output_dir, options.gs_skp_dir, options.slave_num, | 197 options.gs_output_dir, options.gs_skp_dir, options.slave_num, |
| 203 options.gm_json_path, options.imagediffdb_path, | 198 options.gm_json_path, options.imagediffdb_path) |
| 204 options.skpdiff_output_csv) | |
| OLD | NEW |