Подтвердить что ты не робот

Сортировка списка триплетов 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.

4b9b3361

Ответ 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)