80 lines
1.8 KiB
Python
80 lines
1.8 KiB
Python
# 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)
|