I spent a day back in Python and it was wonderful but not altogether perfect. It’s like the old friend that you spend some time with, and it’s comforting and affirming, but after a while they begin to p*** you off.

Also after so long of OOP it’s nice to be back in functional programming for a quick job like this.

I wanted to average the colours of each colour image drawn way back in the flavour workshop, and then average these colours to return…….the average colour used to describe each flavour. This small project was started with good intentions but ended with a satisfactory to middling ‘alright’ result. It wasn’t how I expected, but it was cool to see the variety.

I manually sorted the files into bitter, sweet etc folders and set about accessing these and averaging them using a script I found on GitHub. I adapted it to navigate my own file system and create two averages – a collection of averages of single images, and a final image averaging the colours for that category.

from PIL import Image
import sys, os
import numpy

def average_colour(image):

colour_tuple = [None, None, None]
for channel in range(3):

# Get data for one channel at a time
pixels = image.getdata(band=channel)

values = []
for pixel in pixels:

colour_tuple[channel] = sum(values) / len(values)

return tuple(colour_tuple)

def most_frequent_colour(image):

w, h = image.size
pixels = image.getcolors(w * h)

most_frequent_pixel = pixels[0]

for count, colour in pixels:
if count > most_frequent_pixel[0]:
most_frequent_pixel = (count, colour)

return most_frequent_pixel[1]

def average_colour_in_k_clusters(image, k):

def compare(title, image, colour_tuple):
image = Image.new("RGB", (200, 200,), colour_tuple)
return image

def kmeans(pixels, k):
numFeatures = len(pixels)

centroids = getRandomCentroids(numFeatures, k)

iterations = 0
oldCentroids = None

while not shouldStop(oldCentroids, centroids, iterations):

oldCentroids = centroids

interations += 1

def save(name, result, image):
# image.save("images/results/{}.jpg".format(name))
sample = Image.new("RGB", (200, 200,), result)

def main():
for images_folder in os.listdir(os.getcwd()):

if images_folder == "images":
for folder in os.listdir(os.getcwd()):
if folder.endswith('_colour'):
colour_tuples = []

for i in os.listdir(os.getcwd()):

if i.endswith(".png"):
image = Image.open(i)
result = average_colour(image)

if result[0] and result[1] and result[2] >= 254:

# save(i, result, image)
red = int(numpy.mean([int(i[0]) for i in colour_tuples]))
green = int(numpy.mean([int(i[1]) for i in colour_tuples]))
blue = int(numpy.mean([int(i[2]) for i in colour_tuples]))

average_rgb = tuple([red,green,blue])

print "Average RGB for "+ folder +" : ", average_rgb

sample = Image.new("RGB", (200, 200,), average_rgb)


if __name__ == "__main__":

As I have mentioned previously, I wanted to remove my subjectivity from this process, however I feel I might have employed some in the final, manual stages of this small project, that being amping the saturation up to detail the difference in hue more obviously. At first, a lot of the images were coming out white, as there is a lot of white space in each image, so I decided to drop the whiter tuples in favour of the more hued.

This is the resulting Finder view of the script four the sour category;

Screen Shot 2015-05-28 at 02.10.50

And the final averages;

Screen Shot 2015-05-28 at 02.12.23

Against the white background, bordered with drop shadows they look strikingly different, however on my (now grey) Processing sketch, they appear too similar to make any statement, hence the amped up saturation i’ll implement in my next iteration.

Looking back on my initial predictions, it was interesting to see that the sweet colour was indeed warmer, more ‘summery’ compared to the others, and that umami was rather cool and bland. Here, bitter is darker than the other averages, which reflects the overwhelmed feeling I experienced with the initial images.

Generally, an interesting little project, i’m glad I decided to automate this process.