PaletteOptimiser

Changeset

27:736979f99379
2015-10-02 Paul Boddie raw files shortlog changelog graph Experiment with combining more than two colours at once for an input colour.
optimiser.py (file)
     1.1 --- a/optimiser.py	Thu Oct 01 18:39:59 2015 +0200
     1.2 +++ b/optimiser.py	Fri Oct 02 13:37:29 2015 +0200
     1.3 @@ -1,6 +1,6 @@
     1.4  #!/usr/bin/env python
     1.5  
     1.6 -from random import randint
     1.7 +from random import random
     1.8  from os.path import extsep, splitext
     1.9  import EXIF
    1.10  import PIL.Image
    1.11 @@ -17,53 +17,30 @@
    1.12      r2, g2, b2 = rgb2
    1.13      return math.sqrt(pow(r1 - r2, 2) + pow(g1 - g2, 2) + pow(b1 - b2, 2))
    1.14  
    1.15 -def brightness(rgb):
    1.16 -    return distance(rgb, (0, 0, 0))
    1.17 -
    1.18 -def factor(start, end, rgb):
    1.19 -    r1, g1, b1 = start
    1.20 -    r2, g2, b2 = end
    1.21 -    gr, gg, gb = r2 - r1, g2 - g1, b2 - b1
    1.22 -    r, g, b = rgb
    1.23 -    pr, pg, pb = r - r1, g - g1, b - b1
    1.24 -    dp = pr * gr + pg * gg + pb * gb
    1.25 -    return dp / pow(distance(start, end), 2)
    1.26 -
    1.27 -def darklight(rgb1, rgb2):
    1.28 -    if brightness(rgb1) <= brightness(rgb2):
    1.29 -        return rgb1, rgb2
    1.30 -    else:
    1.31 -        return rgb2, rgb1
    1.32 -
    1.33 -def nearest(rgb, values=None):
    1.34 -    l = map(lambda c: (distance(rgb, c), c), values or corners)
    1.35 -    l.sort()
    1.36 -    return l
    1.37 +def distribution(rgb, points):
    1.38 +    l = []
    1.39 +    total = 0
    1.40 +    for c in points:
    1.41 +        d = distance(rgb, c)
    1.42 +        if d == 0:
    1.43 +            return [(1, c)]
    1.44 +        l.append((pow(d, -3), c))
    1.45 +        total += pow(d, -3)
    1.46 +    return [(d / total, c) for d, c in l]
    1.47  
    1.48  def pattern(rgb, values=None):
    1.49 -    l = nearest(rgb, values)
    1.50 -    start, end = l[0][1], l[1][1]
    1.51 -    f = factor(start, end, rgb)
    1.52 -    #if f > 0.5:
    1.53 -    #    start, end = end, start
    1.54 -    #    f = 1 - f
    1.55 -    return start, end, f
    1.56 +    l = distribution(rgb, values or corners)
    1.57 +    l.sort(reverse=True)
    1.58 +    return l
    1.59  
    1.60 -def choose(seq, f):
    1.61 -    last = int(seq * f)
    1.62 -    current = int((seq + 1) * f)
    1.63 -    return last != current
    1.64 -
    1.65 -def get_value(xy, rgb, width, height, values=None):
    1.66 -    x, y = xy
    1.67 -    rgb1, rgb2, f = pattern(rgb, values)
    1.68 -    if choose(x + randint(0, width), f) and choose(y + randint(0, height), f):
    1.69 -        return rgb2
    1.70 -    else:
    1.71 -        return rgb1
    1.72 -
    1.73 -def get_best(rgb, values):
    1.74 -    return nearest(rgb, values)[0][1]
    1.75 +def get_value(rgb, values=None):
    1.76 +    choose = random()
    1.77 +    threshold = 0
    1.78 +    for f, c in pattern(rgb, values):
    1.79 +        threshold += f
    1.80 +        if choose < threshold:
    1.81 +            return c
    1.82 +    return c
    1.83  
    1.84  def sign(x):
    1.85      return x >= 0 and 1 or -1
    1.86 @@ -80,7 +57,7 @@
    1.87          im = PIL.Image.new("RGB", (size, size))
    1.88          for g in range(0, size):
    1.89              for b in range(0, size):
    1.90 -                value = get_value((g, b), (r, (g * 256) / size, (b * 256 / size)), size, size)
    1.91 +                value = get_value((r, (g * 256) / size, (b * 256 / size)))
    1.92                  im.putpixel((g, b), value)
    1.93          im.save("rgb%d.png" % r)
    1.94  
    1.95 @@ -89,7 +66,7 @@
    1.96      im = PIL.Image.new("RGB", (size, size))
    1.97      for y in range(0, size):
    1.98          for x in range(0, size):
    1.99 -            im.putpixel((x, y), get_value((x, y), rgb, size, size))
   1.100 +            im.putpixel((x, y), get_value(rgb))
   1.101      im.save("rgb%02d%02d%02d.png" % rgb)
   1.102  
   1.103  def rotate_and_scale(im, width, height, rotate):
   1.104 @@ -125,7 +102,7 @@
   1.105      desaturate = sys.argv[3:].count("-d")
   1.106  
   1.107      x = EXIF.process_file(open(input_filename))
   1.108 -    im = PIL.Image.open(input_filename)
   1.109 +    im = PIL.Image.open(input_filename).convert("RGB")
   1.110      im = rotate_and_scale(im, width, height, rotate)
   1.111  
   1.112      if preview:
   1.113 @@ -148,7 +125,7 @@
   1.114  
   1.115              # Count the number of requested colours.
   1.116  
   1.117 -            value = get_value((x, y), rgb, width, height)
   1.118 +            value = get_value(rgb)
   1.119              if not c.has_key(value):
   1.120                  c[value] = 1
   1.121              else:
   1.122 @@ -174,9 +151,9 @@
   1.123              # Get the requested colours and choose the closest alternative for
   1.124              # less common colours.
   1.125  
   1.126 -            value = get_value((x, y), rgb, width, height)
   1.127 +            value = get_value(rgb)
   1.128              if value in least:
   1.129 -                value = get_value((x, y), rgb, width, height, most)
   1.130 +                value = get_value(rgb, most)
   1.131              im.putpixel((x, y), value)
   1.132  
   1.133      im.save(output_filename)