1#!/usr/bin/env vpython 2# Copyright 2020 The Chromium Authors. All rights reserved. 3# Use of this source code is governed by a BSD-style license that can be 4# found in the LICENSE file. 5 6import argparse 7import logging 8import sys 9 10import gold_inexact_matching.base_parameter_optimizer as base_optimizer 11import gold_inexact_matching.binary_search_parameter_optimizer\ 12 as binary_optimizer 13import gold_inexact_matching.brute_force_parameter_optimizer as brute_optimizer 14import gold_inexact_matching.local_minima_parameter_optimizer\ 15 as local_optimizer 16from gold_inexact_matching import optimizer_set 17 18# Script to find suitable values for Skia Gold inexact matching. 19# 20# Inexact matching in Skia Gold has three tunable parameters: 21# 1. The max number of differing pixels. 22# 2. The max delta for any single pixel. 23# 3. The threshold for a Sobel filter. 24# 25# Ideally, we use the following hierarchy of comparison approaches: 26# 1. Exact matching. 27# 2. Exact matching after a Sobel filter is applied. 28# 3. Fuzzy matching after a Sobel filter is applied. 29# 30# However, there may be cases where only using a Sobel filter requires masking a 31# very large amount of the image compared to Sobel + very conservative fuzzy 32# matching. 33# 34# Even if such cases are not hit, the process of determining good values for the 35# parameters is quite tedious since it requires downloading images from Gold and 36# manually running multiple calls to `goldctl match`. 37# 38# This script attempts to remedy both issues by handling all of the trial and 39# error and suggesting potential parameter values for the user to choose from. 40 41 42def CreateArgumentParser(): 43 parser = argparse.ArgumentParser( 44 formatter_class=argparse.ArgumentDefaultsHelpFormatter) 45 script_parser = parser.add_argument_group('Script Arguments') 46 script_parser.add_argument( 47 '-v', 48 '--verbose', 49 dest='verbose_count', 50 default=0, 51 action='count', 52 help='Verbose level (multiple times for more') 53 54 subparsers = parser.add_subparsers(help='Optimization algorithm') 55 56 binary_parser = subparsers.add_parser( 57 'binary_search', 58 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 59 help='Perform a binary search to optimize a single parameter. The best ' 60 'option if you only want to tune one parameter.') 61 binary_parser.set_defaults( 62 clazz=binary_optimizer.BinarySearchParameterOptimizer) 63 binary_optimizer.BinarySearchParameterOptimizer.AddArguments(binary_parser) 64 65 local_parser = subparsers.add_parser( 66 'local_minima', 67 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 68 help='Perform a BFS to find local minima using weights for each ' 69 'parameter. Slower than binary searching, but supports an arbitrary ' 70 'number of parameters.') 71 local_parser.set_defaults(clazz=local_optimizer.LocalMinimaParameterOptimizer) 72 local_optimizer.LocalMinimaParameterOptimizer.AddArguments(local_parser) 73 74 brute_parser = subparsers.add_parser( 75 'brute_force', 76 formatter_class=argparse.ArgumentDefaultsHelpFormatter, 77 help='Brute force all possible combinations. VERY, VERY slow, but can ' 78 'potentially find better values than local_minima.') 79 brute_parser.set_defaults(clazz=brute_optimizer.BruteForceParameterOptimizer) 80 brute_optimizer.BruteForceParameterOptimizer.AddArguments(brute_parser) 81 82 return parser 83 84 85def SetLoggingVerbosity(args): 86 logger = logging.getLogger() 87 if args.verbose_count == 0: 88 logger.setLevel(logging.WARNING) 89 elif args.verbose_count == 1: 90 logger.setLevel(logging.INFO) 91 else: 92 logger.setLevel(logging.DEBUG) 93 94 95def main(): 96 parser = CreateArgumentParser() 97 args = parser.parse_args() 98 SetLoggingVerbosity(args) 99 optimizer = optimizer_set.OptimizerSet(args, args.clazz) 100 optimizer.RunOptimization() 101 return 0 102 103 104if __name__ == '__main__': 105 sys.exit(main()) 106