PaletteOptimiser

optimiser.py

7:18ebf1c73555
2015-09-08 Paul Boddie Removed redundant tables.
     1 #!/usr/bin/env python     2      3 from array import array     4 from itertools import combinations     5 import PIL.Image     6 import sys     7      8 def scale(v):     9     return (v + 64) / 128    10     11 def point(rgb):    12     return tuple(map(scale, rgb))    13     14 def index(p):    15     return p[0] * 9 + p[1] * 3 + p[2]    16     17 def colour(i):    18     return (255 * (i % 2), 255 * ((i / 2) % 2), 255 * ((i / 4) % 2))    19     20 def add(d, v):    21     d[v] = (d.has_key(v) and d[v] or 0) + 1    22     23 def by_frequency(d):    24     l = [(f, t) for (t, f) in d.items()]    25     l.sort(reverse=True)    26     return [i[1] for i in l]    27     28 def match(b, bases):    29     return b in bases and b    30     31 def match_lighter(b, bases):    32     return upward[b] in bases and upward[b]    33     34 def match_darker(b, bases):    35     return downward[b] in bases and downward[b]    36     37 def fallback(bases):    38     for b in by_frequency(bases):    39         if b not in ["_", "W"]:    40             return b    41     return by_frequency(bases)[0]    42     43 tones = [    44     "___", "_BB", "BBB", # 00x    45     "_GG", "_CC", "BCC", # 01x    46     "GGG", "GCC", "CCC", # 02x    47     "_RR", "_MM", "BMM", # 10x    48     "_YY", "_*W", "BBW", # 11x    49     "GYY", "GGW", "CCW", # 12x    50     "RRR", "RMM", "MMM", # 20x    51     "RYY", "RRW", "MMW", # 21x    52     "YYY", "YYW", "WWW", # 22x    53     ]    54     55 colours = ["_", "R", "G", "Y", "B", "M", "C", "W"]    56     57 if __name__ == "__main__":    58     width = 320    59     input_filename, output_filename = sys.argv[1:3]    60     61     im = PIL.Image.open(input_filename)    62     w, h = im.size    63     height = (width * h) / w    64     im = im.resize((width, height))    65     66     usage = []    67     base_usage = []    68     toned = []    69     70     for row in range(0, height):    71         u = {}    72         usage.append(u)    73         bu = {}    74         base_usage.append(bu)    75         tr = []    76         toned.append(tr)    77         for column in range(0, width):    78             rgb = im.getpixel((column, row))    79             p = point(rgb)    80             i = index(p)    81             t = tones[i]    82             add(u, t)    83             if t[0] != "*":    84                 add(bu, t[0])    85             if t[1] != "*":    86                 add(bu, t[1])    87             if t[2] != "*":    88                 add(bu, t[2])    89             tr.append(t)    90     91     chosen = []    92     93     for row, (u, bu) in enumerate(zip(usage, base_usage)):    94         light = row % 2    95         best = 0    96         best_bases = None    97         best_missing = None    98         best_map = None    99         for bases in combinations(bu, 4):   100             bases = dict([(base, bu[base]) for base in bases])   101             count = 0   102             missing = []   103             tone_map = {}   104             for tone, freq in u.items():   105                 base = match(tone[1], bases) or match(light and tone[2] or tone[0], bases)   106                 if base:   107                     tone_map[tone] = base   108                     count += freq   109                 else:   110                     missing.append(tone)   111             if count > best:   112                 best_bases = bases   113                 best_missing = missing   114                 best_map = tone_map   115                 best = count   116         chosen.append((best, best_bases or bases, best_map or tone_map, best_missing or missing))   117    118     output = []   119    120     for row, (tr, ch) in enumerate(zip(toned, chosen)):   121         o = []   122         for column, t in enumerate(tr):   123             best, bases, tone_map, missing = ch   124             base = tone_map.get(t) or fallback(bases)   125             o.append(base)   126             i = colours.index(base)   127             im.putpixel((column, row), colour(i))   128    129         output.append("".join(o))   130    131     im.save(output_filename)   132    133 # vim: tabstop=4 expandtab shiftwidth=4