# coding: utf-8 from PIL import Image img = Image.open('peacock.jpg') resized = img.resize((128,128)) hex_colors = """#000000 #1D2B53 #7E2553 #008751 #AB5236 #5F574F #C2C3C7 #FFF1E8 #FF004D #FFA300 #FFEC27 #00E436 #29ADFF #83769C #FF77A8 #FFCCAA #291814 #111D35 #422136 #125359 #742F29 #49333B #A28879 #F3EF7D #BE1250 #FF6C24 #A8E72E #00B543 #065AB5 #754665 #FF6E59 #FF9D81""" pico_palette_32 = [x.strip() for x in hex_colors.splitlines()] def hex_to_rgb(h): dec = lambda x: int(x, base=16) return (dec(h[1:3]), dec(h[3:5]), dec(h[5:7])) pico_rgb = [hex_to_rgb(x) for x in pico_palette_32] import numpy as np bayer = np.array([[0]]) np.block([[4*bayer, 4*bayer+3],[4*bayer+2, 4*bayer+1]]) bayer = np.block([[4*bayer, 4*bayer+3],[4*bayer+2, 4*bayer+1]]) bayer = np.block([[4*bayer, 4*bayer+3],[4*bayer+2, 4*bayer+1]]) bayer = np.block([[4*bayer, 4*bayer+3],[4*bayer+2, 4*bayer+1]]) def dither_pixel(img, xy, pal): global bayer pal2 = [np.array(list(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(list(img.getpixel(xy))) err = np.array([0,0,0]) for _ in range(64): err += color i = nearest(err) counts[i] += 1 err -= pal2[i] thresh = bayer[y % 8][x % 8] 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]) import qtdm import tqdm for x in tqdm.tqdm(range(128)): for y in range(128): i = dither_pixel(resized, (x,y), pico_rgb[:16]) dithered.putpixel((x,y), i)