Skip to content

Instantly share code, notes, and snippets.

@eviatarbach
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save eviatarbach/bca5fb04edc14893edab to your computer and use it in GitHub Desktop.
Save eviatarbach/bca5fb04edc14893edab to your computer and use it in GitHub Desktop.
Get matching colours from a list
#!/usr/bin/env python
# Copyright 2015 Eviatar Bach, eviatarbach@gmail.com
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import colorsys
import random
import copy
import itertools
STEP = 0.001
# See "Color Harmonization" by Cohen-Or et al.
TEMPLATES = {'T': [[0, 0.5]], 'V': [[0.87, 0.13]], 'i': [[0.9575, 0.025]],
'X': [[0.87, 0.13], [0.37, 0.63]],
'I': [[0.975, 0.025], [0.475, 0.525]],
'Y': [[0.87, 0.13], [0.475, 0.525]],
'L': [[0.0975, 0.025], [0.14, 0.36]],
'L2': [[0.0975, 0.025], [0.64, 0.86]]}
def in_interval(angle, interval):
if interval[1] >= interval[0]:
return interval[0] <= angle <= interval[1]
else:
return (angle >= interval[0]) or (angle <= interval[1])
def shift_intervals(intervals, offset):
'''
Return `intervals` rotated by angle `offset`
'''
intervals = copy.deepcopy(intervals)
for interval in intervals:
interval[0] = (interval[0] + offset) % 1
interval[1] = (interval[1] + offset) % 1
return intervals
def fit(colours, template, num):
'''
Try to find `num` colours in `colours` that fit in the template under some rotation
'''
hues = [colorsys.rgb_to_hsv(colour[0]/255., colour[1]/255., colour[2]/255.)[0]
for colour in colours]
intervals = TEMPLATES[template]
rots = list(range(0, int(1/STEP)))
random.shuffle(rots)
for i in rots:
shifted_intervals = shift_intervals(intervals, i*STEP)
colours_in_intervals = []
for index, hue in enumerate(hues):
if any(in_interval(hue, interval) for interval in shifted_intervals):
colours_in_intervals.append(colours[index])
if len(colours_in_intervals) >= num:
while len(colours_in_intervals) > num:
colours_in_intervals.pop(random.randint(0, len(colours_in_intervals) - 1))
return colours_in_intervals
raise ValueError("Could not find a fit")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment