2017-03-06 20:11:00 +00:00
import struct
import scipy
import scipy . misc
import scipy . cluster
import codecs
# from IPython.display import Markdown, display, HTML
import colorsys
import math
import numpy as np
2017-03-11 10:49:47 +00:00
import sklearn . cluster
from PIL import Image
2017-03-06 20:11:00 +00:00
NUM_CLUSTERS = 64
def getColourAsHex ( colour ) :
return ' # ' + ' ' . join ( format ( c , ' 02x ' ) for c in colour . astype ( int ) )
2017-03-11 10:49:47 +00:00
def getColoursForImageByKMeansClusters ( image ) :
2017-03-06 20:11:00 +00:00
"""
Adapted on answers by
Peter Hansen ( http : / / stackoverflow . com / a / 3244061 )
& Johan Mickos ( http : / / stackoverflow . com / a / 34140327 )
"""
im = image . copy ( ) . resize ( ( 150 , 150 ) ) # optional, to reduce time
ar = scipy . misc . fromimage ( im )
shape = ar . shape
ar = ar . reshape ( scipy . product ( shape [ : 2 ] ) , shape [ 2 ] )
# print( 'finding clusters')
codes , dist = scipy . cluster . vq . kmeans ( ar . astype ( float ) , NUM_CLUSTERS )
# print ('cluster centres:\n', codes)
vecs , dist = scipy . cluster . vq . vq ( ar , codes ) # assign codes
counts , bins = scipy . histogram ( vecs , len ( codes ) ) # count occurrences
# When only looking for single color:
# index_max = scipy.argmax(counts) # find most frequent
# peak = codes[index_max]
# colour = ''.join(chr(c) for c in peak).encode('hex')
# print( 'most frequent is %s (#%s)' % (peak, colour))
percentages = 100 * counts / sum ( counts )
# print("Percentages", percentages)
# colours = [ in codes]
# print(colours)
return list ( zip ( codes , percentages ) )
2017-03-11 10:49:47 +00:00
def getColoursForImageByMeanShiftClusters ( image , saveImgName = False ) :
"""
Adapted on answers by
Peter Hansen ( http : / / stackoverflow . com / a / 3244061 )
& Johan Mickos ( http : / / stackoverflow . com / a / 34140327 )
Now using MeanShift clustering
if saveImgName set to the path / prefix_ for the layer images , save images of each cluster matched pixels
"""
imgSize = ( 170 , 170 )
# imgSize = (int(targetWidth), int(image.size[1] / (image.size[0]/targetWidth)))
im = image . copy ( ) # optional, to reduce time
im . thumbnail ( imgSize )
imgSize = im . size
print ( " \t Render image of " , image . size , " for " , imgSize )
imgAr = scipy . misc . fromimage ( im )
shape = imgAr . shape
ar = imgAr . reshape ( scipy . product ( shape [ : 2 ] ) , shape [ 2 ] )
total = len ( ar )
# print( 'finding clusters')
# codes, dist = scipy.cluster.vq.kmeans(ar.astype(float), NUM_CLUSTERS)
bandwidth = sklearn . cluster . estimate_bandwidth ( ar . astype ( float ) , quantile = 0.1 , n_samples = 500 )
ms = sklearn . cluster . MeanShift ( bandwidth = bandwidth )
ms . fit ( ar . astype ( float ) )
labels = ms . labels_ # labels per point
cluster_centers = ms . cluster_centers_ # centers of found clusters
labels_unique = np . unique ( labels )
n_clusters_ = len ( labels_unique )
print ( " \t Clusters found: " , n_clusters_ )
colours = [ ]
for k in labels_unique :
cluster_center = cluster_centers [ k ] # np.array with rgb
mask = labels == k # True/False map of flattened array
# m = np.ma.masked_where(labels != k, labels)
count = len ( ar [ mask ] ) # nr of pixels for this label
# pass on percentages:
colours . append ( ( cluster_center , 100 * count / total ) )
if saveImgName :
# save image as RGBA with transparent pixels, except for there where label == k
layer = np . array ( [ np . append ( ar [ i ] , 255 ) if l == k else [ 0 , 0 , 0 , 0 ] for i , l in enumerate ( list ( labels ) ) ] , dtype = np . uint8 )
layerImgAr = layer . reshape ( ( imgSize [ 1 ] , imgSize [ 0 ] , 4 ) ) # layers are stacked: vertical, horizontal, rgba
layerImg = Image . fromarray ( layerImgAr , mode = " RGBA " )
layerFilename = saveImgName + ' - %s .png ' % k
layerImg . save ( layerFilename )
print ( layerFilename )
# display(HTML("<span style='background:%s'>%s</span>" % (getColourAsHex(cluster_center),getColourAsHex(cluster_center))))
return colours
2017-03-06 20:11:00 +00:00
def getColoursForImageByPxAvg ( image ) :
im = image . copy ( ) . resize ( ( 8 , 8 ) )
pixels = np . concatenate ( scipy . misc . fromimage ( im ) )
# colours = ['#' + ''.join(format(c, '02x') for c in color.astype(int)) for color in pixels]
percentages = np . zeros ( len ( pixels ) ) + ( 100 / len ( pixels ) )
return list ( zip ( pixels , percentages ) )
def getColoursAsHTML ( colours ) :
return " " . join ( [ ' <span style= " background: %s " > %s - ( %s %% )</span> ' % ( getColourAsHex ( colour [ 0 ] ) , getColourAsHex ( colour [ 0 ] ) , colour [ 1 ] ) for colour in colours ] ) ;
def loadColoursFromDbImages ( images ) :
2017-03-11 10:49:47 +00:00
return [ i . colours for i in images if not i . colours is None ]
2017-03-06 20:11:00 +00:00
def getSvgFromDbImages ( images , elId = " " ) :
# sum concatenates all colour arrays
2017-03-11 10:49:47 +00:00
# allColours = []
# for c in loadColoursFromDbImages(images):
# allColours += c
2017-03-06 20:11:00 +00:00
# box 160, because center or circle = 100 => +/- 50 => + r of colour circle (max: 10) => 160
2017-03-11 21:04:12 +00:00
# svg = '<svg viewBox="-160 -160 320 320" xmlns="http://www.w3.org/2000/svg" id="%s">' % (elId, )
svg = ' <svg viewBox= " -160 -160 320 320 " xmlns= " http://www.w3.org/2000/svg " style= " width:100 % ;height:95 % " id= " colourImage " > ' # because of IE this is fully defined here
2017-03-06 20:11:00 +00:00
radius = 100
2017-03-11 10:49:47 +00:00
for image in images :
if image . colours is None :
continue
for i , colour in enumerate ( image . colours ) :
colourId = ' %s - %s ' % ( image . id , i )
rgb , percentage = colour
rgbNorm = rgb / 255
hsv = colorsys . rgb_to_hsv ( rgbNorm [ 0 ] , rgbNorm [ 1 ] , rgbNorm [ 2 ] )
# find position on circle
radians = 2 * math . pi * hsv [ 0 ]
x = math . cos ( radians )
y = math . sin ( radians )
# based on saturation, we move inwards/outwards
# min = 0.5, max = 1.5 (dus + 0.5)
pos = np . array ( [ x , y ] ) * ( 0.5 + hsv [ 1 ] ) * radius
# Posibilitiy: determine position based on avg(saturation, value) => dark & grey inside, shiney and colourful outside
# pos = np.array([x,y]) * (0.5 + (hsv[1]+hsv[2])/2) * radius
r = max ( 1 , - 10 / percentage + 10 ) # as r, we converge to maximum radius 10, but don't want to get smaller radi then 1
2017-03-11 19:12:48 +00:00
c = ' <circle cx= " %s " cy= " %s " r= " %s " style= " fill: %s " onmouseover= " triggerover( \' %s \' , this) " ></circle> ' % ( pos [ 0 ] , pos [ 1 ] , r , getColourAsHex ( rgb ) , colourId )
2017-03-11 10:49:47 +00:00
svg + = c
2017-03-06 20:11:00 +00:00
svg + = " </svg> "
return svg