Бандинг видео: почему градиент идёт ступенями

Автор: Николай СапуновОбновлено: август 202616 мин чтения
Содержание статьи +

TL;DR

Бандинг, он же ложное контурирование (false contouring), – это лестница плоских полос там, где картинка должна держать плавный градиент: чистое небо, студийный задник, медленное затемнение. У него две складывающиеся причины: слишком мало уровней яркости, чтобы нарисовать градиент (низкая битовая глубина), и кодек, округляющий прочь крошечные вариации, которые этот градиент несли (квантование). Это артефакт, который популярные полнореференсные метрики ловят хуже всего: попиксельная ошибка видимой полосы может быть одно кодовое значение, поэтому PSNR показывает 48 дБ, а VMAF – 95, пока полосы видны глазу, который усиливает прямой низкоконтрастный край, а математика считает его пренебрежимым. Правильные инструменты – безреференсные детекторы бандинга на модели человеческого зрения: CAMBI от Netflix (теперь внутри VMAF) и индекс BBAND; а средства – бо́льшая битовая глубина (кодируйте даже 8-битный SDR в 10 бит), дизеринг (калиброванный шум, разбивающий ступени) и специальные дебандинг-фильтры. Измеряйте бандинг на плоских областях, детектором, созданным под него, и никогда не закрывайте кодирование одной слитной оценкой.

Почему это важно

Если вы кодируете или принимаете по QC видео с небом, закатами, тёмными сценами, анимацией или любым медленным градиентом, бандинг – тот артефакт, что переживает зелёный дашборд качества и всё равно собирает жалобу. Это хрестоматийный пример слепого пятна метрики: чистый VMAF может сидеть ровно поверх видимых контуров, поэтому довериться числу вместо собственных глаз – значит отгрузить баг. Статья написана для видеоинженера, ведущего по кодированию или QA-инженера, который видит полосы, но хочет понять, почему именно они образуются, почему привычные метрики их пропускают, какой детектор добавить и за какое из трёх стандартных средств взяться. Сделайте это правильно – и вы перестанете спорить с дашбордом, который уверенно ошибается.

Что такое бандинг на самом деле

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

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

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

Откуда берётся бандинг: битовая глубина и квантование

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

Первая причина – битовая глубина, то есть сколько различимых уровней яркости формат хранит на цветовой канал. Стандартное 8-битное видео имеет 2⁸ = 256 уровней на канал; 10-битное – 1024, вчетверо больше; 12-битное – 4096. Уровень – это наименьшая ступень яркости, которую формат способен представить, и она же – наименьшая ступень, которую глаз может поймать на плоском поле. Когда градиент охватывает лишь несколько уровней, картинке ничего не остаётся, кроме как нарисовать его несколькими плоскими полосами.

Арифметику стоит проделать один раз, потому что она указывает прямо на лечение. Допустим, небо плавно идёт от кодового значения 90 к 110 – всего 20 различимых уровней – на 400 пикселях высоты. Это 400 ÷ 20 = 20 пикселей одинаковой яркости, прежде чем значению позволено измениться, поэтому вы видите плоские полосы шириной 20 пикселей с видимой ступенью между каждой. Закодируйте тот же градиент в 10 бит, и тот же диапазон яркости теперь охватывает около 80 кодовых значений; полосы сжимаются примерно до 400 ÷ 80 = 5 пикселей, и ступени падают ниже порога, на котором глаз их выхватывает. Вчетверо больше уровней – вчетверо у́же полоса. Механика битовой глубины со стороны причины живёт в разделе Video Encoding про битовую глубину; здесь мы остаёмся на распознавании и измерении результата.

