1.1 --- a/optimiser.py Tue Sep 08 14:42:05 2015 +0200
1.2 +++ b/optimiser.py Tue Sep 08 19:52:24 2015 +0200
1.3 @@ -1,6 +1,8 @@
1.4 #!/usr/bin/env python
1.5
1.6 from array import array
1.7 +from itertools import combinations
1.8 +from random import randint
1.9 import PIL.Image
1.10 import sys
1.11
1.12 @@ -16,37 +18,147 @@
1.13 def colour(i):
1.14 return (255 * (i % 2), 255 * ((i / 2) % 2), 255 * ((i / 4) % 2))
1.15
1.16 +def add(d, v):
1.17 + d[v] = (d.has_key(v) and d[v] or 0) + 1
1.18 +
1.19 +def by_frequency(d):
1.20 + l = [(f, t) for (t, f) in d.items()]
1.21 + l.sort(reverse=True)
1.22 + return [i[1] for i in l]
1.23 +
1.24 +def match(b, bases):
1.25 + return b in bases and b
1.26 +
1.27 +def match_lighter(b, bases):
1.28 + return upward[b] in bases and upward[b]
1.29 +
1.30 +def match_darker(b, bases):
1.31 + return downward[b] in bases and downward[b]
1.32 +
1.33 +def match_tone(t, bases):
1.34 + return match(t[1], bases)
1.35 +
1.36 +def match_variant(t, bases, fn):
1.37 + return fn(t[0], bases)
1.38 +
1.39 +def neutral(bases, light):
1.40 + l = ["W", "C", "Y", "M", "G", "R", "B", "_"]
1.41 + if not light:
1.42 + l.reverse()
1.43 + for b in l:
1.44 + if b in bases:
1.45 + return b
1.46 + return bases[randint(0, 3)]
1.47 +
1.48 tones = [
1.49 - "__", "B_", "BB", # 00x
1.50 - "G_", "C_", "CB", # 01x
1.51 - "GG", "CG", "CC", # 02x
1.52 - "R_", "M_", "MB", # 10x
1.53 - "Y_", "W_", "WB", # 11x
1.54 - "YG", "WG", "WC", # 12x
1.55 - "RR", "MR", "MM", # 20x
1.56 - "YR", "WR", "WM", # 21x
1.57 + "__", "_B", "BB", # 00x
1.58 + "_G", "_C", "BC", # 01x
1.59 + "GG", "GC", "CC", # 02x
1.60 + "_R", "_M", "BM", # 10x
1.61 + "_Y", "**", "WB", # 11x
1.62 + "GY", "WG", "WC", # 12x
1.63 + "RR", "RM", "MM", # 20x
1.64 + "RY", "WR", "WM", # 21x
1.65 "YY", "WY", "WW", # 22x
1.66 ]
1.67
1.68 colours = ["_", "R", "G", "Y", "B", "M", "C", "W"]
1.69
1.70 +upward = {
1.71 + "_" : ["R", "G", "B"],
1.72 + "R" : ["Y", "M"],
1.73 + "G" : ["Y", "C"],
1.74 + "B" : ["C", "M"],
1.75 + "Y" : ["W"],
1.76 + "C" : ["W"],
1.77 + "M" : ["W"],
1.78 + "W" : ["W"],
1.79 + "*" : ["W", "Y", "C", "M"],
1.80 + }
1.81 +
1.82 +downward = {
1.83 + "_" : ["_"],
1.84 + "R" : ["_"],
1.85 + "G" : ["_"],
1.86 + "B" : ["_"],
1.87 + "Y" : ["R", "G"],
1.88 + "C" : ["G", "B"],
1.89 + "M" : ["R", "B"],
1.90 + "W" : ["Y", "C", "M"],
1.91 + "*" : ["R", "G", "B", "_"],
1.92 + }
1.93 +
1.94 if __name__ == "__main__":
1.95 -
1.96 + width = 320
1.97 + height = 192
1.98 input_filename, output_filename = sys.argv[1:3]
1.99
1.100 im = PIL.Image.open(input_filename)
1.101 - im = im.resize((320, 256))
1.102 + im = im.resize((width, height))
1.103 +
1.104 + usage = []
1.105 + base_usage = []
1.106 + toned = []
1.107
1.108 - for row in range(0, 256):
1.109 - for column in range(0, 320):
1.110 + for row in range(0, height):
1.111 + u = {}
1.112 + usage.append(u)
1.113 + bu = {}
1.114 + base_usage.append(bu)
1.115 + tr = []
1.116 + toned.append(tr)
1.117 + for column in range(0, width):
1.118 rgb = im.getpixel((column, row))
1.119 p = point(rgb)
1.120 i = index(p)
1.121 t = tones[i]
1.122 - c = t[row % 2]
1.123 - i = colours.index(c)
1.124 + add(u, t)
1.125 + if t[0] != "*":
1.126 + add(bu, t[0])
1.127 + if t[1] != "*":
1.128 + add(bu, t[1])
1.129 + tr.append(t)
1.130 +
1.131 + chosen = []
1.132 +
1.133 + light = True
1.134 + for u, bu in zip(usage, base_usage):
1.135 + best = 0
1.136 + best_bases = None
1.137 + best_missing = None
1.138 + best_map = None
1.139 + for bases in combinations(bu, 4):
1.140 + count = 0
1.141 + missing = []
1.142 + tone_map = {}
1.143 + for tone, freq in u.items():
1.144 + base = match(light and tone[1] or tone[0], bases)
1.145 + if base:
1.146 + tone_map[tone] = base
1.147 + count += freq
1.148 + else:
1.149 + missing.append(tone)
1.150 + if count > best:
1.151 + best_bases = bases
1.152 + best_missing = missing
1.153 + best_map = tone_map
1.154 + best = count
1.155 + chosen.append((best, best_bases or bases, best_map or tone_map, best_missing or missing))
1.156 + light = not light
1.157 +
1.158 + output = []
1.159 +
1.160 + for row, (tr, ch) in enumerate(zip(toned, chosen)):
1.161 + o = []
1.162 + for column, t in enumerate(tr):
1.163 + best, bases, tone_map, missing = ch
1.164 + base = tone_map.get(t) or neutral(bases, light)
1.165 + o.append(base)
1.166 + i = colours.index(base or "_")
1.167 im.putpixel((column, row), colour(i))
1.168
1.169 + output.append("".join(o))
1.170 +
1.171 im.save(output_filename)
1.172
1.173 # vim: tabstop=4 expandtab shiftwidth=4