From cdfce3a4f8a453fbcc44feb483f54abb45be4b10 Mon Sep 17 00:00:00 2001 From: Chris Mounce Date: Sun, 26 Jun 2022 13:18:40 -0700 Subject: [PATCH] Miscellaneous cleanup - Remove old dither code from dither.py - Commit an old color-distance experiment --- .gitignore | 1 + color-distance.py | 50 +++++++++++++++++++++++++++++++++++++++++++++++ dither.py | 35 --------------------------------- 3 files changed, 51 insertions(+), 35 deletions(-) create mode 100644 .gitignore create mode 100644 color-distance.py diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bee8a64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__ diff --git a/color-distance.py b/color-distance.py new file mode 100644 index 0000000..da1000c --- /dev/null +++ b/color-distance.py @@ -0,0 +1,50 @@ +# Playing with measuring color distances +# Cleaned-up transcript from an ipython session, mostly experimental. +# The actual compression algorithm probably won't use this. + +from dither import * + +def distance(x, y): + return 2.5*((x[0]-y[0])/255)**2 + 4*((x[1]-y[1])/255)**2 + 2.5*((x[2]-y[2])/255)**2 + +distances = {(i,j): distance(PICO_RGB[i],PICO_RGB[j]) for i in range(len(PICO_RGB)) for j in range(len(PICO_RGB))} + +def rect_distance_sum(img1, img2, xy1, xy2): + """Returns summed color distance of two images, using a rectangular mask""" + result = 0.0 + x1, y1 = xy1 + x2, y2 = xy2 + for y in range(y1, y2): + for x in range(x1, x2): + c1 = img1.getpixel((x, y)) + c2 = img2.getpixel((x, y)) + result += distances[(c1, c2)] + return result + +# d = dithered version of resized (peacock image, RGB color) +d = pattern_dither(resized, PICO_RGB[:16], amount=1) + +# s = nearest-color image +s = Image.new(size=d.size, mode='P', color=1) +s.putpalette([c for rgb in PICO_RGB[:16] for c in rgb]) + +def solid_cost(img, xy1, xy2, color): + """Returns cost of approximating a rectangular region with a solid color""" + x1, y1 = xy1 + x2, y2 = xy2 + result = 0.0 + for y in range(y1, y2): + for x in range(x1, x2): + p = img.getpixel((x, y)) + result += distances[(color, p)] + return result + +# Downsample the dithered image with a given size of rectangles +skip = 2 +for y in range(0, 128, skip): + for x in range(0, 128, skip): + _, i = min( (solid_cost(d, (x,y), (x+skip,y+skip), c), c) for c in range(16) ) + for x2 in range(x, x + skip): + for y2 in range(y, y + skip): + s.putpixel((x2,y2), i) +# s.show() diff --git a/dither.py b/dither.py index fa8b132..b101ab6 100644 --- a/dither.py +++ b/dither.py @@ -108,38 +108,3 @@ def pattern_dither(img, palette, *, pat_size=4, amount=0.75): result.putpalette([c for rgb in old_palette for c in rgb]) result.putdata([old_palette_indexes[i] for i in output_indexes]) return result - -def dither_pixel(img, xy, pal): - global bayer - pal2 = [np.array(rgb_to_linear(c)) for c in pal] - counts = [0]*len(pal) - x, y = xy - def diff(c1, c2): - return sum((c1-c2)**2) - def nearest(rgb): - cost, index = min((diff(rgb,c), i) for i,c in enumerate(pal2)) - return index - color = np.array(rgb_to_linear(img.getpixel(xy))) - err = np.array([0.0,0.0,0.0]) - for _ in range(bayer.size): - err += color - i = nearest(err) - counts[i] += 1 - err -= pal2[i] - thresh = bayer[y % bayer.shape[0]][x % bayer.shape[1]] - for i, count in enumerate(counts): - thresh -= count - if thresh < 0: - return i - -dithered = Image.new('P', resized.size) -dithered.putpalette([x for rgb in PICO_RGB[:16] for x in rgb]) -def do_it(): - global dithered, resized - for x in tqdm(range(128)): - for y in range(128): - i = dither_pixel(resized, (x,y), PICO_RGB[:16]) - dithered.putpixel((x,y), i) -# import cProfile -# cProfile.run('do_it()') -#do_it()