PaletteOptimiser

Change of optimiser.py

29:21c5d47536ea
optimiser.py
     1.1 --- a/optimiser.py	Fri Oct 02 13:37:29 2015 +0200
     1.2 +++ b/optimiser.py	Fri Oct 02 19:22:17 2015 +0200
     1.3 @@ -1,9 +1,11 @@
     1.4  #!/usr/bin/env python
     1.5  
     1.6 +from dither import dither
     1.7  from random import random
     1.8 -from os.path import extsep, splitext
     1.9 +from os.path import splitext
    1.10  import EXIF
    1.11  import PIL.Image
    1.12 +import itertools
    1.13  import math
    1.14  import sys
    1.15  
    1.16 @@ -17,10 +19,10 @@
    1.17      r2, g2, b2 = rgb2
    1.18      return math.sqrt(pow(r1 - r2, 2) + pow(g1 - g2, 2) + pow(b1 - b2, 2))
    1.19  
    1.20 -def distribution(rgb, points):
    1.21 +def distribution(rgb, values=None):
    1.22      l = []
    1.23      total = 0
    1.24 -    for c in points:
    1.25 +    for c in values or corners:
    1.26          d = distance(rgb, c)
    1.27          if d == 0:
    1.28              return [(1, c)]
    1.29 @@ -51,6 +53,22 @@
    1.30  def saturate_value(x, exp):
    1.31      return int(127.5 + sign(x - 127.5) * 127.5 * pow(abs(x - 127.5) / 127.5, exp))
    1.32  
    1.33 +def get_best(im, width, y, colours):
    1.34 +    best = 0
    1.35 +    best_values = None
    1.36 +
    1.37 +    for values in itertools.combinations([value for n, value in colours], 4):
    1.38 +        current = 0
    1.39 +        for x in range(0, width):
    1.40 +            rgb = im.getpixel((x, y))
    1.41 +            for f, value in distribution(rgb, values):
    1.42 +                current += f
    1.43 +        if current >= best:
    1.44 +            best_values = values
    1.45 +            best = current
    1.46 +
    1.47 +    return best_values
    1.48 +
    1.49  def test():
    1.50      size = 512
    1.51      for r in (0, 63, 127, 191, 255):
    1.52 @@ -94,21 +112,23 @@
    1.53  
    1.54      input_filename, output_filename = sys.argv[1:3]
    1.55      basename, ext = splitext(output_filename)
    1.56 -    preview_filename = extsep.join([basename + "_preview", ext])
    1.57  
    1.58 -    preview = "-p" in sys.argv[3:]
    1.59      rotate = "-r" in sys.argv[3:]
    1.60      saturate = sys.argv[3:].count("-s")
    1.61      desaturate = sys.argv[3:].count("-d")
    1.62 +    best = "-b" in sys.argv[3:]
    1.63 +    dithering = "-d" in sys.argv[3:]
    1.64  
    1.65      x = EXIF.process_file(open(input_filename))
    1.66      im = PIL.Image.open(input_filename).convert("RGB")
    1.67      im = rotate_and_scale(im, width, height, rotate)
    1.68  
    1.69 -    if preview:
    1.70 -        im_preview = im.copy()
    1.71 +    width, height = im.size
    1.72  
    1.73 -    width, height = im.size
    1.74 +    im_original = im
    1.75 +
    1.76 +    if dithering:
    1.77 +        im = dither(im).convert("RGB")
    1.78  
    1.79      colours = []
    1.80  
    1.81 @@ -123,28 +143,25 @@
    1.82                  rgb = saturate_rgb(rgb, saturate and math.pow(0.5, saturate) or math.pow(2, desaturate))
    1.83                  im.putpixel((x, y), rgb)
    1.84  
    1.85 -            # Count the number of requested colours.
    1.86 +            # Sum the colour probabilities.
    1.87  
    1.88 -            value = get_value(rgb)
    1.89 -            if not c.has_key(value):
    1.90 -                c[value] = 1
    1.91 -            else:
    1.92 -                c[value] += 1
    1.93 -
    1.94 -            if preview:
    1.95 -                im_preview.putpixel((x, y), value)
    1.96 +            for f, value in distribution(rgb):
    1.97 +                if not c.has_key(value):
    1.98 +                    c[value] = f
    1.99 +                else:
   1.100 +                    c[value] += f
   1.101  
   1.102          c = [(n, value) for value, n in c.items()]
   1.103          c.sort(reverse=True)
   1.104          colours.append(c)
   1.105  
   1.106 -    if preview:
   1.107 -        im_preview.save(preview_filename)
   1.108 -
   1.109      for y, c in enumerate(colours):
   1.110          most = [value for n, value in c[:4]]
   1.111          least = [value for n, value in c[4:]]
   1.112  
   1.113 +        if least and best:
   1.114 +            most = get_best(im_original, width, y, c)
   1.115 +
   1.116          for x in range(0, width):
   1.117              rgb = im.getpixel((x, y))
   1.118  
   1.119 @@ -153,7 +170,9 @@
   1.120  
   1.121              value = get_value(rgb)
   1.122              if value in least:
   1.123 +                rgb = im_original.getpixel((x, y))
   1.124                  value = get_value(rgb, most)
   1.125 +
   1.126              im.putpixel((x, y), value)
   1.127  
   1.128      im.save(output_filename)