89 lines
No EOL
3.3 KiB
Python
89 lines
No EOL
3.3 KiB
Python
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
|
|
|
|
NUM_CLUSTERS = 64
|
|
|
|
def getColourAsHex(colour):
|
|
return '#' + ''.join(format(c, '02x') for c in colour.astype(int))
|
|
|
|
def getColoursForImageByClusters(image):
|
|
"""
|
|
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))
|
|
|
|
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):
|
|
return [i.colours for i in images]
|
|
|
|
|
|
def getSvgFromDbImages(images, elId = ""):
|
|
# sum concatenates all colour arrays
|
|
allColours = []
|
|
for c in loadColoursFromDbImages(images):
|
|
allColours += c
|
|
# box 160, because center or circle = 100 => +/- 50 => + r of colour circle (max: 10) => 160
|
|
svg = '<svg viewBox="-160 -160 320 320" xmlns="http://www.w3.org/2000/svg" id="%s">' % elId
|
|
|
|
radius = 100
|
|
|
|
for colour in allColours:
|
|
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
|
|
c = '<circle cx="%s" cy="%s" r="%s" style="fill:%s" />' % (pos[0], pos[1], r, getColourAsHex(rgb))
|
|
svg += c
|
|
|
|
svg += "</svg>"
|
|
return svg |