Опубликован проект, предлагающий простой алгоритм и цветовое пространство для генерации разнообразных оттенков кожи — с готовым цветовым пикером на JavaScript и примером процедурного алгоритма на Python. Исходники обоих вариантов доступны в открытом доступе, так что математику можно взять и использовать в собственных задачах — от создателей персонажей до цифровой живописи.

Цель проекта — определить максимально широкий и инклюзивный диапазон цветов в пространстве RGB, соответствующий правдоподобным, хотя и упрощённым тонам кожи. Ключевая задача — найти простые, «достаточно хорошие» уравнения, описывающие эту область, чтобы диапазон можно было использовать в самых разных контекстах.

# Plug the output of one of the select_point implementations into to_rgb(t, u, v)

def select_point(r_square: float = 2.) -> tuple[float, float, float]:
    """Uniformly sample from the sphere deterministically"""
    radius = r_square ** (1. / 2)

    phi = uniform(0, 2 * math.pi)
    costheta = uniform(-1, 1)
    n = uniform(0, 1)

    theta = math.acos(costheta)
    r = radius * (n ** (1.0 / 3))

    t = r * math.sin(theta) * math.cos(phi)
    u = r * math.sin(theta) * math.sin(phi)
    v = r * math.cos(theta)

    return (t, u, v)

def select_point(r_square: float = 2.) -> tuple[float, float, float]:
    """Uniformly sample from the sphere using rejection sampling"""
    radius = r_square ** (1. / 2)
    R = radius + 1

    while R > radius:
        t = uniform(-radius, radius)
        u = uniform(-radius, radius)
        v = uniform(-radius, radius)

        R = (t**2 + u**2 + v**2) ** (1.0 / 2)

    return (t, u, v)

def to_rgb(t, u, v) -> tuple[int, int, int]:
    x = (t - 0.15) / 0.45
    y = (v - 1.2 * t ** 2 + 0.2 * t + 0.655) / 1.84
    z = u / 3.6

    r = 28.77438370854 * x + 36.78307445559 * y - 19.69766918644 * z + 187.1436241611
    g = 35.38327306318 * x - 2.009931981182 * y + 47.93462563172 * z + 137.1073825503
    b = 36.14733717939 * x - 43.54346996173 * y - 28.50821294135 * z + 108.2241610738

    return int(r), int(g), int(b)

Обзор

Какого цвета кожа человека? Короткий ответ — что-то вроде «коричневый», а длинный ответ очень, очень длинный. Цифровое представление широкого диапазона оттенков человеческой кожи — непростая задача. Часто ограниченный набор цветов подаётся как достаточный для покрытия всего спектра разнообразия. Но при использовании узкого набора цветов большие группы людей оказываются представлены неточно или вовсе исключены.

Цель работы — выявить максимально широкий инклюзивный диапазон цветов в пространстве RGB, соответствующий правдоподобным, но упрощённым тонам кожи. Уравнения намеренно названы «достаточно хорошими», чтобы подчеркнуть ограничения этой работы — результаты полезны как отправная точка, но не претендуют на авторитетность.

Введение

Несмотря на улучшения в наборах цветов, представляющих людей, разрыв всё ещё остаётся значительным. Эмодзи предлагают 5 оттенков (или мультяшно-жёлтый); бренд косметики может предложить 50; а редактор персонажей просто разведёт руками и предложит выбрать из всех 16 777 216 вариантов. Достаточно выглянуть в окно — или посмотреть на себя — чтобы понять: ни один из этих подходов не сравнится с реальным разнообразием; один человек — это не просто один цвет. Тем не менее сведение палитры к меньшему числу значений может быть полезным. Unicode Consortium и производители косметики вправе определять свои диапазоны, но существует решение где-то между «несколькими» и «несколькими миллионами».

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

бесформенный прямоугольник со спектром смешанных оттенков кожи
«Flesh Cloud» пользователя Tumblr shiroxix

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

пикер оттенков кожи с 18 вариантами и дополнительной кнопкой для открытия обычного цветового пикера
Скриншот редактора персонажей из игры раннего доступа Paralives

Ограничения

У этой работы есть ряд неотъемлемых ограничений.

Как уже упоминалось, тон кожи — это гораздо более сложная величина, чем один цвет. Он сильно варьируется между разными участками тела и подвержен сложным биологическим процессам. Воспринимаемый цвет кожи зависит от кровотока, концентрации меланина, сложного рассеяния света в слоях кожи, а также таких факторов, как витилиго, веснушки, гиперпигментация, рубцы и другие распространённые вариации.

Кроме того, ряд заболеваний может приводить к оттенкам кожи, выходящим далеко за пределы того, что можно счесть правдоподобным. Аргирия часто придаёт коже сине-серый оттенок; повышенный билирубин может вызывать желтоватость или зеленоватость кожи.

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

Наконец, цвета воспринимаются непоследовательно на разных типах дисплеев и в разных условиях просмотра. Значения RGB выглядят по-разному на разных экранах, а люди выглядят совершенно иначе при разном освещении.

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

Методология

Что означают все эти числа и как они были получены?

Предупреждение о содержании — далее описана ненаучная методология. Другими словами: «достаточно хорошо» вполне устраивает инженера.

Краткое изложение метода:

  1. Вручную разметить цвета в RGB, чтобы получить приблизительную форму набора данных
  2. Провести анализ главных компонент (PCA) с N=3 на наборе данных, чтобы преобразовать форму во что-то более удобное для работы
  3. С помощью удобного графического инструмента вручную подобрать уравнения, отображающие сферу в целевом пространстве на преобразованные данные в пространстве PCA

Ручная разметка цветов

веб-страница с наборами разноцветных лиц слева и справа — слева лица с цветами, похожими на тона кожи, справа — фиолетовые, синие и зелёные
Интерфейс для разметки данных

Иногда лучше всего начать с большого объёма монотонной работы. Не каждый цвет в RGB был размечен, но их было немало. Для разметки был создан простой веб-интерфейс: кликом лицо перемещалось между сторонами «да» и «нет». Изначально это были просто квадраты, но в итоге появилось нарисованное лицо, на которое накладывались цвета — глядя в глаза своему неуклюжему исследовательскому помощнику, было гораздо проще быстро решить «да, вполне могу представить такого человека на улице».

При построении графика по этим данным получилась следующая форма — визуально похожая на банан, изгибающийся между точками 0,0,0 и 255,255,255. Кривая смещена в сторону красного и в сторону от синего.

3D-график точек — цвета варьируются от тёмных в нижнем левом углу до светлых в верхнем правом
График размеченных данных в matplotlib

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

В итоге стало ясно, что форму нужно преобразовать во что-то более удобное для работы — именно тогда пришло знакомство с методом главных компонент, который сразу вдохновил на продолжение.

Гуманитарная интермедия

Хотя вся математика и технологии здесь интересны, важно признать, что технологии существуют в социальном контексте. Прямо говоря: светлые оттенки кожи — как сейчас, так и исторически — воспевались и получали приоритет, тогда как тёмные оттенки маргинализировались и порочились. Расизм и колоризм систематически присутствуют во многих культурах — как явно, так и в скрытых формах.

Ниже перечислены видео, эссе и проекты, освещающие эти вопросы с разных сторон.

«Важно, чтобы косметические бренды выпускали продукты для всех оттенков, и как человек с более тёмным тоном кожи, я хочу помогать другим, кто сталкивается с той же проблемой!» — Nyma Tang, автор видеосерии The Darkest Shade, в которой рассматриваются самые тёмные оттенки от разных косметических брендов.

В похожем ключе видео Kat Blaque Youthforia's Blackface Foundation рассказывает о косметическом бренде, выпустившем тёмный оттенок, буквально чёрного цвета — намного темнее, чем могло бы быть правдоподобно полезным.

