Skip to content

Instantly share code, notes, and snippets.

@Josef-Friedrich
Created May 27, 2019 11:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Josef-Friedrich/51350435faee48c0f9d9ba0cc4efe778 to your computer and use it in GitHub Desktop.
Save Josef-Friedrich/51350435faee48c0f9d9ba0cc4efe778 to your computer and use it in GitHub Desktop.
# http://kneasle.weebly.com/hama-beads.html
from PIL import Image
import random, math
import tkinter as tk
def diff( num1 , num2 ):
return max( num1 , num2 ) - min( num1 , num2 )
#create a class to store the HAMA bead colors
class Color:
def __init__( self , r , g , b , name = 'NoName' ):
self.r = r
self.g = g
self.b = b
self.name = name
self.index = 0
#returns the difference between this color, and
#another one
def dist( self , r1 , g1 , b1 ):
r = diff( self.r , r1 )
g = diff( self.g , g1 )
b = diff( self.b , b1 )
return ( r + g + b ) / 3
#returns a tuple representing the color
def get( self ):
return ( self.r , self.g , self.b )
#override the string so I can print colors easily
def __str__( self ):
return '<COL:(' + str( self.r ) + \
',' + str( self.g ) + \
',' + str( self.b ) + \
') ' + self.name + '>'
# pick the best colored bead for a given pixel colour
# (r1 and r2 the randomness to add a bit of variety/texturing
# to the image)
# r1: total amount of randomness
# r2: bias towards the "correct" color
def pick_best( cols , r , g , b , r1 = 0 , r2 = 2 ):
# create a function to find the appropriateness of all the colors
func = lambda p: p.dist( r , g , b )
#sort the colors (so the first one will be the best)
sort = sorted( cols , key = func )
#return the one of the first colours (will be a good match)
return sort[ int( round( r1 * random.random() ** r2 ) ) ]
def mousemove( evt ):
# calculate which dot the mouse is hovering over
x = math.floor( evt.x / grid_size )
y = math.floor( evt.y / grid_size )
# try to output the colour (sometimes the program crashes doing this,
# so I added a work-around
try:
out.config( text = '(' + str( x + 1 ) + ',' + str( y + 1 ) + '): ' \
+ str( cols[ x ][ y ].name ) + ' #' + \
str( cols[ x ][ y ].index ) )
except IndexError:
print( 'error' , x , y )
colors = [
Color( 236 , 237 , 237 , 'H01-white' ) ,
Color( 240 , 232 , 185 , 'H02-cream' ) ,
Color( 240 , 185 , 1 , 'H03-yellow' ) ,
Color( 230 , 79 , 39 , 'H04-orange' ) ,
Color( 182 , 49 , 54 , 'H05-red' ) ,
Color( 225 , 136 , 159 , 'H06-pink' ) ,
Color( 105 , 74 , 130 , 'H07-purple' ) ,
Color( 44 , 70 , 144 , 'H08-dark blue' ) ,
Color( 48 , 92 , 176 , 'H09-light blue' ) ,
Color( 37 , 104 , 71 , 'H10-mid green' ) ,
Color( 73 , 174 , 137 , 'H11-light green' ) ,
Color( 83 , 65 , 55 , 'H12-brown' ) ,
Color( 131 , 136 , 138 , 'H17-grey' ) ,
Color( 46 , 47 , 49 , 'H18-black' ) ,
Color( 127 , 51 , 42 , 'H20-reddish brown' ) ,
Color( 165 , 105 , 63 , 'H21-light brown' ) ,
Color( 222 , 155 , 144 , 'H26-flesh' ) ,
Color( 222 , 180 , 139 , 'H27-beige' ) ,
Color( 54 , 63 , 56 , 'H28-dark green' ) ,
Color( 185 , 57 , 94 , 'H29-claret' ) ,
Color( 103 , 151 , 174 , 'H31-turquoise' ) ,
Color( 167 , 98 , 36 , 'N05-caramel' )
]
# number and darken the colours
darkening = 0
for ind , i in enumerate( colors ):
# index the colours for quick reference
i.index = ind + 1
# darken all of the colours (clamping at zero,
# as negative colours don't exist)
i.r = max( 0 , i.r - darkening )
i.g = max( 0 , i.g - darkening )
i.b = max( 0 , i.b - darkening )
if __name__ == '__main__':
# open file
file = 'home.png'
img = Image.open( file )
# load the pixel map for the image
pixels = img.load()
# create a matrix of all the colours
cols = [
[ None for i in range( img.size[ 1 ] ) ]
for i in range( img.size[ 0 ] )
]
for i in range(img.size[0]): # for every pixel:
for j in range(img.size[1]):
# get the colour from the matrix
r , g , b = pixels[ i , j ]
# set up the random number generator so that the numbers are always
# the same. This means that if you refresh the image, it stays
# identical
random.seed( str( i ) + '-' + str( j ) )
# find the best colour, add it to the matrix, and change the pixel
col = pick_best( colors , r , g , b , 1 , 10 )
cols[ i ][ j ] = col
pixels[i,j] = ( col.r , col.g , col.b ) # set the colour accordingly
# save the image as an export copy
img.save( 'E_' + file , 'PNG' )
#create global variable for the grid size
global grid_size
grid_size = 20
# create tkinter elements
master = tk.Tk()
master.title( 'BUGELPERLEN: ' + file )
# create a canvas big enough to hold the entire image (zoomed in)
canvas = tk.Canvas(
master ,
width = img.size[ 0 ] * grid_size + 1,
height = img.size[ 1 ] * grid_size + 1,
highlightthickness = 0
)
# create an output label
out = tk.Label(
master ,
font = ( 'Courier' , 30 )
)
#create the ovals
for i in range( img.size[ 0 ] ):
for j in range( img.size[ 1 ] ):
# 'b' stores how much overlap is required between the ovals
b = 3
canvas.create_oval(
i * grid_size - b , j * grid_size - b ,
( i + 1 ) * grid_size + b , ( j + 1 ) * grid_size + b ,
fill = "#%02x%02x%02x" % cols[ i ][ j ].get() ,
width = 0
)
# bind an on-mouse-move command to update the output box
canvas.bind( '<Motion>' , mousemove )
# start the app
canvas.pack()
out.pack()
master.mainloop()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment