Автоматическое определение цвета - опыт команды «Яндекса»
Продуктовый дизайнер «Яндекса» Михаил Аникин в своем блоге на Medium описал новый алгоритм подбора цветов для промо-карточек приложений в Yandex Launcher.
Редакция публикует материал с разрешения автора.
Различные сервисы «Яндекса» работают с цветом для решения интерфейсных задач: выделение информационных блоков и объектных ответов, управление вниманием и создание визуальной иерархии.
Примеры использования алгоритмов подбора цветов в поиске и в «Яндекс. Музыке»
В зависимости от задач подбор цвета может требовать сложных вычислений. Но бывает, что получить необходимый результат гораздо проще.
У нас в Yandex Launcher есть промо-карточки приложений: рейтинг, описание и кнопка «Установить». Это контекстные рекомендации - они открываются поверх списка приложений или в папке на рабочем столе.
Первоначальная реализация
Цвет для фона карточки подбирался автоматически на основе иконки, кнопка была полупрозрачная белая. Алгоритм пытался определить основной цвет иконки, разбирая пиксели по цветовому тону. Такой подход не всегда давал красивый результат, у него были недостатки:
- неправильное определение цвета;
- «грязные» цвета из-за усреднения;
- тусклые кнопки, скучные карточки.
Примеры проблемных карточек
Чего на самом деле хотелось
Карточка должна была стать настоящим продолжением иконки, а цвета - сочными и яркими. Хотелось создать ощущение, что карточку бережно делали вручную, а не подсунули что-то небрежно сгенерированное автоматически.
Красивее хочется сделать всегда, но ресурсы не безграничны. Выделять команду на написание чудо-библиотеки по определению цветов не планировалось. Так что задача - минимальными силами улучшить алгоритм определения цветов, придумать, как покрасить карточку красиво, не изобретая при этом космический корабль.
В субботу я сдул пыль с редактора кода, расчехлил HTML5 и Canvas и стал придумывать. В понедельник пришел к команде с предложением.
Новый алгоритм определения цветов
Шаг 1. Берем иконку. Выкидываем белые, черные и прозрачные пиксели.
Исходная иконка? Квадрат из отфильтрованных пикселей Шаг 2. Уменьшаем полученное изображение до размера 2? 2 пикселя (с отключенным антиалиасингом). В результате получим четыре цвета иконки. Если исходная картинка однородная, они могут повторяться - ничего страшного.
Результат после второго шага. Исходная иконка? Цвета
У нас отключен антиалиасинг, чтобы цвета не смешивались, не становились «грязными».
На деле получается так: квадрат делится на четыре части, мы берем средний пиксель из верхнего ряда каждой четверти. В реализации все просто: нам даже не нужен реальный downsample изображения и вообще работа с графикой. Пиксели с нужной позицией берем из одномерного массива, получившегося после первого шага.
Шаг 3. Почти все готово. Осталось совсем чуть-чуть: достаем полученные цвета, переводим в HSL, сортируем по светлоте (L). Красим карточку.
Светлая схема:
- фон - самый светлый цвет;
- кнопка - ближайший к светлому;
- текст - самый темный.
Темная схема (если два и более цветов темные):
- фон - самый темный цвет;
- кнопка - ближайший к темному;
- текст - самый светлый.
Применяя цвета, проверяем контрастность: разница Lightness между фоном и кнопкой? 20; между фоном и текстом? 60. Если не соответствует, корректируем.
Получившиеся карточки. Исходная иконка? Цвета? Карточка
И еще немного карточек для примера:
Результат
У нас получились красочные карточки, из настоящих цветов иконки, без «грязных» примесей. За счет использования нескольких цветов карточка выглядит гораздо живее. Особенно приятно, что при однородном фоне иконки карточка становится ее прямым продолжением: граница между ними совсем не заметна.
И самое главное: через два дня после предложения нового алгоритма первая реализация уже была доступна в dev-сборке. Опробовали внутри команды, настроили пороги для фильтра на первом шаге, предусмотрели особые случаи:
- иконка из одного цвета - делаем фон чуть темнее, чтобы не сливалась;
- иконка с фоном - смотрим пиксели по краям; если все одинаковы, ставим такой же фон карточки.
Доработанный алгоритм вошел в ближайший релиз. Отдельное спасибо руководителю группы разработки Yandex Launcher Диме Овчарову - за интерес, желание и терпение. Напоследок - больше примеров.