mirror of
https://github.com/KrisKennaway/ii-vision.git
synced 2024-09-27 04:54:59 +00:00
Add some tests for edit_weight and byte_to_colour_string
This commit is contained in:
parent
7db5c1c444
commit
718dc15cf2
25
video.py
25
video.py
@ -24,34 +24,31 @@ def hamming_weight(n):
|
||||
n = (n & 0x0F) + ((n & 0xF0) >> 4)
|
||||
return n
|
||||
|
||||
# TODO: what about increasing transposition cost? Might be better to have
|
||||
# any pixel at the right place even if the wrong colour?
|
||||
|
||||
# K G V W
|
||||
# O B
|
||||
|
||||
error_substitute_costs = np.ones((128, 128), dtype=np.float64)
|
||||
substitute_costs = np.ones((128, 128), dtype=np.float64)
|
||||
|
||||
# Penalty for turning on/off a black bit
|
||||
for c in "01GVWOB":
|
||||
error_substitute_costs[(ord('K'), ord(c))] = 5
|
||||
error_substitute_costs[(ord(c), ord('K'))] = 5
|
||||
substitute_costs[(ord('K'), ord(c))] = 5
|
||||
substitute_costs[(ord(c), ord('K'))] = 5
|
||||
|
||||
# Penalty for changing colour
|
||||
for c in "01GVWOB":
|
||||
for d in "01GVWOB":
|
||||
error_substitute_costs[(ord(c), ord(d))] = 1
|
||||
error_substitute_costs[(ord(d), ord(c))] = 1
|
||||
substitute_costs[(ord(c), ord(d))] = 1
|
||||
substitute_costs[(ord(d), ord(c))] = 1
|
||||
|
||||
insert_costs = np.ones(128, dtype=np.float64) * 1000
|
||||
delete_costs = np.ones(128, dtype=np.float64) * 1000
|
||||
|
||||
|
||||
@functools.lru_cache(None)
|
||||
def edit_weight(a: int, b: int, is_odd_offset: bool, error=False):
|
||||
def edit_weight(a: int, b: int, is_odd_offset: bool):
|
||||
a_pixels = byte_to_colour_string(a, is_odd_offset)
|
||||
b_pixels = byte_to_colour_string(b, is_odd_offset)
|
||||
|
||||
substitute_costs = error_substitute_costs # if error else None
|
||||
|
||||
dist = weighted_levenshtein.dam_lev(
|
||||
a_pixels, b_pixels,
|
||||
insert_costs=insert_costs,
|
||||
@ -82,12 +79,12 @@ def byte_to_colour_string(b: int, is_odd_offset: bool) -> str:
|
||||
"W" # 0x11
|
||||
), (
|
||||
"K", # 0x00
|
||||
"O", # 0x01
|
||||
"B", # 0x10
|
||||
"B", # 0x01
|
||||
"O", # 0x10
|
||||
"W" # 0x11
|
||||
)
|
||||
)
|
||||
palette = palettes[b & 0x80 != 0]
|
||||
palette = palettes[(b & 0x80) != 0]
|
||||
|
||||
for _ in range(3):
|
||||
pixel = palette[(b >> idx) & 0b11]
|
||||
|
334
video_test.py
334
video_test.py
@ -16,152 +16,216 @@ class TestHammingWeight(unittest.TestCase):
|
||||
self.assertEqual(7, video.hamming_weight(0b11111110))
|
||||
|
||||
|
||||
class TestVideo(unittest.TestCase):
|
||||
def testEncodeEmptyFrame(self):
|
||||
f = screen.MemoryMap(screen_page=1)
|
||||
v = video.Video()
|
||||
class TestByteToColourString(unittest.TestCase):
|
||||
def testEncoding(self):
|
||||
self.assertEqual(
|
||||
"KKK0", video.byte_to_colour_string(0, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
"0KKK", video.byte_to_colour_string(0, is_odd_offset=True))
|
||||
|
||||
self.assertEqual([], list(v.encode_frame(f)))
|
||||
self.assertEqual(
|
||||
"WWW1", video.byte_to_colour_string(0xff, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
"1WWW", video.byte_to_colour_string(0xff, is_odd_offset=True))
|
||||
|
||||
def testEncodeOnePixel(self):
|
||||
f = screen.HGR140Bitmap()
|
||||
a = np.zeros((f.YMAX, f.XMAX), dtype=bool)
|
||||
a[0, 0] = True
|
||||
self.assertEqual(
|
||||
"GGG0", video.byte_to_colour_string(0x2a, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
"1GGG", video.byte_to_colour_string(0x55, is_odd_offset=True))
|
||||
|
||||
f = screen.HGR140Bitmap(a).to_memory_map(screen_page=1)
|
||||
|
||||
v = video.Video()
|
||||
|
||||
want = [
|
||||
opcodes.SetPage(0x20),
|
||||
opcodes.SetContent(0x03),
|
||||
opcodes.Store(0x00),
|
||||
]
|
||||
got = list(v.encode_frame(f))
|
||||
self.assertListEqual(want, got)
|
||||
self.assertEqual(
|
||||
"OOO0", video.byte_to_colour_string(0xaa, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
"1OOO", video.byte_to_colour_string(0xd5, is_odd_offset=True))
|
||||
|
||||
|
||||
class TestIndexPage(unittest.TestCase):
|
||||
def testFullPageSameValue(self):
|
||||
"""Constant data with nonzero weights should return single run"""
|
||||
v = video.Video()
|
||||
|
||||
data = np.ones((256,), dtype=np.uint8)
|
||||
class TestEditWeight(unittest.TestCase):
|
||||
def testTransposition(self):
|
||||
self.assertEqual("WKK0", video.byte_to_colour_string(
|
||||
0b00000011, is_odd_offset=False))
|
||||
self.assertEqual("KWK0", video.byte_to_colour_string(
|
||||
0b00001100, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
1, video.edit_weight(0b00000011, 0b00001100, is_odd_offset=False)
|
||||
)
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = [(256, 0, 1, 256)]
|
||||
got = list(v._index_page(video.hamming_weight(data), data))
|
||||
self.assertEqual("OWK1", video.byte_to_colour_string(
|
||||
0b11001110, is_odd_offset=False))
|
||||
self.assertEqual("OKW1", video.byte_to_colour_string(
|
||||
0b11110010, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
1, video.edit_weight(0b11001110, 0b11110010, is_odd_offset=False)
|
||||
)
|
||||
|
||||
self.assertEqual(want, got)
|
||||
def testSubstitution(self):
|
||||
# Black has cost 5
|
||||
self.assertEqual("WKK0", video.byte_to_colour_string(
|
||||
0b00000011, is_odd_offset=False))
|
||||
self.assertEqual("KKK0", video.byte_to_colour_string(
|
||||
0b00000000, is_odd_offset=False))
|
||||
self.assertEqual(
|
||||
5, video.edit_weight(0b00000011, 0b00000000, is_odd_offset=False)
|
||||
)
|
||||
self.assertEqual(
|
||||
5, video.edit_weight(0b00000000, 0b00000011, is_odd_offset=False)
|
||||
)
|
||||
|
||||
def testFullPageZeroValue(self):
|
||||
"""Zero data with 0 weights should return nothing"""
|
||||
v = video.Video()
|
||||
|
||||
data = np.zeros((256,), dtype=np.uint8)
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = []
|
||||
got = list(v._index_page(video.hamming_weight(data), data))
|
||||
|
||||
self.assertEqual(want, got)
|
||||
|
||||
def testFullPageZeroValueWithDiff(self):
|
||||
"""Zero data with nonzero weights should return single run"""
|
||||
v = video.Video()
|
||||
|
||||
old_data = np.ones((256,), dtype=np.uint8)
|
||||
|
||||
data = np.zeros((256,), dtype=np.uint8)
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = [(256, 0, 0, 256)]
|
||||
got = list(v._index_page(video.hamming_weight(old_data), data))
|
||||
|
||||
self.assertEqual(want, got)
|
||||
|
||||
def testSingleRun(self):
|
||||
"""Single run of nonzero data"""
|
||||
v = video.Video()
|
||||
|
||||
data = np.zeros((256,), dtype=np.uint8)
|
||||
for i in range(5):
|
||||
data[i] = 1
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = [(5, 0, 1, 5)]
|
||||
got = list(v._index_page(video.hamming_weight(data), data))
|
||||
|
||||
self.assertEqual(want, got)
|
||||
|
||||
def testTwoRuns(self):
|
||||
"""Two consecutive runs of nonzero data"""
|
||||
v = video.Video()
|
||||
|
||||
data = np.zeros((256,), dtype=np.uint8)
|
||||
for i in range(5):
|
||||
data[i] = 1
|
||||
for i in range(5, 10):
|
||||
data[i] = 2
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = [(5, 0, 1, 5), (5, 5, 2, 5)]
|
||||
got = list(v._index_page(video.hamming_weight(data), data))
|
||||
|
||||
self.assertEqual(want, got)
|
||||
|
||||
def testShortRun(self):
|
||||
"""Run that is too short to encode as RLE opcode"""
|
||||
v = video.Video()
|
||||
|
||||
data = np.zeros((256,), dtype=np.uint8)
|
||||
for i in range(2):
|
||||
data[i] = 1
|
||||
|
||||
# total_xor_difference, start_offset, content, run_length
|
||||
want = [(1, 0, 1, 1), (1, 1, 1, 1)]
|
||||
got = list(v._index_page(video.hamming_weight(data), data))
|
||||
|
||||
self.assertEqual(want, got)
|
||||
# Other colour has cost 1
|
||||
self.assertEqual(
|
||||
1, video.edit_weight(0b00000010, 0b00000011, is_odd_offset=False)
|
||||
)
|
||||
self.assertEqual(
|
||||
1, video.edit_weight(0b00000011, 0b00000010, is_odd_offset=False)
|
||||
)
|
||||
|
||||
|
||||
class TestEncodeDecode(unittest.TestCase):
|
||||
def testEncodeDecode(self):
|
||||
for _ in range(10):
|
||||
s = video.Video(frame_rate=1)
|
||||
screen_cls = screen.HGR140Bitmap
|
||||
|
||||
im = np.random.randint(
|
||||
0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
f = screen_cls(im).to_memory_map(screen_page=1)
|
||||
|
||||
_ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
|
||||
# assert that the screen decodes to the original bitmap
|
||||
bm = screen_cls.from_bytemap(s.memory_map.to_bytemap()).bitmap
|
||||
|
||||
self.assertTrue(np.array_equal(bm, im))
|
||||
|
||||
def testEncodeDecodeTwoFrames(self):
|
||||
|
||||
for _ in range(10):
|
||||
s = video.Video(frame_rate=1)
|
||||
screen_cls = screen.HGR140Bitmap
|
||||
|
||||
im = np.random.randint(
|
||||
0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
f = screen_cls(im).to_memory_map(screen_page=1)
|
||||
_ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
|
||||
im2 = np.random.randint(
|
||||
0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
f = screen_cls(im2).to_memory_map(screen_page=1)
|
||||
_ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
|
||||
# assert that the screen decodes to the original bitmap
|
||||
bm = screen_cls.from_bytemap(s.memory_map.to_bytemap()).bitmap
|
||||
|
||||
self.assertTrue(np.array_equal(bm, im2))
|
||||
# class TestVideo(unittest.TestCase):
|
||||
# def testEncodeEmptyFrame(self):
|
||||
# f = screen.MemoryMap(screen_page=1)
|
||||
# v = video.Video()
|
||||
#
|
||||
# self.assertEqual([], list(v.encode_frame(f)))
|
||||
#
|
||||
# def testEncodeOnePixel(self):
|
||||
# f = screen.HGR140Bitmap()
|
||||
# a = np.zeros((f.YMAX, f.XMAX), dtype=bool)
|
||||
# a[0, 0] = True
|
||||
#
|
||||
# f = screen.HGR140Bitmap(a).to_memory_map(screen_page=1)
|
||||
#
|
||||
# v = video.Video()
|
||||
#
|
||||
# want = [
|
||||
# opcodes.SetPage(0x20),
|
||||
# opcodes.SetContent(0x03),
|
||||
# opcodes.Store(0x00),
|
||||
# ]
|
||||
# got = list(v.encode_frame(f))
|
||||
# self.assertListEqual(want, got)
|
||||
#
|
||||
#
|
||||
# class TestIndexPage(unittest.TestCase):
|
||||
# def testFullPageSameValue(self):
|
||||
# """Constant data with nonzero weights should return single run"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# data = np.ones((256,), dtype=np.uint8)
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = [(256, 0, 1, 256)]
|
||||
# got = list(v._index_page(video.hamming_weight(data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
# def testFullPageZeroValue(self):
|
||||
# """Zero data with 0 weights should return nothing"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# data = np.zeros((256,), dtype=np.uint8)
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = []
|
||||
# got = list(v._index_page(video.hamming_weight(data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
# def testFullPageZeroValueWithDiff(self):
|
||||
# """Zero data with nonzero weights should return single run"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# old_data = np.ones((256,), dtype=np.uint8)
|
||||
#
|
||||
# data = np.zeros((256,), dtype=np.uint8)
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = [(256, 0, 0, 256)]
|
||||
# got = list(v._index_page(video.hamming_weight(old_data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
# def testSingleRun(self):
|
||||
# """Single run of nonzero data"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# data = np.zeros((256,), dtype=np.uint8)
|
||||
# for i in range(5):
|
||||
# data[i] = 1
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = [(5, 0, 1, 5)]
|
||||
# got = list(v._index_page(video.hamming_weight(data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
# def testTwoRuns(self):
|
||||
# """Two consecutive runs of nonzero data"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# data = np.zeros((256,), dtype=np.uint8)
|
||||
# for i in range(5):
|
||||
# data[i] = 1
|
||||
# for i in range(5, 10):
|
||||
# data[i] = 2
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = [(5, 0, 1, 5), (5, 5, 2, 5)]
|
||||
# got = list(v._index_page(video.hamming_weight(data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
# def testShortRun(self):
|
||||
# """Run that is too short to encode as RLE opcode"""
|
||||
# v = video.Video()
|
||||
#
|
||||
# data = np.zeros((256,), dtype=np.uint8)
|
||||
# for i in range(2):
|
||||
# data[i] = 1
|
||||
#
|
||||
# # total_xor_difference, start_offset, content, run_length
|
||||
# want = [(1, 0, 1, 1), (1, 1, 1, 1)]
|
||||
# got = list(v._index_page(video.hamming_weight(data), data))
|
||||
#
|
||||
# self.assertEqual(want, got)
|
||||
#
|
||||
#
|
||||
# class TestEncodeDecode(unittest.TestCase):
|
||||
# def testEncodeDecode(self):
|
||||
# for _ in range(10):
|
||||
# s = video.Video(frame_rate=1)
|
||||
# screen_cls = screen.HGR140Bitmap
|
||||
#
|
||||
# im = np.random.randint(
|
||||
# 0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
# f = screen_cls(im).to_memory_map(screen_page=1)
|
||||
#
|
||||
# _ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
#
|
||||
# # assert that the screen decodes to the original bitmap
|
||||
# bm = screen_cls.from_bytemap(s.memory_map.to_bytemap()).bitmap
|
||||
#
|
||||
# self.assertTrue(np.array_equal(bm, im))
|
||||
#
|
||||
# def testEncodeDecodeTwoFrames(self):
|
||||
#
|
||||
# for _ in range(10):
|
||||
# s = video.Video(frame_rate=1)
|
||||
# screen_cls = screen.HGR140Bitmap
|
||||
#
|
||||
# im = np.random.randint(
|
||||
# 0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
# f = screen_cls(im).to_memory_map(screen_page=1)
|
||||
# _ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
#
|
||||
# im2 = np.random.randint(
|
||||
# 0, 2, (screen_cls.YMAX, screen_cls.XMAX), dtype=np.bool)
|
||||
# f = screen_cls(im2).to_memory_map(screen_page=1)
|
||||
# _ = bytes(s.emit_stream(s.encode_frame(f)))
|
||||
#
|
||||
# # assert that the screen decodes to the original bitmap
|
||||
# bm = screen_cls.from_bytemap(s.memory_map.to_bytemap()).bitmap
|
||||
#
|
||||
# self.assertTrue(np.array_equal(bm, im2))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
Loading…
Reference in New Issue
Block a user