Статья Beauty Brawl Джейсона Ли систематически измеряет инклюзивность разных косметических брендов с помощью впечатляющих визуализаций данных. А этот ноутбук Макса Бо развивает анализ дальше, причём один из графиков даёт похожую форму полумесяца, что и размеченные данные в этом проекте.

Видео Vox How beauty brands failed women of color рассказывает об истории дискриминации в косметической индустрии и ограниченной доступности тёмных оттенков, с рядом интервью экспертов и обсуждением связи с историей чернокожего населения США.

Если говорить о видеоиграх, эссе Остина Уокера Me, On The Screen: Race in Animal Crossing: New Leaf рассказывает о личной борьбе за то, чтобы увидеть себя представленным в видеоиграх. За прошедшие годы Animal Crossing стала намного инклюзивнее, но эссе также затрагивает историю невидимости — или персонажей, застрявших в расистских штампах.

Фотопроект Humanae Анжелики Дасс — это «непривычно прямое отражение цвета кожи, попытка задокументировать истинные цвета человечества, а не ложные ярлыки «белый», «красный», «чёрный» и «жёлтый», связанные с расой». В некотором смысле это очень похоже на текущий проект — только с фокусом на документирование и диалог, а не описание, и с использованием оттенков Pantone вместо hex-кодов.

Видео Ти Ноир It's not a Coincidence. It's Colorism. объясняет, что такое колоризм, и приводит примеры его проявления в современной поп-культуре.

Наконец, Writing With Color — отличный блог с множеством материалов о том, как писать о разнообразии. Его ведёт команда с экспертизой в разных областях, регулярно отвечающая на вопросы читателей. Особенно интересен пост Words for Skin Tone | How to Describe Skin Color.

Анализ главных компонент

Кратко: анализ главных компонент (PCA) — это способ повернуть и растянуть набор данных так, чтобы главные направления изменчивости легли вдоль осей координатной системы. Возвращаясь к форме «банана» из размеченного набора данных: в исходном виде «банан» как бы парил в пространстве. PCA расположил эту форму на «полу» так, что она стала симметричной относительно осей и хорошо выровненной. Также произошло небольшое растяжение и масштабирование, но это менее важно.

График до и после применения преобразования PCA
два 3D-графика со стрелкой PCA слева направо — слева кривая от начала координат в верхний правый угол, справа похожая кривая, но выровненная по осям

Помимо преобразованного набора данных, ещё одним результатом анализа является матрица, позволяющая взять точку из пространства RGB и перевести её в «лежащее на полу» пространство — назовём его пространством PCA. Для него используются переменные X, Y и Z, но путать это пространство с CIE XYZ не стоит.

Ручная подгонка функции

Итог предыдущих шагов: начали с данных в пространстве RGB (вручную размеченный набор), PCA дал способ преобразовать точки этого пространства в пространство PCA.

Набор данных в пространстве PCA, построенный в Desmos
3D-график облака точек

Теперь цель — подогнать функцию под все эти точки. Поскольку форма плотная, если определить её поверхность уравнением, можно модифицировать это уравнение, включив внутренние точки, превратив равенство в неравенство (например, из x² + y² + z² = 2 в x² + y² + z² ≤ 2).

Процесс подгонки функции выглядел так:

  1. Начать с функции сферы: R² = t² + u² + v² (см. раздел «Настройка R²» — почему выбрана именно сфера)
  2. Определить t, u и v через x, y и z
  3. Изменять определения t, u и v до тех пор, пока сфера не совпадёт с ожидаемыми данными
  4. Инвертировать зависимости, чтобы выразить x, y и z через t, u и v
Как выглядит график при t = x, u = y и v = z
3D-график облака точек со сферой, пересекающейся с серединой

Начав с (t = x, u = y, v = z), можно постепенно менять эти зависимости, вырабатывая интуицию о том, как изменения уравнений сдвигают сферу.

Именно так и было сделано — причём многократно. Проще говоря: функции подгонялись вручную под целевое облако точек. Никакой регрессии — буквально метод проб и ошибок с визуальной проверкой результата. Всё это делалось в Desmos 3D — удивительно, насколько хорошо этот инструмент подходит для такой задачи, если давно не пользовались Desmos.

