Очень простой алгоритм подбора цвета, который работает

Михаил Аникин рассказал в статье на Medium как он и его коллеги подбирают цвета для выделения информационных блоков, объектных ответов; для управления вниманием и создания визуальной иерархии.


Различные сервисы Яндекса работают с цветом для решения интерфейсных задач: выделения информационных блоков, объектных ответов; для управления вниманием и создания визуальной иерархии.

1*TutswM3U-CjM875DdCYi3AПримеры использования алгоритмов подбора цветов в Яндекс.Музыке и в поиске

В зависимости от задач подбор цвета может требовать сложных вычислений. Но бывает, что получить необходимый результат гораздо проще. Об этом история.

У нас в Yandex Launcher есть промо-карточки приложений: рейтинг, описание и кнопка «Установить». Это контекстные рекомендации— открываются поверх списка приложений или в папке на рабочем столе.

Первоначальная реализация

Цвет для фона карточки подбирался автоматически на основе иконки, кнопка — полупрозрачная белая. Алгоритм пытался определить основной цвет иконки, разбирая пиксели по hue. Такой подход не всегда давал красивый результат, обладал недостатками:
● неправильное определение цвета,
● «грязные» цвета из-за усреднения,
● тусклые кнопки, скучные карточки.

1*FDzUinQlCm-UH7RWYSTrxwПримеры проблемных карточек

Чего на самом деле хотелось

Карточка должна была стать настоящим продолжением иконки. Цвета — сочными и яркими. Хотелось создать ощущение, что карточку бережно делали вручную, а не подсунули что-то небрежно сгенерированное автоматически.

Красивее хочется сделать всегда, но ресурсы не безграничны. Выделять команду на написание чудо-библиотеки по определению цветов не планировалось. Так что, задача:

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

В субботу я сдул пыль с редактора кода, расчехлил HTML5 и Canvas и стал придумывать. В понедельник пришёл к команде с предложением.

Новый алгоритм определения цветов

Шаг 1.

Берём иконку. Выкидываем белые, чёрные и прозрачные пиксели.

1*0b7KV6aRs6YoYp4BUV24cAИсходная иконка → Квадрат из отфильтрованных пикселей

Шаг 2.

Уменьшаем полученное изображение до размера 2 × 2 пикселя (с отключенным антиалиасингом). В результате получим четыре цвета иконки. В случае однородной исходной картинки они могут повторяться, ничего страшного.

1*3CInb-gq53DVk9qJQCORKQРезультат после второго шага. Исходная иконка → Цвета

У нас отключен антиалиасинг, чтобы цвета не смешивались, не становились «грязными».

1*jrNK0ANkqRZ29MWg1Vc0oQНа деле получается так:
квадрат делится на четыре части; мы берём средний пиксель из верхнего ряда каждой четверти.

В реализации всё просто: нам даже не нужен реальный даунсепмл изображения и вообще работа с графикой.

Пиксели с нужной позицией берём из одномерного массива, получившегося после первого шага.

Шаг 3.

Почти всё готово. Осталось совсем чуть-чуть: достаем полученные цвета, переводим в HSL, сортируем по светлоте (L). Красим карточку.

Светлая схема:
● фон — самый светлый цвет,
● кнопка — ближайший к светлому,
● текст — самый тёмный.

Тёмная схема (если 2 и более цветов тёмные):
● фон — самый тёмный цвет,
● кнопка — ближайший к тёмному,
● текст — самый светлый.

Применяя цвета, проверяем контрастность: разница Lightness между фоном и кнопкой ≥ 20; между фоном и текстом ≥ 60. Если не соответствует, корректируем.

1*Jlua-yA75IUNkQiF2gN3hA

И ещё немного карточек для примера:

1*tAEclGQSfbs489hNa0V6NQ

Результат

У нас получились красочные карточки, из настоящих цветов иконки, без «грязных» примесей. За счет использования нескольких цветов карточка выглядит гораздо живее. Особенно приятно, что при однородном фоне иконки, карточка становится её прямым продолжением: граница между ними совсем не заметна.

И самое главное:
Через 2 дня после предложения нового алгоритма первая реализация уже была доступна в dev-сборке. Опробовали внутри команды, настроили пороги для фильтра на первом шаге, предусмотрели особые случаи:
● иконка из одного цвета — делаем фон чуть темнее, чтобы не сливалась,
● иконка с фоном—смотрим пиксели по краям, если все одинаковы, ставим такой же фон карточки.

Доработанный алгоритм вошёл в ближайший релиз.

Отдельное спасибо Диме Овчарову, руководителю группы разработки Yandex Launcher, — за интерес, желание и терпение.

Напоследок, больше примеров

1*XPdA_3J9QpkrRg5FZ3nZDg

1*VWXG7u7JFAE4MlpbPRJHWw

1*eDzTvTnbeSwS7QKs4N7ybA

Источник: medium