Вторая причина – квантование, бит-экономящий шаг внутри каждого кодека с потерями и тот же механизм, что порождает блочность. Кодер переписывает каждый блок как сумму волновых паттернов (дискретное косинусное преобразование, DCT), затем делит силу каждой волны на шаг и округляет, удаляя мелкие. В гладкой области градиент несут целиком слабые низкоамплитудные волны и дизер-подобная текстура естественного зерна плёнки. Квантование округляет именно их, сваливая плавно меняющийся участок к одному плоскому значению, – и граница, где один плоский участок встречает следующий, и есть контур. Поэтому даже 8-битный контент, выглядевший гладким на источнике, может приобрести бандинг при кодировании, потому что кодек выбросил тонкую вариацию, державшую градиент вместе. Деталь со стороны причины – как задаётся шаг квантователя – принадлежит статье Video Encoding про квантование.

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

Рисунок 1. Как образуется бандинг. У плавного градиента (слева) слишком мало кодовых значений, чтобы его нарисовать, поэтому квантование защёлкивает его в плоские полосы (в центре); каждая ступень – ложный контур (справа). Больше битовой глубины – больше и тоньше ступени, полосы слишком малы, чтобы их увидеть.

Почему глаз видит ступень, которую метрика называет крошечной

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

Глаз измеряет не абсолютную яркость, а изменение. На любом крае, где яркость ступенчато растёт, человеческое зрение усиливает ступень – затемняя тёмную сторону и осветляя светлую, – эффект, названный полосами Маха в честь физика Эрнста Маха, описавшего его в 1860-х. На плоском поле, где ничто не отвлекает, край в одно кодовое значение, идущий прямо через градиент, усиливается этим механизмом в линию, которую невозможно не увидеть. Та же ступень, спрятанная в текстуре, замаскировалась бы полностью. Бандинг – идеальный шторм: низкоамплитудный край, идеально прямой, сидящий на единственном типе области – гладкой и однородной, – где глаз к нему чувствительнее всего.

Теперь проделаем измерительную арифметику и посмотрим, как метрика его пропускает. Возьмём 8-битную картинку, пиковое значение 255, где бандинговое небо отличается от истинного плавного градиента в среднем примерно на одно кодовое значение на пиксель. Тогда среднеквадратичная ошибка около 1, а пиковое отношение сигнал/шум – метрика «сырой» пиксельной ошибки, в децибелах – это:

PSNR = 10 · log10(255² / MSE)
     = 10 · log10(65025 / 1)
     = 10 · log10(65025)
     = 48,1 дБ

PSNR в 48 дБ читается как почти идеальное кодирование по любому эмпирическому правилу. Уполовиньте ошибку до половины кодового значения – и она перевалит за 51 дБ. А полосы при этом ясно видны. Число не врёт про пиксели – ошибка действительно крошечная, – оно врёт про восприятие, потому что у него нет модели глаза, усиливающего прямой низкоконтрастный край. Это полная противоположность блочности, которую метрики хотя бы детектируют; бандинг они едва регистрируют. Полный каталог этих провалов – Где врут объективные метрики.

Три средства: битовая глубина, дизеринг, дебандинг

Поскольку у бандинга две причины, у него небольшая семья средств, и они чисто ложатся на причины.

Бо́льшая битовая глубина бьёт в корень. Дайте градиенту больше уровней – и полосы у́же до тех пор, пока не упадут ниже порога глаза; переход 8 → 10 бит вчетверо у́же полосу, как показала арифметика выше. Контринтуитивно то, что это помогает даже для обычного 8-битного SDR-контента: кодирование 8-битного источника в 10 бит гоняет внутреннюю математику кодека на большей точности, поэтому округление, создающее контуры, происходит на более тонкой сетке. Netflix кодирует свои SDR-потоки AV1 в 10 бит ровно по этой причине, сообщая и о снижении бандинга, и о чуть меньших файлах при равном качестве. Компромиссы 8 против 10 бит разобраны в статье Video Encoding про 8 и 10 бит.

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

Дебандинг-фильтры бьют по уже полученному кодированию. Дебандер находит плоские области, сглаживает в них контуры и добавляет немного зерна, чтобы сглаживание само не выглядело пластиковым. В FFmpeg два практичных фильтра – gradfun, интерполирующий поперёк градиента и дизерящий (его strength по умолчанию 1.2, radius – 16), и deband, нацеленный на более выраженные контуры. Оба – препроцессинг или постпроцессинг, а не настройки кодека.