Как в итоге выглядело «рабочее пространство» в Desmos
экран графического калькулятора — слева набор уравнений, справа 3D-фигура, совпадающая с облаком точек

Функции, связывающие (t, u, v) с (x, y, z), позволяют переводить точку между этими пространствами. Анализ главных компонент дал способ перехода между RGB и пространством PCA, а новые уравнения — способ перехода между пространством PCA и TUV. Связав все преобразования вместе, получаем функции перехода между TUV и RGB.

Поддерживает ли автор эту методологию как таковую? Нет. Но и отчасти да. В данной конкретной ситуации именно этот подход помог довести дело до конца и получить работающие уравнения. Было бы отлично увидеть, как кто-то сделает это правильно, с чистой символьной регрессией и качественными обучающими данными. Но поскольку размеченные вручную данные были в лучшем случае среднего качества, метод проб и ошибок с визуальной проверкой оказался практичнее.

При всём этом общий подход — «Разметка данных» → «PCA» → «Подгонка сферического уравнения» — вполне можно рекомендовать, даже если конкретная реализация не идеальна.

Результаты

От полученных уравнений до примера кода в начале статьи — всего один шаг перевода. Следующий раздел описывает компоненты интерфейса пикера, а также объясняет, что представляет собой пространство TUV и какими свойствами оно обладает.

Интерфейс пикера

интерфейс цветового пикера с обозначенными частями, управляющими T, U и V
К сожалению, это изображение не интерактивно

Как в обычном цветовом пикере можно регулировать значения красного, зелёного и синего (или оттенок, насыщенность и яркость), в этом пикере есть три независимых значения — в примерах кода они обозначены как T, U и V.

Компонент Аспект Имя переменной
Вверх/вниз по квадрату Тёмный/светлый T
Влево/вправо по квадрату Румяный/охристый U
Влево/вправо по слайдеру Холодный/тёплый V

Особенно интересно, что понятия, регулируемые каждым элементом управления, — это чистый результат анализа главных компонент. То есть было неизвестно, что именно будут контролировать эти направления, пока пикер не был готов. Это отличная демонстрация того, что делает PCA: разворачивает данные так, чтобы каждая ось имела максимальную содержательность.

Тем, кто знаком с цветовыми пространствами, это может напомнить HSL/HSV. Однако при первых экспериментах с размеченными данными эти цветовые пространства не вполне отражали нужную структуру. T и U кажутся похожими на Value и Hue, но не совпадают с ними полностью. Наибольшее отличие — между V и Saturation: V меняется от синего к оранжевому, тогда как Saturation больше похожа на переход от серого к оранжевому; хотя при некоторых значениях (T, U) V может напоминать Saturation, в целом корреляция не строгая.

Настройка R²

Что такое R²? Это радиус сферы в цветовом пространстве оттенков кожи. Поскольку один из шагов перевода из RGB в TUV связан со сферой, сферы становятся естественной формой для работы в пространстве TUV. Многие интересные свойства, о которых пойдёт речь, — просто следствие полезных свойств сфер вообще.

Для наглядности ниже приведена таблица значений R² и результатов использования сферы с этим значением:

Описание Пример
0.1Почти без вариаций
0.5Незначительные вариации
1.0Минимальное значение для приличного разнообразия при случайном выборе
1.5Хорошее разнообразие при сохранении реалистичности
2.0Потенциально мультяшно — при случайном выборе иногда появляются выбросы
2.5Случайный выбор в этом диапазоне может давать неожиданные значения, но полезно для интерфейса пикера
10Возможно, подойдёт для фэнтезийного сеттинга

Что происходит в этой таблице? Поскольку сфера определяется радиусом, можно задавать полезные диапазоны выборки одним-единственным значением, а затем легко выбирать точки внутри сферы. Например, в образце реализации функции генерации тона используется радиус 2 — именно этот радиус применялся при разработке цветового пространства и обычно даёт широкий диапазон тонов. Если сгенерированные результаты выглядят неправдоподобно при этом радиусе, его можно немного уменьшить, чтобы сократить вариативность генерируемых цветов.

