HSL Интерполяция

Если компонент оттенка моего цвета HSL указан в градусах, как я могу правильно интерполировать между двумя оттенками? Использование (h1 + h2) / 2 не дает желаемых результатов во всех случаях. Вот два примера, которые поясняют, почему:

Позволять:

красный = 0 °
желтый = 60 °
синий = 240 °

(красный + желтый) / 2 = 30 ° (оранжевый)
(желтый + синий) / 2 = 150 ° (сине-зеленый)
(красный + синий) / 2 = 120 ° (зеленый)

Как видите, усреднение красного и синего дает зеленый цвет вместо пурпурного / пурпурного! Однако, если мы позволим:

красный = 360 °
желтый = 60 °
синий = 240 °

(красный + желтый) / 2 = 210 ° (сине-зеленый)
(желтый + синий) / 2 = 150 ° (сине-зеленый)
(красный + синий) / 2 = 300 ° (пурпурный)

Теперь красный и синий дают ожидаемый цвет, а красный и желтый дают сине-зеленый цвет! Как я могу интерполировать компонент оттенка цвета, чтобы результат соответствовал тому, что можно было бы ожидать от смешивания фактической краски? Спасибо!


person Community    schedule 13.09.2009    source источник


Ответы (3)


Вы в основном делаете это правильно, чтобы получить то, что, как я полагаю, вы хотите, а именно цвет, который выглядит средним между вашими двумя входами, но вам просто нужно иметь дело с тем фактом, что этот расчет выполняется для круга, который оборачивается. (Я предполагаю, что вам на самом деле не нужно «смешивать, как краска», а нужен только средний цвет - то есть вы не хотите, чтобы красный и зеленый давали коричневый, верно?)

Вот функция Python, которая выбирает угол между двумя углами на окружности. По сути, он просто пробует два варианта (добавление 360 или нет) и выбирает тот, который дает угол, наиболее близкий к исходным углам:

pairs = [(0, 60), (60, 239), (60, 241), (0, 240), (350, 30)]

def circ_ave(a0, a1):
    r = (a0+a1)/2., ((a0+a1+360)/2.)%360 
    if min(abs(a1-r[0]), abs(a0-r[0])) < min(abs(a0-r[1]), abs(a1-r[1])):
        return r[0]
    else:
        return r[1]

for a0, a1 in pairs:
    print a0, a1, circ_ave(a0, a1)

производит:

0 60    30.0
60 239  149.5  # 60, 240 is ambiguous
60 241  330.5
0 240   300.0
350 30  10.0

(Я считаю, что должен быть более простой способ сделать этот расчет, но мне это не приходило в голову.)

person tom10    schedule 13.09.2009
comment
Это правильный ответ. Проблема в исходном вопросе заключается в том, что, когда исходные значения разнесены более чем на 180d, среднее значение фактически находится на неправильной стороне круга (или на 180d неверно). решение, реализованное здесь, состоит в том, чтобы попробовать как avg, так и avg + 180d и использовать тот, который ближе. - person RBarryYoung; 13.09.2009

Для каждого значения цвета x, x < 360 это может быть x или x+360. Затем у вас есть 4 пары значений цвета. Если вы найдете пару наименьших расстояний, используйте эту пару для интерполяции цвета. Это может дать вам нужный визуальный эффект.

Например,

красный = 0 ° или 360 °
желтый = 60 ° или 420 °
синий = 240 ° или 600 °

наименьшее расстояние между красным и желтым - 60 (красный 0, желтый 60), поэтому интерполяция должна быть 30.
наименьшее расстояние между желтым и синим составляет 180 (желтый 60, синий 240), поэтому интерполяция должна быть 150. < br> наименьшее расстояние между красным и синим 60 (красный 360 синий 240), поэтому интерполяция должна быть 300.

person leiz    schedule 13.09.2009

Вы, вероятно, не хотели этого слышать, но преобразовываете в RGB, интерполируете и конвертируете обратно.

edit: только что увидел, что "можно ожидать смешивания настоящей краски"

В этом случае вы, вероятно, захотите преобразовать в цветовое пространство CMY, а не в RGB. Взгляните на смешивание цветов в Википедии.

person Artelius    schedule 13.09.2009
comment
На самом деле HLS - это намного лучшая модель для такого рода вещей. - person RBarryYoung; 13.09.2009