SHARE
TWEET

Untitled

a guest Feb 10th, 2015 507 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/usr/bin/env python3
  2.  
  3. from collections import namedtuple
  4. from math import sqrt
  5. import colorsys
  6. import random
  7. try:
  8.     import Image
  9. except ImportError:
  10.     from PIL import Image
  11. import sys
  12. import re
  13. import os.path
  14. import argparse
  15. import json
  16.  
  17.  
  18. Pr, Pg, Pb = .299, .587, .114
  19.  
  20. Point = namedtuple('Point', ('coords', 'n', 'ct'))
  21. Cluster = namedtuple('Cluster', ('points', 'center', 'n'))
  22.  
  23.  
  24. def get_points(img):
  25.     points = []
  26.     w, h = img.size
  27.     for count, color in img.getcolors(w * h):
  28.         points.append(Point(color, 3, count))
  29.     return points
  30.  
  31.  
  32. rtoh = lambda rgb: '#%s' % ''.join(('%02x' % p for p in rgb))
  33. rgb_to_hsp = lambda rgb: sqrt(
  34.     sum([rgb[0] ** 2 * Pr, rgb[1] ** 2 * Pg, rgb[2] ** 2 * Pb]))
  35.  
  36.  
  37. def colorize(filename, n=16):
  38.     img = Image.open(filename)
  39.     img.thumbnail((200, 200))
  40.     w, h = img.size
  41.  
  42.     points = get_points(img)
  43.     clusters = kmeans(points, n, 1)
  44.     rgbs = [list(map(int, c.center.coords)) for c in clusters]
  45.     return list(map(rtoh, sorted(rgbs, key=rgb_to_hsp)))
  46.  
  47.  
  48. def euclidean(p1, p2):
  49.     return sqrt(sum([
  50.         (p1.coords[i] - p2.coords[i]) ** 2 for i in range(p1.n)
  51.     ]))
  52.  
  53.  
  54. def calculate_center(points, n):
  55.     vals = [0.0 for i in range(n)]
  56.     plen = 0
  57.     for p in points:
  58.         plen += p.ct
  59.         for i in range(n):
  60.             vals[i] += (p.coords[i] * p.ct)
  61.     return Point([(v / plen) for v in vals], n, 1)
  62.  
  63.  
  64. def kmeans(points, k, min_diff):
  65.     clusters = [Cluster([p], p, p.n) for p in random.sample(points, k)]
  66.  
  67.     while True:
  68.         plists = [[] for i in range(k)]
  69.  
  70.         for p in points:
  71.             smallest_distance = float('Inf')
  72.             for i in range(k):
  73.                 distance = euclidean(p, clusters[i].center)
  74.                 if distance < smallest_distance:
  75.                     smallest_distance = distance
  76.                     idx = i
  77.             plists[idx].append(p)
  78.  
  79.         diff = 0
  80.         for i in range(k):
  81.             old = clusters[i]
  82.             center = calculate_center(plists[i], old.n)
  83.             new = Cluster(plists[i], center, old.n)
  84.             clusters[i] = new
  85.             diff = max(diff, euclidean(old.center, new.center))
  86.  
  87.         if diff < min_diff:
  88.             break
  89.  
  90.     return clusters
  91.  
  92.  
  93. def make_file(colors, patterns):
  94.     def _proccess_color_pattern(pattern, colors):
  95.         return ''.join(pattern.format(i, color) for i, color in enumerate(colors))
  96.  
  97.     def _add(pattern, colors):
  98.         return ''.join(to_add['pattern'].format(colors[to_add['pos']]) for to_add in pattern['add'])
  99.  
  100.     fake_patterns = list(
  101.         (dict(expression='', out='', add=[], pattern='Color{0}: {1}\n'),))
  102.  
  103.     try:
  104.         with open(patterns, 'r') as input:
  105.             try:
  106.                 patterns = json.loads(input.read())
  107.             except ValueError:
  108.                 sys.stdout.write('Cant parse JSON file')
  109.                 patterns = fake_patterns
  110.     except (FileNotFoundError, TypeError):
  111.         sys.stdout.write('JSON file not found')
  112.         patterns = fake_patterns
  113.  
  114.     for pattern in patterns:
  115.         result = (_proccess_color_pattern(
  116.             pattern['pattern'], colors) or '') + (_add(pattern, colors) or '')
  117.         out = os.path.expanduser(pattern['out'])
  118.         if out:
  119.             with open(out, 'r') as input:
  120.                 data = input.read()
  121.                 with open(out, 'w') as output:
  122.                     p = re.compile(pattern['expression'], re.S)
  123.                     if p.search(data):
  124.                         output.write(p.sub(r'\1{0}\2'.format(result), data))
  125.         else:
  126.             sys.stdout.write(result)
  127.  
  128.  
  129. def main():
  130.     parser = argparse.ArgumentParser(
  131.         description='Proccess dominant colors on input image and print it.')
  132.     parser.add_argument('-i', '--image', type=str, help='image')
  133.     parser.add_argument(
  134.         '-c', '--count', type=int, help='count of out colors', default=16)
  135.     parser.add_argument(
  136.         '-p', '--patterns', type=str, help='patterns of out colors', default=None)
  137.  
  138.     args = parser.parse_args()
  139.     colors = colorize(args.image, args.count)
  140.  
  141.     make_file(colors, args.patterns)
  142.  
  143. if __name__ == '__main__':
  144.     main()
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Top