def test_default_matrix_not_available_and_non_specified(self): with pytest.raises(SystemExit): parse_quantisation_matrix_argument( None, WaveletFilters.le_gall_5_3, WaveletFilters.le_gall_5_3, 100, 0, )
def test_bad_custom_matrix(self, argument): with pytest.raises(SystemExit): parse_quantisation_matrix_argument( argument.split(), WaveletFilters.le_gall_5_3, WaveletFilters.le_gall_5_3, 0, 1, )
def test_use_default_matrix(self): assert parse_quantisation_matrix_argument( None, WaveletFilters.le_gall_5_3, WaveletFilters.le_gall_5_3, 4, 0, ) == QUANTISATION_MATRICES[( WaveletFilters.le_gall_5_3, WaveletFilters.le_gall_5_3, 4, 0, )]
def test_custom_matrix_supplied(self): assert parse_quantisation_matrix_argument( "0 L 10 1 H 20".split(), WaveletFilters.le_gall_5_3, WaveletFilters.le_gall_5_3, 0, 1, ) == { 0: { "L": 10 }, 1: { "H": 20 }, }
def main(args=None): args = parse_args(args) # Load precomputed signal bounds static_filter_analysis = json.load(args.static_filter_analysis) quantisation_matrix = parse_quantisation_matrix_argument( args.custom_quantisation_matrix, static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], ) analysis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["analysis_signal_bounds"] ) synthesis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["synthesis_signal_bounds"] ) ( concrete_analysis_signal_bounds, concrete_synthesis_signal_bounds, ) = evaluate_filter_bounds( static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], analysis_signal_bounds, synthesis_signal_bounds, args.picture_bit_width, ) print(quantisation_index_bound( concrete_analysis_signal_bounds, quantisation_matrix, )) return 0
default=sys.stdout, type=FileType("w"), help=""" Filename to write the signal range information CSV to. Defaults to stdout. """) args = parser.parse_args() if args.wavelet_index_ho is None: args.wavelet_index_ho = args.wavelet_index args.quant_matrix = parse_quantisation_matrix_argument( args.quant_matrix, args.wavelet_index, args.wavelet_index_ho, args.dwt_depth, args.dwt_depth_ho, ) ################################################################################ # Read the picture ################################################################################ state = dict( wavelet_index=args.wavelet_index, wavelet_index_ho=args.wavelet_index_ho, dwt_depth=args.dwt_depth, dwt_depth_ho=args.dwt_depth_ho, quant_matrix=args.quant_matrix, )
assert static_filter_analysis["dwt_depth_ho"] == optimised_json[ "dwt_depth_ho"] args.picture_bit_width = optimised_json["picture_bit_width"] quantisation_matrix = deserialise_quantisation_matrix( optimised_json["quantisation_matrix"]) synthesis_test_signals = deserialise_test_signals( OptimisedTestSignalSpecification, optimised_json["optimised_synthesis_test_signals"]) else: quantisation_matrix = parse_quantisation_matrix_argument( args.custom_quantisation_matrix, static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], ) # Compute signal bounds for all specified bit widths # # analysis_bounds_dicts = [{(level, array_name, x, y): (lower_bound, upper_bound), ...}, ...] # synthesis_bounds_dicts = same as above concrete_analysis_bounds, concrete_synthesis_bounds = evaluate_filter_bounds( static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], analysis_signal_bounds, synthesis_signal_bounds,
def parse_args(args=None): parser = ArgumentParser(description=""" Create, or query a compressed bundle containing a set of static filter analyses (from vc2-static-filter-analysis) and optimised synthesis test patterns (from vc2-optimise-synthesis-test-patterns). """) subparsers = parser.add_subparsers() parser.add_argument( "--verbose", "-v", default=0, action="count", help=""" Show more detailed status information during execution. """, ) parser.set_defaults(action=None) create_parser = subparsers.add_parser( "create", help=""" Create a bundle file. """, ) create_parser.set_defaults(action="create") create_parser.add_argument( "bundle_file", type=FileType("wb"), help=""" Filename for the bundle file to create/overwrite. """, ) create_parser.add_argument( "--static-filter-analysis", "-s", type=FileType("rb"), nargs="+", metavar="JSON_FILE", action="append", default=[], help=""" Filenames of the JSON files containing static filter analyses produced by vc2-static-filter-analysis. """, ) create_parser.add_argument( "--optimised-synthesis-test-patterns", "-o", type=FileType("rb"), nargs="+", metavar="JSON_FILE", action="append", default=[], help=""" Filenames of the JSON files containing optimised synthesis test patterns produced by vc2-optimise-synthesis-test-patterns. """, ) ls_parser = subparsers.add_parser( "list", help=""" List the contents of a bundle file. """, ) ls_parser.set_defaults(action="list") ls_parser.add_argument( "bundle_file", type=FileType("rb"), help=""" Filename for the bundle file to list. """, ) extract_sfa_parser = subparsers.add_parser( "extract-static-filter-analysis", help=""" Extract a static filter analysis from the bundle. """, ) extract_sfa_parser.set_defaults(action="extract-static-filter-analysis") extract_ostp_parser = subparsers.add_parser( "extract-optimised-synthesis-test-patterns", help=""" Extract a set of optimised synthesis test patterns from the bundle. """, ) extract_ostp_parser.set_defaults(action="extract-optimised-synthesis-test-patterns") # Arguments shared by both extract subcommands for sub_parser in [extract_sfa_parser, extract_ostp_parser]: sub_parser.add_argument( "bundle_file", type=FileType("rb"), help=""" Filename for the bundle file to query. """, ) sub_parser.add_argument( "--output", "-o", type=FileType("w"), default=sys.stdout, help=""" Filename for the extracted JSON file. Defaults to stdout. """, ) sub_parser.add_argument( "--wavelet-index", "-w", type=wavelet_index_or_name, required=True, help=""" The VC-2 wavelet index for the wavelet transform. One of: {}. """.format(", ".join( "{} or {}".format(int(index), index.name) for index in WaveletFilters )), ) sub_parser.add_argument( "--wavelet-index-ho", "-W", type=wavelet_index_or_name, help=""" The VC-2 wavelet index for the horizontal parts of the wavelet transform. If not specified, assumed to be the same as --wavelet-index/-w. """, ) sub_parser.add_argument( "--dwt-depth", "-d", type=int, default=0, help=""" The VC-2 transform depth. Defaults to 0 if not specified. """ ) sub_parser.add_argument( "--dwt-depth-ho", "-D", type=int, default=0, help=""" The VC-2 horizontal-only transform depth. Defaults to 0 if not specified. """ ) # Add optimised synthesis test pattern specific arguments extract_ostp_parser.add_argument( "--picture-bit-width", "-b", type=int, required=True, help=""" The number of bits in the picture signal. """, ) extract_ostp_parser.add_argument( "--custom-quantisation-matrix", "-q", nargs="+", help=""" Use a custom quantisation matrix for the search. Optional except for filters without a default quantisation matrix defined. Should be specified as a series 3-argument tuples giving the level, orientation and quantisation matrix value for every entry in the quantisation matrix. """, ) args = parser.parse_args(args) if args.action is None: parser.error("Expected a command.") # Flatten create arguments if args.action == "create": args.static_filter_analysis = [ entry for lst in args.static_filter_analysis for entry in lst ] args.optimised_synthesis_test_patterns = [ entry for lst in args.optimised_synthesis_test_patterns for entry in lst ] # Auto-fill horizontal only wavelet if args.action in ( "extract-static-filter-analysis", "extract-optimised-synthesis-test-patterns", ): if args.wavelet_index_ho is None: args.wavelet_index_ho = args.wavelet_index if args.action == "extract-optimised-synthesis-test-patterns": args.quantisation_matrix = parse_quantisation_matrix_argument( args.custom_quantisation_matrix, args.wavelet_index, args.wavelet_index_ho, args.dwt_depth, args.dwt_depth_ho, ) return args
def load_filter_analysis( static_filter_analysis_file, optimised_synthesis_patterns_file, quantisation_matrix_argument, picture_bit_width, ): """ Load a static filter analysis and optionally a set of optimised synthesis test patterns, returning all of the loaded data. Parameters ========== static_filter_analysis_file : :py:class:`file` An open file ready to read the static filter analysis data from a JSON file. optimised_synthesis_patterns_file : :py:class:`file` or None An open file ready to read a set of optimised synthesis test patterns for a JSON file. If None, synthesis test patterns will be read from the ``static_filter_analysis_file`` instead. quantisation_matrix_argument : [str, ...] or None The --custom-quantisation-matrix argument which will be parsed (if optimised_synthesis_patterns_file is not provided) picture_bit_width : int or None The --picture-bit-width argument which will be used if no optimised_synthesis_test_patterns file is provided. Returns ======= wavelet_index : int wavelet_index_ho : int dwt_depth : int dwt_depth_ho : int quantisation_matrix : {level: {orient: value, ...}, ...} picture_bit_width : int max_quantisation_index : int concrete_analysis_bounds : {(level, array_name, x, y): (lo, hi), ...} concrete_synthesis_bounds : {(level, array_name, x, y): (lo, hi), ...} analysis_test_patterns : {(level, array_name, x, y): :py:class:`~vc2_bit_widths.patterns.TestPatternSpecification`, ...} synthesis_test_patterns : {(level, array_name, x, y): :py:class:`~vc2_bit_widths.patterns.TestPatternSpecification`, ...} """ # Load precomputed signal bounds static_filter_analysis = json.load(static_filter_analysis_file) analysis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["analysis_signal_bounds"] ) synthesis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["synthesis_signal_bounds"] ) # Load precomputed test patterns analysis_test_patterns = deserialise_test_pattern_specifications( TestPatternSpecification, static_filter_analysis["analysis_test_patterns"] ) synthesis_test_patterns = deserialise_test_pattern_specifications( TestPatternSpecification, static_filter_analysis["synthesis_test_patterns"] ) # Load optimised synthesis signal if optimised_synthesis_patterns_file is not None: optimised_json = json.load(optimised_synthesis_patterns_file) assert static_filter_analysis["wavelet_index"] == optimised_json["wavelet_index"] assert static_filter_analysis["wavelet_index_ho"] == optimised_json["wavelet_index_ho"] assert static_filter_analysis["dwt_depth"] == optimised_json["dwt_depth"] assert static_filter_analysis["dwt_depth_ho"] == optimised_json["dwt_depth_ho"] picture_bit_width = optimised_json["picture_bit_width"] quantisation_matrix = deserialise_quantisation_matrix( optimised_json["quantisation_matrix"] ) synthesis_test_patterns = deserialise_test_pattern_specifications( OptimisedTestPatternSpecification, optimised_json["optimised_synthesis_test_patterns"] ) else: quantisation_matrix = parse_quantisation_matrix_argument( quantisation_matrix_argument, static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], ) # Compute signal bounds for all specified bit widths # # analysis_bounds_dicts = [{(level, array_name, x, y): (lower_bound, upper_bound), ...}, ...] # synthesis_bounds_dicts = same as above concrete_analysis_bounds, concrete_synthesis_bounds = evaluate_filter_bounds( static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], analysis_signal_bounds, synthesis_signal_bounds, picture_bit_width, ) # Find the maximum quantisation index for each bit width max_quantisation_index = quantisation_index_bound( concrete_analysis_bounds, quantisation_matrix, ) return ( static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], quantisation_matrix, picture_bit_width, max_quantisation_index, concrete_analysis_bounds, concrete_synthesis_bounds, analysis_test_patterns, synthesis_test_patterns, )
def main(args=None): args = parse_args(args) if args.verbose: logging.basicConfig(level=logging.INFO) static_filter_analysis = json.load(args.static_filter_analysis) quantisation_matrix = parse_quantisation_matrix_argument( args.custom_quantisation_matrix, static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], ) analysis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["analysis_signal_bounds"]) synthesis_signal_bounds = deserialise_signal_bounds( static_filter_analysis["synthesis_signal_bounds"]) synthesis_test_patterns = deserialise_test_pattern_specifications( TestPatternSpecification, static_filter_analysis["synthesis_test_patterns"]) ( concrete_analysis_signal_bounds, concrete_synthesis_signal_bounds, ) = evaluate_filter_bounds( static_filter_analysis["wavelet_index"], static_filter_analysis["wavelet_index_ho"], static_filter_analysis["dwt_depth"], static_filter_analysis["dwt_depth_ho"], analysis_signal_bounds, synthesis_signal_bounds, args.picture_bit_width, ) max_quantisation_index = quantisation_index_bound( concrete_analysis_signal_bounds, quantisation_matrix, ) random_state = np.random.RandomState(args.seed) optimised_synthesis_test_patterns = optimise_synthesis_test_patterns( wavelet_index=static_filter_analysis["wavelet_index"], wavelet_index_ho=static_filter_analysis["wavelet_index_ho"], dwt_depth=static_filter_analysis["dwt_depth"], dwt_depth_ho=static_filter_analysis["dwt_depth_ho"], quantisation_matrix=quantisation_matrix, picture_bit_width=args.picture_bit_width, synthesis_test_patterns=synthesis_test_patterns, max_quantisation_index=max_quantisation_index, random_state=random_state, number_of_searches=args.number_of_searches, terminate_early=args.terminate_early, added_corruption_rate=args.added_corruption_rate, removed_corruption_rate=args.removed_corruption_rate, base_iterations=args.base_iterations, added_iterations_per_improvement=args.added_iterations_per_improvement, ) out = { "wavelet_index": static_filter_analysis["wavelet_index"], "wavelet_index_ho": static_filter_analysis["wavelet_index_ho"], "dwt_depth": static_filter_analysis["dwt_depth"], "dwt_depth_ho": static_filter_analysis["dwt_depth_ho"], "picture_bit_width": args.picture_bit_width, "quantisation_matrix": serialise_quantisation_matrix(quantisation_matrix, ), "optimised_synthesis_test_patterns": serialise_test_pattern_specifications( OptimisedTestPatternSpecification, optimised_synthesis_test_patterns, ) } json.dump(out, args.output) args.output.write("\n") return 0