Одна оговорка экономит много впустую потраченных усилий: не дизерьте и не дебандьте прямо перед кодированием с потерями, ожидая, что это переживёт сжатие. Сжатие трактует дизер как шум и тут же его выквантовывает, и полосы возвращаются. Добавляйте зерно или дизер как можно ближе к финальному отдаваемому битстриму – или поднимите битовую глубину, чтобы градиент вообще не полосился. Потеря детали, которую может внести агрессивный дебандинг, – тема статьи Размытие и потеря детали.

Рисунок 2. Три средства. Бо́льшая битовая глубина (8→10→12 бит) даёт больше уровней и тоньше ступени; дизеринг рассеивает пиксели между уровнями, и глаз сводит их гладко; дебандинг-фильтр чинит готовое кодирование. Осторожно: дизер, добавленный перед кодированием с потерями, выквантовывается прочь.

Как измерять бандинг и какой метрике верить

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

Текущий стандарт – CAMBI (Contrast-Aware Multiscale Banding Index), опубликованный Tandon, Afonso, Solé и Krasula на Picture Coding Symposium в 2021 году и открытый внутри репозитория VMAF от Netflix. CAMBI – безреференсный детектор, работающий покадрово и построенный на модели человеческого зрения: он использует функцию контрастной чувствительности (Contrast Sensitivity Function) – насколько видима ступень контраста при данной яркости и пространственном масштабе – чтобы взвесить каждый кандидат-контур по тому, насколько вероятно зритель его действительно увидит. Эта контраст-зависимость и есть суть; метрика, просто считающая края, отметила бы безобидную деталь, а CAMBI оценивает края, которые поймает глаз.

Читать оценку CAMBI просто. Она начинается с 0 – бандинг не обнаружен – и растёт с тяжестью; около 5 бандинг становится слегка раздражающим, а худшие наблюдаемые значения достигают ~24 (невозможно смотреть). Одна честная оговорка, на которой настаивают авторы: видимость бандинга сильно зависит от условий просмотра – ярче дисплей и темнее комната, тем виднее контур, – поэтому порог CAMBI стоит привязывать к тому, как ваша аудитория реально смотрит. CAMBI считает оценку с внутренней точностью 10 бит (преобразуя 8-битный вход вверх), а его окно анализа по умолчанию в 63 пикселя соответствует примерно одному градусу зрительного угла на 4K-экране при дистанции в 1,5 высоты картинки.

Второй серьёзный инструмент – индекс BBAND (Blind BANding Detector) от Tu, Lin, Wang, Adsumilli и Bovik с ICASSP 2020. Как и CAMBI, он безреференсный и зрение-инспирированный, и добавляет полезный выход: попиксельную карту видимости бандинга рядом с оценкой тяжести на уровне кадра и видео, так что видно, где контуры, а не только насколько плох кадр в целом.

МетрикаЧто измеряетНужен референсГде врёт на бандинге
PSNRсредняя пиксельная ошибка (дБ)полнореференснаяпочти слепа: контур в 1 код. значение – крошечная MSE, ~48 дБ
SSIMструктурное сходство, 0–1полнореференснаяв основном пропускает; плоские полосы держат высокое структурное сходство
VMAF (старая)слитная перцептивная оценка, 0–100полнореференснаязадокументированное слепое пятно – пробел, ради которого создан CAMBI
VMAF (v1, +CAMBI)слитная оценка с фичей бандингаполнореференснаятеперь реагирует, потому что CAMBI встроен
CAMBIконтраст-зависимая видимость бандинга, 0–24безреференснаясоздана для бандинга; та, что нужна; порог привязать к условиям просмотра
BBANDкарта видимости бандинга + тяжестьбезреференснаясоздана для бандинга; основана на HVS; даёт попиксельную карту

Таблица 1. Шесть способов, которыми метрика трактует бандинг. Полнореференсные недооценивают или пропускают его; специальные безреференсные детекторы (CAMBI, BBAND) – то, за чем тянуться, и они работают на лайве и UGC, где оригинала нет. Сопровождайте число взглядом на плоские области, где бандинг проступает первым.

Рисунок 3. Поведение метрик на бандинге. Полнореференсные недооценивают или пропускают его (PSNR и SSIM почти слепы); безреференсные детекторы, созданные под бандинг, – это CAMBI и BBAND. Вердикт несут и цвет, и колонка, поэтому ни один по отдельности не обязателен.

Замечание о VMAF, потому что это оценка, за которой следит большинство команд. Обычный VMAF был в основном слеп к бандингу – пробел, который CAMBI и закрывал, – а новая модель v1 встраивает CAMBI как фичу, так что актуальный VMAF реагирует на контуры там, где старая модель по умолчанию не реагировала. Подвох в том, что многие пайплайны до сих пор гоняют старую модель по умолчанию, поэтому «наш VMAF в порядке» – это заверение про бандинг лишь если вы знаете, какая модель его выдала. Полная история моделей VMAF – в статье VMAF: объяснение.

Рисунок 4. Внутри CAMBI. Три стадии – препроцессинг, контраст-зависимая уверенность в бандинге по нескольким масштабам, затем пространственно-временной пулинг – превращают кадр в одну безреференсную оценку, 0 (чисто) до ~24 (невозможно смотреть), где ~5 – точка, с которой бандинг начинает раздражать.
«Частая ошибка: верить зелёному дашборду больше, чем небу в кадре 200. Самая дорогая ошибка во всей теме – прочитать «VMAF 95, отгружаем» с модели, которая никогда не видела бандинг. Чистая слитная оценка может сидеть ровно поверх очевидных контуров в закате, тёмном интерьере или анимационном фоне, потому что – если вы не на CAMBI-aware модели – бандинг едва входит в число. Когда у контента плавные градиенты, добавьте детектор бандинга (CAMBI или BBAND), задайте порог, привязанный к тому, как смотрят ваши зрители, и подтвердите плоские кадры глазом. Метрика – это прокси со своей областью, а не справка о чистом здоровье; более широкая версия этого урока – Где врут объективные метрики.»

Где здесь Фора Софт

Фора Софт отгружает видеософт с 2005 года – стриминг, WebRTC-конференции, OTT, e-learning, телемедицину и видеонаблюдение, – и бандинг чаще других проскальзывает мимо автоматической проверки и доходит до зрителя, потому что дашборд говорит, что кодирование чистое. Мы трактуем его как задачу измерения известной формы: найти гладкие области, оценить их безреференсным детектором бандинга, а не слитным числом, и привязать порог «прошёл/не прошёл» к тому, как реально смотрит аудитория, – яркий экран в гостиной для OTT прощает меньше, чем телефон при дневном свете. Дальше средство следует за причиной: больше битовой глубины для неба и анимации, дизеринг или проход дебандинга там, где перекодировать в 10 бит нельзя. Где это помогает решению, мы указываем на собственные бенчмарк-данные, чтобы вы проверяли метод, а не верили на слово.

Ключевые выводы

  • Бандинг (ложное контурирование) – лестница плоских ступеней там, где должен быть плавный градиент.
  • У него две причины: слишком мало уровней яркости (низкая битовая глубина) и квантование, округляющее тонкую вариацию.
  • Глаз усиливает прямой низкоконтрастный край (полосы Маха), поэтому контур в 1 кодовое значение бросается в глаза.
  • PSNR, SSIM и старый VMAF почти пропускают бандинг – полосатое небо читается как ~48 дБ / VMAF 95.
  • Измеряйте его безреференсным детектором на модели зрения: CAMBI (0–24, внутри VMAF) или индекс BBAND.
  • Чините бо́льшей битовой глубиной, дизерингом или дебандинг-фильтром – но никогда не дизерьте прямо перед кодированием с потерями.

Что почитать дальше

Строите такую систему?

Подберём параметры кодирования под ваш контент и посчитаем стоимость доставки до старта разработки.