Skip to content

Instantly share code, notes, and snippets.

@christianp
Created March 6, 2014 10:42
Show Gist options
  • Save christianp/9387171 to your computer and use it in GitHub Desktop.
Save christianp/9387171 to your computer and use it in GitHub Desktop.
from math import sqrt
from rtree import index
from itertools import product
from PIL import Image
from random import shuffle
import numpy
# granularity of colour comonents
component_max = 64
# values each colour component can take
component_space = range(component_max)
# Ratio between component_max and 256
colour_scale = component_max/255.0
# unique id number for an (r,g,b) tuple
def id(colour):
r,g,b = colour
return r*component_max*component_max + g*component_max + b
# convert id back to (r,g,b) tuple
def unid(n):
b = n % component_max
n = (n-b)/component_max
g = n % component_max
n = (n-g)/component_max
r = n
return (r,g,b)
# make a 3d r-tree
property_3d = index.Property()
property_3d.dimension = 3
idx = index.Index(properties=property_3d)
# fill up the r-tree with one of every colour
print("Filling r-tree...")
for colour in product(component_space,component_space,component_space):
idx.insert(id(colour),colour)
# calculate width of an image which contains every colour
img_width = int(sqrt(component_max**3))
# load the input image
print("Opening image...")
img = Image.open(open(r'd:\tmp\4096doge.png','rb')).resize((img_width,img_width))
#create the output image
new_img = Image.new('RGB',(img_width,img_width))
arr = numpy.array(new_img)
# shuffle up the pixels in the output image
print("Shuffling pixels...")
pixels = list(product(range(img_width),range(img_width)))
shuffle(pixels)
print("Replacing pixels...")
progress = 0
l = len(pixels)
acc = 0
for pixel in pixels:
acc += 1.0
oprogress, progress = progress, int(100*acc/l)
if progress>oprogress:
print(progress)
# get the colour of this pixel in the source image
colour = [c*colour_scale for c in img.getpixel(pixel)]
# find the id of the nearest colour still in the r-tree
nearest = idx.nearest(colour).next()
# convert back from the id to (r,g,b)
r,g,b = unid(nearest)
# remove it from the r-tree
idx.delete(nearest,(r,g,b))
new_pixel = arr[pixel]
new_pixel[0] = r/colour_scale
new_pixel[1] = g/colour_scale
new_pixel[2] = b/colour_scale
print("Saving image...")
new_img = Image.fromarray(arr)
new_img.save("out.png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment