# HG changeset patch # User Paul Boddie # Date 1443785849 -7200 # Node ID 736979f993792736a288b559217ebfd96474aaf8 # Parent cd815af3effc57bd3a92b4861b7bb293ac104af3 Experiment with combining more than two colours at once for an input colour. diff -r cd815af3effc -r 736979f99379 optimiser.py --- a/optimiser.py Thu Oct 01 18:39:59 2015 +0200 +++ b/optimiser.py Fri Oct 02 13:37:29 2015 +0200 @@ -1,6 +1,6 @@ #!/usr/bin/env python -from random import randint +from random import random from os.path import extsep, splitext import EXIF import PIL.Image @@ -17,53 +17,30 @@ r2, g2, b2 = rgb2 return math.sqrt(pow(r1 - r2, 2) + pow(g1 - g2, 2) + pow(b1 - b2, 2)) -def brightness(rgb): - return distance(rgb, (0, 0, 0)) - -def factor(start, end, rgb): - r1, g1, b1 = start - r2, g2, b2 = end - gr, gg, gb = r2 - r1, g2 - g1, b2 - b1 - r, g, b = rgb - pr, pg, pb = r - r1, g - g1, b - b1 - dp = pr * gr + pg * gg + pb * gb - return dp / pow(distance(start, end), 2) - -def darklight(rgb1, rgb2): - if brightness(rgb1) <= brightness(rgb2): - return rgb1, rgb2 - else: - return rgb2, rgb1 - -def nearest(rgb, values=None): - l = map(lambda c: (distance(rgb, c), c), values or corners) - l.sort() - return l +def distribution(rgb, points): + l = [] + total = 0 + for c in points: + d = distance(rgb, c) + if d == 0: + return [(1, c)] + l.append((pow(d, -3), c)) + total += pow(d, -3) + return [(d / total, c) for d, c in l] def pattern(rgb, values=None): - l = nearest(rgb, values) - start, end = l[0][1], l[1][1] - f = factor(start, end, rgb) - #if f > 0.5: - # start, end = end, start - # f = 1 - f - return start, end, f + l = distribution(rgb, values or corners) + l.sort(reverse=True) + return l -def choose(seq, f): - last = int(seq * f) - current = int((seq + 1) * f) - return last != current - -def get_value(xy, rgb, width, height, values=None): - x, y = xy - rgb1, rgb2, f = pattern(rgb, values) - if choose(x + randint(0, width), f) and choose(y + randint(0, height), f): - return rgb2 - else: - return rgb1 - -def get_best(rgb, values): - return nearest(rgb, values)[0][1] +def get_value(rgb, values=None): + choose = random() + threshold = 0 + for f, c in pattern(rgb, values): + threshold += f + if choose < threshold: + return c + return c def sign(x): return x >= 0 and 1 or -1 @@ -80,7 +57,7 @@ im = PIL.Image.new("RGB", (size, size)) for g in range(0, size): for b in range(0, size): - value = get_value((g, b), (r, (g * 256) / size, (b * 256 / size)), size, size) + value = get_value((r, (g * 256) / size, (b * 256 / size))) im.putpixel((g, b), value) im.save("rgb%d.png" % r) @@ -89,7 +66,7 @@ im = PIL.Image.new("RGB", (size, size)) for y in range(0, size): for x in range(0, size): - im.putpixel((x, y), get_value((x, y), rgb, size, size)) + im.putpixel((x, y), get_value(rgb)) im.save("rgb%02d%02d%02d.png" % rgb) def rotate_and_scale(im, width, height, rotate): @@ -125,7 +102,7 @@ desaturate = sys.argv[3:].count("-d") x = EXIF.process_file(open(input_filename)) - im = PIL.Image.open(input_filename) + im = PIL.Image.open(input_filename).convert("RGB") im = rotate_and_scale(im, width, height, rotate) if preview: @@ -148,7 +125,7 @@ # Count the number of requested colours. - value = get_value((x, y), rgb, width, height) + value = get_value(rgb) if not c.has_key(value): c[value] = 1 else: @@ -174,9 +151,9 @@ # Get the requested colours and choose the closest alternative for # less common colours. - value = get_value((x, y), rgb, width, height) + value = get_value(rgb) if value in least: - value = get_value((x, y), rgb, width, height, most) + value = get_value(rgb, most) im.putpixel((x, y), value) im.save(output_filename)