5.19. Тоновая коррекция

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

Коррекции делятся на два семейства: настройки яркости и контраста, которые перераспределяют яркость, и цветовые настройки, которые меняют то, каким цветом считывается каждый пиксель. Оба семейства имеют аналоги в ISP датчика, который корректирует каждый кадр на входе; методы, описанные здесь, применяются к уже захваченному Image постфактум – для случаев, когда кадру требуется больше коррекции, чем дал ISP.

5.19.1. Выравнивание гистограммы

Простейшая операция растяжения контраста – это выравнивание гистограммы. Идея состоит в том, чтобы переотобразить значения пикселей так, чтобы гистограмма выходного изображения была максимально плоской – каждое значение встречается примерно одинаково часто. Визуальный эффект заключается в том, что низкоконтрастное изображение (гистограмма которого сосредоточена в узкой полосе) становится высококонтрастным, пиксели которого покрывают весь диапазон от 0 до 255.

histeq() выполняет выравнивание:

img.histeq()

Механизм прямолинеен. Вычисляется кумулятивная функция распределения (CDF) гистограммы источника; каждое входное значение пикселя отображается на свою позицию в CDF, масштабированную к выходному диапазону. Там, где пиксели уже были распределены равномерно, отображение близко к тождественному; там, где пиксели были сгруппированы на одной яркости, отображение распределяет их, растягивая эту яркость на более широкий диапазон выходных значений.

Результат впечатляет на низкоконтрастных сценах – разница между тусклой фотографией в помещении и той же фотографией после histeq часто равна разнице между «нечитаемым» и «прекрасно различимым». Компромисс состоит в том, что операция усиливает всё, включая шум датчика. На сцене с реальными низкоконтрастными деталями, которые нужно восстановить, histeq – правильный выбор; на чистой, хорошо экспонированной сцене, которая в этом просто не нуждается, histeq вносит заметный шум.

5.19.2. CLAHE: адаптивное выравнивание

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

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

Флаг adaptive=True переключает histeq() в режим CLAHE:

img.histeq(adaptive=True, clip_limit=10)

Параметр clip_limit – это та часть CLAHE, на которую ссылается «ограничение контраста» в названии. Локальное выравнивание может чрезмерно усиливать шум в плоских областях, где CDF имеет очень мало различных значений; ограничение отсечения ограничивает то, насколько агрессивно может быть перераспределена любая отдельная корзина, что предотвращает усиление шума, но при этом позволяет растягивать контраст там, где это важно. Значение около 10 – разумная отправная точка; бо́льшие значения позволяют CLAHE работать активнее ценой более заметного шума, меньшие значения делают его мягче.

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

5.19.3. Гамма, контраст и яркость

Выравнивание гистограммы – это управляемый данными способ переотображения яркости. Не зависящий от данных способ – применить выбранную кривую, параметризованную несколькими легко настраиваемыми регуляторами. gamma() предоставляет три:

img.gamma(gamma=1.0, contrast=1.0, brightness=0.0)

Каждый параметр применяет к каждому пикселю одно конкретное преобразование:

gamma пропускает значение каждого пикселя через степенную функцию output = input ** (1 / gamma). Стандартное значение: значения больше 1.0 осветляют изображение и поднимают полутона (классическая коррекция «гаммы монитора»); значения меньше 1.0 затемняют его. Параметр нелинеен – он сохраняет точки чёрного и белого и изменяет только распределение между ними, что является правильным поведением, когда цель – восстановить детали в тенях или светах, не разрушая существующие крайние значения.

contrast пропускает каждый пиксель через прямое умножение вокруг точки среднего серого. Значения больше 1.0 повышают контраст (тёмное темнеет, яркое светлеет, среднее серое остаётся прежним); значения меньше 1.0 снижают контраст.

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

Эти три параметра комбинируются: один вызов gamma() может применить гамма-кривую, затем умножение контраста, затем сдвиг яркости – всё за один проход. Порядок таков: сначала гамма, затем контраст, затем яркость, что соответствует порядку, дающему наиболее интуитивно понятные результаты, когда все три значения отличаются от значений по умолчанию.

5.19.4. Автоматический баланс белого

Цветовое семейство тоновых коррекций начинается с автоматического баланса белого. Тот же механизм, который ISP датчика запускает в составе конвейера обработки изображений – регулировка относительных усилений по красному, зелёному и синему каналам так, чтобы усреднённый серый участок считывался как настоящий серый – также доступен как операция после захвата над готовым Image:

img.awb()

По умолчанию используется алгоритм gray-world: предполагается, что средний цвет всего изображения является нейтральным серым, и усиления по каналам подстраиваются для достижения этого. Альтернативная форма max=True использует алгоритм white-patch: предполагается, что самые яркие пиксели являются нейтральным белым, и усиления подстраиваются для достижения этого. Оба алгоритма работают с RGB565 и с необработанным Bayer; ни один не работает с оттенками серого (где нет цвета для балансировки) или YUV (где представление цвета не таково, с каким работают эти алгоритмы).

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

5.19.5. Матрица цветовой коррекции

Когда необходимая изображению цветовая коррекция – это не поканальное масштабирование, которое даёт баланс белого, а более общее смешивание каналов, нужная операция – это матрица цветовой коррекции. Метод ccm() применяет матрицу 3 на 3 (или 3 на 4 со смещением), которая умножает вектор (r, g, b) каждого пикселя, чтобы получить новый вектор (r, g, b):

img.ccm([[1.1, -0.05, -0.05],
        [-0.05, 1.1, -0.05],
        [-0.05, -0.05, 1.1]])

Матрица позволяет приложению корректировать перекрёстные помехи между цветовыми каналами – например, там, где отклик красного датчика включает часть зелёного света, матрица может вычесть долю зелёного канала из красного выхода для компенсации. В сочетании с поканальным смещением форма 3 на 4 также позволяет приложению заново обнулить каждый канал.

Материал о конвейере ISP раскрывает почему применяются матрицы цветовой коррекции. Форма после захвата над Image – это просто та же операция, применяемая постфактум.