Сортировка списка триплетов RGB в спектр
У меня есть список триггеров RGB, и я хотел бы строить их так, чтобы они образовывали нечто вроде спектра.
Я преобразовал их в HSV, которые, по-видимому, рекомендуют людям.
from PIL import Image, ImageDraw
import colorsys
def make_rainbow_rgb(colors, width, height):
"""colors is an array of RGB tuples, with values between 0 and 255"""
img = Image.new("RGBA", (width, height))
canvas = ImageDraw.Draw(img)
def hsl(x):
to_float = lambda x : x / 255.0
(r, g, b) = map(to_float, x)
h, s, l = colorsys.rgb_to_hsv(r,g,b)
h = h if 0 < h else 1 # 0 -> 1
return h, s, l
rainbow = sorted(colors, key=hsl)
dx = width / float(len(colors))
x = 0
y = height / 2.0
for rgb in rainbow:
canvas.line((x, y, x + dx, y), width=height, fill=rgb)
x += dx
img.show()
Однако результат не очень похож на приятный радужный спектр. Я подозреваю, что мне нужно либо конвертировать в другое цветовое пространство, либо обрабатывать триплет HSL по-разному.
![this doesn't look like a spectrum]()
Кто-нибудь знает, что мне нужно сделать, чтобы эти данные выглядели примерно как радуга?
Обновление:
Я играл с кривыми Гильберта и пересматривал эту проблему. Сортировка значений RGB (одинаковые цвета на обоих изображениях) по их положению по кривой Гильберта дает интересный (если все еще не совсем удовлетворительный) результат:
![RGB values sorted along a Hilbert curve.]()
Ответы
Ответ 1
Вы пытаетесь преобразовать трехмерное пространство в одномерное пространство. Нет никакой гарантии, что вы можете сделать из нее приятную радугу, как говорит Оли.
Что вы можете сделать, так это "ведро" цветов в несколько разных категорий, основанное на насыщенности и ценности/легкости, а затем сортировку по категориям, чтобы получить несколько независимых градиентов. Например, цвета с высокой насыщенностью сначала для классической радуги, затем насыщенные высокоценными цветами (пастель), затем с низкой насыщенностью (серые).
В качестве альтернативы, если все, о чем вы заботитесь, это радуга, конвертируйте в hsl, затем slam saturation до 1.0 и значение 0.5, конвертируйте обратно в rgb и визуализируйте это вместо исходного цвета.
Ответ 2
Предположительно, вы сортируете по оттенку (т.е. H)? Это даст хороший результат, если S и L (или V) являются постоянными, но если они меняются независимо, тогда вы получите немного беспорядка!
Ответ 3
Интересный метод уменьшения размерности цветовых пространств использует пробел кривая Гильберта. Две соответствующие статьи:
Оба они рассматривают уменьшение 3d → 2d, но промежуточный шаг отображения на 1d-кривую может быть решением вашей проблемы.
Ответ 4
Вот некоторые радуги, которые я сделал недавно, вы можете изменить идею делать то, что хотите
import Image, ImageDraw, sys
from scipy import ones
from matplotlib import pyplot as p
strip_h, strip_w = 100, 720
strip = 255*ones((strip_h,strip_w,3), dtype='uint8')
image_val = Image.fromarray(strip)
image_sat = Image.fromarray(strip)
draw0 = ImageDraw.Draw(image_val)
draw1 = ImageDraw.Draw(image_sat)
for y in xrange(strip_h):
sys.stderr.write('.')
for x in xrange(strip_w):
draw0.point([x, y], fill='hsl(%d,%d%%,%d%%)'%(x%360,y,50))
draw1.point([x, y], fill='hsl(%d,%d%%,%d%%)'%(x%360,100,y))
p.subplot(2,1,1)
p.imshow(image_val)
p.subplot(2,1,2)
p.imshow(image_sat)
p.show()
Ответ 5
Это кажется неправильным.
canvas.line((x, y, x + dx, y), width=height, fill=rgb)
Попробуйте это.
canvas.rectangle([(x, y), (x+dx, y+height)], fill=rgb)