Хабрахабр

[Перевод] Алгоритм генерирования цветовых палитр

Недавно установили дома RGB-подсветку, или хотите покрасить комнату в новые цвета? Ищете красивую цветовую палитру для сайта? В какой бы ситуации вы ни оказались, наверняка постоянно настраиваете цветовые схемы. Или купили клавиатуру с цветной подсветкой и хотите использовать её по полной?

Сразу почуяв, что такой подход может дать не лучшие результаты, я за пару минут реализовал кнопку «перезагрузки» палитры. Будучи программистом, я быстро написал несколько строк кода для генерирования случайных цветовых палитр. Мне представлялось, что для получения прекрасной схемы просто нужно немного удачи и терпения.

Генерирование палитр из случайных цветов — отстой. Я ошибался. Подборки цветов получаются всегда либо слишком тёмные, либо слишком светлые и малоконтрастные, либо наборы состоят из очень похожих цветов. Время от времени красивый цвет соседствует с уродливым, грязным оттенком коричневого или жёлтого. Нужно было придумать другое решение.

Цветовые пространства

Начнём с теории. Сегодня для классификации цветов широко используются такие цветовые пространства:

sRGB

RGB означает Red Green Blue. Так работают дисплеи: они излучают свет в трёх цветовых каналах, которые смешиваются в разной пропорции для получения всевозможных цветов. Значение в каждом канале варьируется от 0 до 255. R:0, G:0, B:0 (или #000000 в шестнадцатеричном выражении) — это чёрный цвет, а R:255, G:255, B:255 (или #ffffff) — белый.

CIE Lab

Цветовое пространство CIE Lab шире sRGB и включает в себя все цвета, воспринимаемые человеком. Оно создавалось с расчётом на универсальность восприятия. Иными словами, расстояние между цветами соответствует субъективной разнице: если значения двух цветов близки друг к другу, то и выглядят они похоже. С другой стороны, два далеко расположенных друг от друга цвета также воспринимаются как совсем непохожие. В CIE Lab для насыщенных цветов выделено больше места, чем для тёмных и светлых. К слову, для человеческого глаза очень тёмный зелёный почти неотличим от чёрного. Кроме того, это цветовое пространство трёхмерное: L означает светлоту (от 0.0 до 1.0), a и b (примерно от -1.0 до 1.0) — цветовые каналы.

HCL

Если RGB описывает, как дисплей отображает цвета, а CIE Lab — как мы их воспринимаем, то HCL — это цветовое пространство, которое ближе всего описывает то, как мы думаем о цветах. Оно тоже трёхмерное, H означает цветовой тон (hue) (от 0 до 360 градусов), С — насыщенность (chroma) и L — яркость (luminance) (оба параметра измеряются от 0,0 до 1,0).

При желании можно преобразовать значения из этих пространств в RGB. Для вычислений рекомендую использовать CIE Lab, а для представления палитр пользователю — HCL.

Разложение цветового пространства

Поскольку мне нужно было получить набор уникальных, индивидуальных цветов, сначала отбросим те, что выглядят очень похожими. Цветовое пространство будет трёхмерным, и для разделения таких низкоразмерных наборов данных прекрасно подходит алгоритм кластеризации методом k-средних. Он пытается разложить данные (в нашем случае — цветовое пространство) на k отдельных областей. И затем палитра собирается из центральных точек кластеров в этих областях. На гифке показано двумерное отображение работы алгоритма в трёхмерном пространстве CIE Lab.

Пишем код

С помощью реализованного на Go алгоритма метода k-средних задача решается всего в несколько строк кода. Сначала подготовим значения цветов в пространстве CIE Lab:

var d clusters.Observations
for l := 0.2; l <= 0.8; l += 0.05 ) } }
}

Я уже подобрал пару параметров и ввёл определённые ограничения для генерируемых цветов. В этом примере мы выкинем цвета слишком тёмные (яркость 0,8).

Разложим только что созданное цветовое пространство:

km := kmeans.New()
clusters, _ := km.Partition(d, 8)

Функция Partition возвратит кусочки восьми кластеров. У каждого кластера есть точка Center, представляющая собой отдельный цвет в заданном пространстве. Её координаты легко можно преобразовать в шестнадцатеричное RGB-значение:

col := colorful.Lab(c.Center[0], c.Center[1], c.Center[2])
col.Clamped().Hex()

Помните, что CIE Lab шире RGB, и значит некоторые Lab-значения нельзя преобразовать в RGB. Такие значения можно с помощью Clamped преобразовать в наиболее близкие цвета RGB-пространства.

Полный код

package main import ( "github.com/muesli/kmeans" "github.com/muesli/clusters" colorful "github.com/lucasb-eyer/go-colorful"
) func main() { // Create data points in the CIE L*a*b* color space // l for lightness, a & b for color channels var d clusters.Observations for l := 0.2; l <= 0.8; l += 0.05 { for a := -1.0; a <= 1.0; a += 0.1 { for b := -1.0; b <= 1.0; b += 0.1 { d = append(d, clusters.Coordinates{l, a, b}) } } } // Partition the color space into 8 clusters km := kmeans.New() clusters, _ := km.Partition(d, 8) for _, c := range clusters { col := colorful.Lab(c.Center[0], c.Center[1], c.Center[2]) fmt.Println("Color as Hex:", col.Clamped().Hex()) }
}

Набор из восьми (не очень) случайных цветов, сгенерированный этим кодом:

Определяем собственное цветовое пространство

Добавим больше контроля над генерированием цветов. Мы легко можем управлять данными, используемыми для дальнейших вычислений, тем самым подбирая цветовое пространство под свои нужды. Сгенерируем пастельную палитру:

func pastel(c colorful.Color) bool { _, s, v := col.Hsv() return 0.2 <= s && s <= 0.4 && 0.7 <= v && v <= 1.0
} for l := 0.0; l <= 1.0; l += 0.05 { for a := -1.0; a <= 1.0; a += 0.1 { for b := -1.0; b <= 1.0; b += 0.1 { col := colorful.Lab(l, a, b) if col.IsValid() && pastel(col) { d = append(d, clusters.Coordinates{l, a, b}) } } }
}

Ещё одно цветовое пространство — HSV, буквы в названии означают оттенок (hue), насыщенность (saturation) и яркость (value). В этом пространстве пастельные цвета обычно имеют высокие значения яркости и низкие значения насыщенности.

Вот что получилось:

Также вы можете фильтровать цвета по их насыщенности (chroma) и яркости, чтобы получить набор «тёплых» тонов:

func warm(col colorful.Color) bool { _, c, l := col.Hcl() return 0.1 <= c && c <= 0.4 && 0.2 <= l && l <= 0.5
}

Результат:

Пакет gamut

Я работаю над библиотекой под названием gamut, в которой соберу все описанные здесь кусочки в один удобный пакет на Go, позволяющий генерировать и управлять цветовыми палитрами и темами. Вы уже можете его попробовать, но он пока в работе.

Показать больше

Похожие публикации

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»