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
import sklearn.cluster
from PIL import Image
NUM_CLUSTERS = 64
def getColourAsHex(colour):
return '#' + ''.join(format(c, '02x') for c in colour.astype(int))
def getColoursForImageByKMeansClusters(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 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("\tRender 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("\tClusters 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("%s" % (getColourAsHex(cluster_center),getColourAsHex(cluster_center))))
return colours
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(['%s - (%s %%)' % (getColourAsHex(colour[0]), getColourAsHex(colour[0]), colour[1]) for colour in colours]);
def loadColoursFromDbImages(images):
return [i.colours for i in images if not i.colours is None]
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 = '"
return svg