Поскольку сфера сжимается по радиусу равномерно, уменьшение вариативности не приводит к значительному снижению представительности. Иными словами, уменьшение радиуса не просто «отсекает» тёмные или светлые тона кожи — тёмные, светлые, румяные, охристые, холодные и тёплые тона кожи равномерно уменьшаются в разнообразии.

Уменьшив R² до 0, можно определить точку начала координат цветового пространства. Если пространство построено корректно, эта точка должна оказаться очень нейтральным, неопределённым тоном. Если начало координат смещено в определённую сторону, это указывает на необходимость дополнительной калибровки пространства. По сути, точка начала координат может служить индикатором смещения в отображении пространства.

С другой стороны, R² можно увеличить, чтобы допустить больше вариативности — например, именно так сделано в интерфейсе цветового пикера. В пикере пользователь может просто игнорировать неправдоподобные цвета, поэтому увеличение вариативности не создаёт больших проблем. В контексте генерации цветов, напротив, желательно избегать появления неправдоподобных оттенков. Единого идеального значения R², подходящего для всех контекстов, вероятно, не существует, но наличие одного параметра для настройки позволяет легко подстроить уравнения под конкретную задачу.

Итог

В результате получено цветовое пространство, пикер для него, алгоритм процедурной генерации и методология для создания новых пространств или модификации существующего. Результат вызывает удовлетворение — он далеко не идеален, но полностью корректного и при этом простого решения, вероятно, не существует. Пикер уже использовался в цифровой живописи и полностью оправдал ожидания, а генератор планируется применять в следующих проектах.

Что дальше?

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

Для связи предлагается использовать страницу issues репозитория проекта — как наиболее безопасный вариант вместо публикации личного email.

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

Планы на будущее

Улучшение пространства

При таком точном определении цветового пространства и использовании конкретных значений R² есть риск, что некоторые цвета оказались исключены или маргинализированы. Однако та же конкретность позволяет и максимально точную критику цветового пространства, а значит — максимально точные улучшения. Как уже говорилось, процесс во многом строился на субъективной визуальной оценке — хорошей итерацией было бы привлечение нескольких людей, возможно экспертов, для разметки данных и более точного измерения результата относительно этой разметки.

Вариации и состояния кожи

Одно из упомянутых направлений — моделирование упрощённых версий различных состояний кожи. Какие модификации можно применить к базовым тонам, чтобы смоделировать желтуху, аргирию или бледность? Какого цвета веснушки, витилиго, рубцы, гиперпигментация или растяжки относительно базового тона человека?

Технические улучшения

С технической стороны формализация процесса генерации уравнений — ещё одно потенциальное направление. Отталкиваясь от формы уравнений, подобранных вручную, символьная регрессия на более качественных обучающих данных могла бы дать ещё более удачное определение цветового пространства.

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

Также было бы интересно посмотреть, что получится, если преобразовать данные в другое цветовое пространство перед проведением анализа главных компонент и подгонкой уравнений — есть шанс, что уравнения окажутся проще или более представительными. Благодаря сфере форма поверхности в построенном цветовом пространстве сохранится и будет в основном масштабироваться со значением R². Иллюстрацию этой идеи можно увидеть в скрипте graph в репозитории проекта.

Благодарности

  • Друзьям — за то, что слушали рассуждения и предлагали отличные идеи
  • Этому видео — за помощь в преодолении затора, благодаря объяснению анализа главных компонент
  • Всем авторам, упомянутым в разделе «Гуманитарная интермедия» — за то, что поделились своими работами и мыслями
  • Инструментам:
    • matplotlib — библиотека для построения графиков на Python
    • scikit-learn — ML-библиотека с реализацией анализа главных компонент
    • Desmos — бесплатный онлайн графический калькулятор
    • SymPy — библиотека символьной математики
  • Читателям — за внимание к проекту!