Skip to content

Instantly share code, notes, and snippets.

@linus
Created March 2, 2011 12:27
Show Gist options
  • Save linus/850851 to your computer and use it in GitHub Desktop.
Save linus/850851 to your computer and use it in GitHub Desktop.
Så gjorde vi Rättviseförmedlingens pressbild
# Return the Euclidean distance between color_a and color_b.
# We optimize a little and don't calculate the square root of the distance.
# The sum of the squares of deltas is good enough.
def color_distance(color_a, color_b):
delta_red = color_a[0] - color_b[0]
delta_green = color_a[1] - color_b[1]
delta_blue = color_a[2] - color_b[2]
return delta_red * delta_red + delta_green * delta_green + delta_blue * delta_blue
TILE_SIZE = 50
# Return a list of tuples with (image, color) for each image in profile_pictures
def profile_colors(profile_pictures):
colors = []
for picture in profile_pictures:
image = Image.open(picture)
colors.append(image, get_color(image))
return colors
# Main function. Takes the original image and a list of profile pictures, and returns the finished mosaic
def create_mosaic(original_image, profile_pictures):
# Calculate the width and height of the scaled image, where each profile picture maps to a pixel in the original image
width, height = image_ratio(original_image, len(profile_pictures))
# Get the pixel values of the scaled image
pixels = get_pixels(original_image, (width, height))
# Get a random list of (x, y) values for each pixel in the image
slices = random_slices(width, height)
# Get a list of tuples with (image, color) for each profile picture
tiles = profile_colors(profile_pictures)
# Create a new image for our mosaic
mosaic = Image.new("RGB", (width * TILE_SIZE, height * TILE_SIZE))
# Go through all random pixels
while(len(slices) > 0):
# Take one pixel
(x, y) = slices.pop()
# Find the nearest profile picture
picture = find_nearest(pixels[x, y], tiles)
# Calculate where we should paste it into the mosaic
position = (x * TILE_SIZE, y * TILE_SIZE)
# Resize the picture to the specified size and paste it in the right position (TILE_SIZE is actually the same size as the profile pictures here, but this makes it easy for us to specify any other size for each tile in the mosaic)
mosaic.paste(picture.resize((TILE_SIZE, TILE_SIZE), Image.ANTIALIAS), position)
return mosaic
# Finds the nearest color in tiles, and removes that tile since it is used
# A tile is a tuple (a pair) of image and the color of that image - (image, color)
def find_nearest(color, tiles):
try:
# Parameter key to sort() takes a function, which calculates the color distance between that tile's color (tile[1]) and the specified color
tiles.sort(key=lambda tile: color_distance(tile[1], color))
# pop() removes that tile from the list, so we don't use it again, and [0] is the actual image
return tiles.pop()[0]
except:
return None
from PIL import Image
# Resize an image to 1 pixel and return the color of that pixel
def get_color(img):
try:
return img.convert("RGB").resize((1, 1), Image.ANTIALIAS).getpixel((0, 0))
except IOError:
# If something went wrong, return None
return None
from random import shuffle
def random_slices(width, height):
slices = [(x, y) for x in range(width) for y in range(height)]
shuffle(slices)
return slices
{
"id":"361481469749",
"name":"R\u00e4ttvisef\u00f6rmedlingen",
"picture":"http:\/\/profile.ak.fbcdn.net\/hprofile-ak-snc4\/23305_361481469749_9327_s.jpg",
"link":"http:\/\/www.facebook.com\/rattviseformedlingen",
"category":"Local business",
"website":"www.rattviseformedlingen.se",
"username":"rattviseformedlingen",
"description":"www.rattviseformedlingen.se",
"location":{
"city":"Stockholm",
"country":"Sweden",
"zip":"rattvisa\u0040frau.se"
},
"public_transit":"R\u00c4TTVISEF\u00d6RMEDLINGEN hj\u00e4lper er som s\u00f6ker folk att hitta alternativ ifr\u00e5n underrepresenterade grupper. Vi vill korrigera skevheter och verka f\u00f6r en r\u00e4ttvis representation i ett j\u00e4mlikt samh\u00e4lle.\n\nVi hj\u00e4lper er som har sv\u00e5rt att hitta annat \u00e4n m\u00e4n f\u00f6r medverkan i era tidningar, tv-program, historieb\u00f6cker, f\u00f6rel\u00e4sningar, p\u00e5 konserter, klubbar, debatter och galor.\n\nVi f\u00f6resl\u00e5r g\u00e4rna andra \u00e4n kvinnor som kan prata om barnomsorg, feminism och f\u00f6r\u00e4ldraskap.\n\nVi hj\u00e4lper dessutom g\u00e4rna till att komma till r\u00e4tta med andra skevheter som handlar om att inte alla sorters m\u00e4nniskor syns och h\u00f6rs. Skicka f\u00f6rslag till: rattvisa\u0040frau.se\n\nR\u00e4ttvisef\u00f6rmedlingens m\u00e5l \u00e4r ett samh\u00e4lle d\u00e4r en m\u00e4nniskas k\u00f6n, \u00e5lder, utseende och ursprung inte begr\u00e4nsar dennes m\u00f6jligheter och r\u00e4ttigheter att g\u00f6ra vad den vill och kan.\n\nR\u00e4ttvisef\u00f6rmedlingen vill och kan alldeles kostnadsfritt hj\u00e4lpa er hitta prima alternativ. F\u00f6r dom finns.\n\nDelta i projektet genom att g\u00e5 med i R\u00e4ttvisef\u00f6rmedlingen h\u00e4r p\u00e5 Facebook!\n\nS\u00e5 h\u00e4r jobbar vi: Optimistiskt, konstruktivt och tolerant. Allas tips \u00e4r v\u00e4lkomna. Vi m\u00e5nar om projekt som v\u00e4nder sig till oss f\u00f6r hj\u00e4lp (heja dom!). Inl\u00e4gg som inte \u00e4r efterlysningar rensas (\u00e4ven glada, fina tillrop) och \u00f6vriga diskussioner l\u00e5ter vi ske n\u00e5n annanstans. H\u00e4r efterlyser och tipsar vi - och forts\u00e4ttter p\u00e5 s\u00e5 vis g\u00f6ra konkret skillnad.\n\nI alla v\u00e5ra efterlysningar \u00e4r ni v\u00e4lkomna att tipsa om passande personer som inte k\u00e4nner sig hemma i ben\u00e4mningen kvinna\/man. Det \u00e4r inte kategorierna som \u00e4r det viktiga, utan m\u00e5ngfalden och normbrytandet.\n\nKontakt: rattvisa\u0040frau.se\n\nR\u00e4ttvisef\u00f6rmedlingen \u00e4r ett projekt av FRAU, www.frau.se ",
"likes":23122
}
from math import sqrt
def image_ratio(img, number_of_profile_pictures):
# Original size
original_width, original_height = img.size
# Calculate the factor: square root of the original size divided
# by the number of profile pictures
scale_factor = sqrt(original_width * original_height / number_of_profile_pictures)
# Get the new width and height
width = int(round(original_width / scale_factor))
height = int(round(original_height / scale_factor))
return (width, height)
def get_pixels(img, size):
# Resize the image and load the pixel data into pixels
# each profile picture corresponds to one pixel in pixels
pixels = img.convert("RGB").resize(size, Image.ANTIALIAS).load()
return pixels
{
"id":"548215162",
"name":"Linus G Thiel",
"first_name":"Linus",
"middle_name":"G",
"last_name":"Thiel",
"link":"http:\/\/www.facebook.com\/yesbabyyes",
"birthday":"01\/25\/1978",
"hometown":{
"id":"106505586052951",
"name":"Stockholm, Sweden"
},
"bio":"Superduperfly r\u00f6r mig genom lasern, till basen\r\nE h\u00e4r ett tag vet inte vart jag ska sen\r\n- Lorentz",
"quotes":"Think wrongly, if you please, but in all cases think for yourself.\r\n- Doris Lessing\r\n\r\nSuperduperfly r\u00f6r mig genom lasern, till basen, e h\u00e4r ett tag vet inte vart jag ska sen\r\n- Lorentz\r\n\r\n[Pragmatism] is all very well in theory, but it doesn't work in practice.\r\n- Sidney Morgenbesser\r\n\r\nThe reasonable man adapts himself to the world; the unreasonable one persists in trying to adapt the world to himself. Therefore all progress depends on the unreasonable man.\r\n- George Bernard Shaw",
"work":[
{
"employer":{
"id":"240999545243",
"name":"Hansson & Larsson"
},
"location":{
"id":"106505586052951",
"name":"Stockholm, Sweden"
},
"position":{
"id":"146619875364730",
"name":"Programmerare"
},
"with":[
{
"id":"1495928420",
"name":"Gunnar Hansson"
}
],
"description":"Hacking for food",
"start_date":"2009-06"
},
{
"employer":{
"id":"105601929475243",
"name":"Bomben"
},
"location":{
"id":"106505586052951",
"name":"Stockholm, Sweden"
},
"position":{
"id":"137396562963803",
"name":"Co-Founder"
},
"start_date":"1998",
"end_date":"2005"
}
],
"favorite_teams":[
{
"id":"170732612971123",
"name":"Hot Dog Stand"
},
{
"id":"150030745050989",
"name":"Sneakersnstuff"
}
],
"inspirational_people":[
{
"id":"113529011990795",
"name":"Steve Jobs"
},
{
"id":"113346302012058",
"name":"Grace Hopper"
},
{
"id":"111835365499393",
"name":"Roger Penrose"
},
{
"id":"216346540057",
"name":"Dancing Richard M. Stallman"
},
{
"id":"108200182540813",
"name":"Maria Gaetana Agnesi"
}
],
"gender":"male",
"interested_in":[
"female"
],
"website":"www.yby.se\nwww.myspace.com\/yesbabyyes",
"timezone":1,
"locale":"en_US",
"verified":true,
"updated_time":"2011-02-26T00:45:19+0000"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment