def test_offset_picture(self): test_patterns = OrderedDict([ ( (1, "Output", 0, 0), TPS( pattern=TP({ (2, 1): +1, (1, 2): -1, }), pattern_translation_multiple=(4, 4), target=(1, 1), target_translation_multiple=(1, 1), ), ), ]) width, height = 20, 10 pictures, locations = pack_test_patterns(width, height, test_patterns) assert len(pictures) == 1 assert list(locations) == list(test_patterns) # Should have been assigned to the top-left most point possible exp_picture = np.zeros((height, width), dtype=np.int8) exp_picture[1, 2] = +1 exp_picture[2, 1] = -1 assert np.array_equal(pictures[0], exp_picture) assert locations[(1, "Output", 0, 0)] == (0, 1, 1)
def test_simple_packing(self): test_patterns = OrderedDict([ ( (1, "Output", 0, 0), TPS( pattern=TP({ (2, 1): +1, (1, 2): -1, }), pattern_translation_multiple=(4, 4), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 1), TPS( pattern=TP({ (2, 1): +1, (1, 2): +1, }), pattern_translation_multiple=(4, 4), target=(1, 1), target_translation_multiple=(1, 1), ), ), ]) width, height = 20, 10 pictures, locations = pack_test_patterns(width, height, test_patterns) assert len(pictures) == 1 assert list(locations) == list(test_patterns) exp_picture = np.zeros((height, width), dtype=np.int8) # First pattern, top left exp_picture[1, 2] = +1 exp_picture[2, 1] = -1 # Second pattern, just underneath exp_picture[5, 2] = +1 exp_picture[6, 1] = +1 assert np.array_equal(pictures[0], exp_picture) assert locations[(1, "Output", 0, 0)] == (0, 1, 1) assert locations[(1, "Output", 0, 1)] == (0, 1, 2)
def generate_test_pictures( picture_width, picture_height, picture_bit_width, analysis_test_patterns, synthesis_test_patterns, synthesis_test_pattern_outputs, ): """ Generate a series of test pictures containing the supplied selection of test patterns. Parameters ========== picture_width : int picture_height : int The dimensions of the pictures to generate. picture_bit_width : int The number of bits in the input pictures. 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`, ...} The individual analysis and synthesis test patterns to be combined. A maximising and minimising variant of each pattern will be included in the output. See :py:func:`static_filter_analysis` and :py:func:`optimise_synthesis_test_patterns`. synthesis_test_pattern_outputs : {(level, array_name, x, y): ((lower_bound, qi), (upper_bound, qi)), ...} The worst-case quantisation indicies for each synthesis test pattern, as computed by :py:func:`evaluate_test_pattern_outputs`. Returns ======= analysis_pictures : [:py:class:`AnalysisPicture`, ...] synthesis_pictures : [:py:class:`SynthesisPicture`, ...] A series of test pictures containing correctly aligned instances of each supplied test pattern. Pictures are returned with values in the range 0 to (2**picture_bit_width)-1, as expected by a VC-2 encoder. Each analysis picture includes a subset of the test patterns supplied (see :py:class:`AnalysisPicture`). The analysis test pictures are intended to be passed to an analysis filter as-is. Each synthesis test picture includes a subset of the test patterns supplied, grouped according to the quantisation index to be used. The synthesis test pictures should first be passed through a synthesis filter and then the transform coefficients quantised using the quantisation index specified (see :py:class:`SynthesisPicture`). The quantised transform coefficients should then be passed through the synthesis filter. """ input_min, input_max = unsigned_integer_range(picture_bit_width) input_mid = (input_max - input_min + 1) // 2 # For better packing, the test patterns will be packed in size order, # largest first. analysis_test_patterns = OrderedDict( sorted( analysis_test_patterns.items(), key=lambda kv: len(kv[1].pattern), reverse=True, )) synthesis_test_patterns = OrderedDict( sorted( synthesis_test_patterns.items(), key=lambda kv: len(kv[1].pattern), reverse=True, )) # Pack analysis signals logger.info( "Packing %d analysis test patterns...", len(analysis_test_patterns) * 2, ) analysis_test_patterns_bipolar = OrderedDict(( (level, array_name, x, y, maximise), spec if maximise else invert_test_pattern_specification(spec), ) for (level, array_name, x, y), spec in analysis_test_patterns.items() for maximise in [True, False]) pictures, locations = pack_test_patterns( picture_width, picture_height, analysis_test_patterns_bipolar, ) if len(locations) < len(analysis_test_patterns_bipolar): logger.warning( "%d analysis test patterns were too large to fit in a " "%d x %d picture and were omitted.", len(analysis_test_patterns_bipolar) - len(locations), picture_width, picture_height, ) analysis_pictures = [ AnalysisPicture( make_saturated_picture(picture, input_min, input_max, input_mid), [], ) for picture in pictures ] for (level, array_name, x, y, maximise), (picture_index, tx, ty) in locations.items(): analysis_pictures[picture_index].test_points.append( TestPoint( level, array_name, x, y, maximise, tx, ty, )) logger.info( "Packed analysis test patterns into %d pictures.", len(analysis_pictures), ) # Group synthesis test patterns by required quantisation index logger.info( "Packing %d synthesis test patterns...", len(synthesis_test_patterns) * 2, ) # {quantisation_index: {(level, array_name, x, y, maximise): spec, ...}, ...} synthesis_test_patterns_grouped = defaultdict(OrderedDict) for (level, array_name, x, y), spec in synthesis_test_patterns.items(): (_, minimising_qi), (_, maximising_qi) = synthesis_test_pattern_outputs[( level, array_name, x, y)] synthesis_test_patterns_grouped[maximising_qi][(level, array_name, x, y, True)] = spec synthesis_test_patterns_grouped[minimising_qi][( level, array_name, x, y, False)] = invert_test_pattern_specification(spec) # Pack the synthesis the test patterns, grouped by QI synthesis_pictures = [] num_too_large = 0 for qi in sorted(synthesis_test_patterns_grouped): pictures, locations = pack_test_patterns( picture_width, picture_height, synthesis_test_patterns_grouped[qi], ) num_too_large += len( synthesis_test_patterns_grouped[qi]) - len(locations) this_synthesis_pictures = [ SynthesisPicture( make_saturated_picture(picture, input_min, input_max, input_mid), qi, [], ) for picture in pictures ] for (level, array_name, x, y, maximise), (picture_index, tx, ty) in locations.items(): this_synthesis_pictures[picture_index].test_points.append( TestPoint( level, array_name, x, y, maximise, tx, ty, )) synthesis_pictures += this_synthesis_pictures if len(locations) < len(synthesis_test_patterns_grouped[qi]): logger.warning( "%d synthesis test patterns were too large to fit in a " "%d x %d picture and were omitted.", num_too_large, picture_width, picture_height, ) logger.info( "Packed synthesis test patterns into %d pictures.", len(synthesis_pictures), ) return ( analysis_pictures, synthesis_pictures, )
def test_large_test_patterns_skipped(self): test_patterns = OrderedDict([ ( (1, "Output", 0, 0), TPS( pattern=TP({ (1, 0): +1, (0, 1): -1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 1), TPS( pattern=TP({ (100, 0): -1, (0, 100): -1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 2), TPS( pattern=TP({ (1, 0): -1, (0, 1): +1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ]) width, height = 20, 10 pictures, locations = pack_test_patterns(width, height, test_patterns) assert len(pictures) == 1 assert list(locations) == [ (1, "Output", 0, 0), (1, "Output", 0, 2), ] exp_picture = np.zeros((height, width), dtype=np.int8) # First pattern, top left exp_picture[0, 1] = +1 exp_picture[1, 0] = -1 # Third pattern, underneath exp_picture[2, 1] = -1 exp_picture[3, 0] = +1 assert np.array_equal(pictures[0], exp_picture) assert locations[(1, "Output", 0, 0)] == (0, 1, 1) assert locations[(1, "Output", 0, 2)] == (0, 1, 3)
def test_overspill_pictures(self): # Tests that allocation can overspill onto extra pictures and that # later allocations can be inserted onto any available picture. # # +------+------+ +-------------+ # | | | | 1 | # | 0 | 2 | +-------------+ # | | | | 3 | # +------+------+ +-------------+ # test_patterns = OrderedDict([ ( (1, "Output", 0, 0), TPS( pattern=TP({ (9, 0): -1, (0, 9): -1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 1), TPS( pattern=TP({ (19, 0): +1, (0, 4): -1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 2), TPS( pattern=TP({ (9, 0): +1, (0, 9): +1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 3), TPS( pattern=TP({ (19, 0): -1, (0, 4): +1, }), pattern_translation_multiple=(1, 1), target=(1, 1), target_translation_multiple=(1, 1), ), ), ]) width, height = 20, 10 pictures, locations = pack_test_patterns(width, height, test_patterns) assert len(pictures) == 2 assert list(locations) == list(test_patterns) exp_picture_0 = np.zeros((height, width), dtype=np.int8) exp_picture_1 = np.zeros((height, width), dtype=np.int8) # Pattern 0 exp_picture_0[0, 9] = -1 exp_picture_0[9, 0] = -1 # Pattern 1 exp_picture_1[0, 19] = +1 exp_picture_1[4, 0] = -1 # Pattern 2 exp_picture_0[0, 19] = +1 exp_picture_0[9, 10] = +1 # Pattern 3 exp_picture_1[5, 19] = -1 exp_picture_1[9, 0] = +1 assert np.array_equal(pictures[0], exp_picture_0) assert np.array_equal(pictures[1], exp_picture_1) assert locations[(1, "Output", 0, 0)] == (0, 1, 1) assert locations[(1, "Output", 0, 1)] == (1, 1, 1) assert locations[(1, "Output", 0, 2)] == (0, 11, 1) assert locations[(1, "Output", 0, 3)] == (1, 1, 6)
def test_target_translation(self): # The test patterns should be allocated like so: # # +--+----+-----+ # |0 | 1 | | # +--+ | | # | +----+-+---+ # | | 2 | | # | | | | # +--+------+---+ # test_patterns = OrderedDict([ ( (1, "Output", 0, 0), TPS( pattern=TP({ (2, 1): +1, (1, 2): -1, }), pattern_translation_multiple=(4, 4), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 1), TPS( pattern=TP({ (10, 1): +1, (1, 5): +1, }), pattern_translation_multiple=(4, 4), target=(1, 1), target_translation_multiple=(1, 1), ), ), ( (1, "Output", 0, 2), TPS( pattern=TP({ (5, 1): -1, (1, 5): -1, }), pattern_translation_multiple=(4, 4), target=(2, 3), target_translation_multiple=(4, 5), ), ), ]) width, height = 20, 15 pictures, locations = pack_test_patterns(width, height, test_patterns) assert len(pictures) == 1 assert list(locations) == list(test_patterns) exp_picture = np.zeros((height, width), dtype=np.int8) # First pattern, top left exp_picture[1, 2] = +1 exp_picture[2, 1] = -1 # Second pattern, just to the right exp_picture[1, 14] = +1 exp_picture[5, 5] = +1 # Third pattern, below-right of both exp_picture[13, 5] = -1 exp_picture[9, 9] = -1 assert np.array_equal(pictures[0], exp_picture) assert locations[(1, "Output", 0, 0)] == (0, 1, 1) assert locations[(1, "Output", 0, 1)] == (0, 2, 1) assert locations[(1, "Output", 0, 2)] == (0, 2 + 4, 3 + (2 * 5))