# теория · шаг 3 из 6
JPEG 2000: полосы, битовые плоскости и слои качества
Коротко
JPEG 2000 Part 1 сочетает преобразование компонент, вейвлетные полосы и блочное энтропийное кодирование коэффициентов. Обратимый путь использует целочисленное 5/3, необратимый - вещественное 9/7 и выбранное квантование. Коэффициенты читаются по битовым плоскостям от старших к младшим, поэтому часть кодовых данных может дать грубое восстановление, а следующие данные его уточнят. Слои качества и порядок пакетов управляют доставкой информации, а область интереса позволяет выделить приоритет нужным деталям. Точность определяется всем конвейером.
Если различаешь 5/3 и 9/7, разрешение и точность, а также восстанавливаешь коэффициенты по битовым плоскостям, переходи к «Теперь сам».
Как думаешь, почему файл можно читать понемногу
У обычного массива пикселов первые сто байтов дают только маленький участок. У подходящего иерархического представления те же сто байтов могут дать грубую картинку целиком, затем новые байты добавят детали. Но это не означает, что любая произвольная обрезка файла обязана корректно декодироваться.
Нужны границы кодовых данных, сведения о полосах и предсказуемый порядок передачи. Именно поэтому JPEG 2000 нельзя описать фразой «вместо ДКП взяли вейвлет». Преобразование создаёт удобные коэффициенты, а следующий конвейер организует их кодирование, приоритет и восстановление.
На что это похоже
Сначала передают старшие разряды измерений: можно отличить крупное значение от нуля. Потом добавляют младшие разряды и уточняют числа. Одновременно можно выбирать, какой участок таблицы отправить раньше. Это две независимые настройки: точность каждого числа и порядок выбора самих чисел.
Для изображения третья ось - масштаб. Получатель может раньше получить низкое разрешение или раньше получить грубую точность на большом разрешении. Читая описание прогрессии, выясняй, что именно улучшается и какие границы нужны декодеру для продолжения; одно слово «прогрессивный» этого не задаёт.
Механизм: от компоненты до кодового блока
Изображение при необходимости разбивают на прямоугольные тайлы, обрабатываемые отдельно. Внутри тайла выполняют сдвиг уровня, преобразование компонент и многоуровневое DWT, дискретное вейвлетное преобразование. Точное обратимое преобразование компонент, 5/3 без необратимого квантования и сохранение всех нужных кодовых данных позволяют вернуть исходные целые. Для необратимого пути применяют 9/7; объявить его точным только из-за высокой настройки качества нельзя.
Полосы делят на кодовые блоки, относительно самостоятельные единицы энтропийного кодирования. Коэффициенты читают по плоскостям двоичных разрядов. Первый ненулевой старший бит делает коэффициент значимым, после чего нужен знак. Дальнейшие младшие биты уточняют уже значимую величину. Вероятность события зависит от контекста, в том числе от значимости соседей.
В классическом блочном кодировании Part 1 применяются три жанра проходов: распространение значимости, уточнение величины и завершающая обработка оставшихся позиций. Сканирование и допустимые контексты заданы стандартом; двоичные решения кодируются адаптивным арифметическим MQ-кодером. Это развитие идеи контекстного моделирования и арифметического кодирования из предыдущих глав, а не независимый метод угадывания коэффициентов.
На самой старшей значимой плоскости кодового блока выполняется только завершающий проход cleanup: прежних значимых коэффициентов ещё нет. На последующих плоскостях первый проход посещает ещё незначимые позиции, у которых уже есть значимый сосед; состояние обновляется по ходу обхода. Второй уточняет коэффициенты, значимые до начала этой плоскости. Третий обрабатывает оставшиеся незначимые позиции. Каждый раз знак нужен при первом ненулевом бите, а не при каждом уточнении. Это предотвращает двойную передачу одного разряда и объясняет разные статистические контексты.
Обратимое цветовое преобразование RCT также должно использовать целые числа и согласованное округление. Фильтр 9/7 требует вещественных коэффициентов, а его ошибку нельзя свести только к отбрасыванию битовых плоскостей. Формулы RCT, четыре шага 9/7 и числовую ROI-маску разберём в следующей главе «Цвет, фильтры и область интереса».
Правило
Различай математическое преобразование, целочисленные символы и организацию кодовых данных. Полный обратимый путь сохраняет исходные целые. Квантование или отказ от части уточняющих данных создают приближение. Кодовые блоки, слои и пакеты позволяют выбирать, какую точность и какие области доставить раньше, не создавая отсутствующую информацию.
Вейвлеты избегают обязательной сетки независимых ДКП-блоков 8×8, но это не обещание отсутствия любых артефактов. Грубая точность может давать размывание и колебания у контуров; границы независимых тайлов также требуют внимания. Размер тайла - другой параметр, чем размер кодового блока коэффициентов.
Разбор: коэффициенты 5,−2,0,1 по плоскостям
Модули имеют записи 101,010,000,001. На плоскости 2 впервые становится
значимым первый коэффициент, передаём его положительный знак.
Грубая реконструкция [4,0,0,0]. На плоскости 1 второй коэффициент
впервые ненулевой, передаём отрицательный знак, получаем [4,−2,0,0].
На плоскости 0 уточняется первый коэффициент: 4 превращается в 5.
Последний коэффициент впервые становится значимым, передаём его положительный
знак. Получаем [5,−2,0,1].
В программе (abs(value) >> plane) & 1 выбирает нужный бит модуля.
Сдвиг вправо на plane позиций для неотрицательного целого равносилен делению
на 2**plane с отбрасыванием остатка, а & 1 оставляет младший двоичный разряд.
Операция 1 << plane строит вес этого разряда. Сами отрицательные коэффициенты
здесь не сдвигаются: модуль и знак учитываются отдельно.
coeff = [5, -2, 0, 1]
seen = [False] * len(coeff)
restored = [0] * len(coeff)
for plane in range(2, -1, -1):
symbols = []
for i, value in enumerate(coeff):
bit = (abs(value) >> plane) & 1
kind = "уточнение" if seen[i] else "значимость"
symbols.append((i, kind, bit))
if bit:
sign = -1 if value < 0 else 1
if not seen[i]:
symbols.append((i, "знак", sign))
seen[i] = True
restored[i] += sign * (1 << plane)
print("плоскость", plane, "реконструкция:", restored)
print("символы:")
for symbol in symbols:
print(" ", symbol)
roi = [False, True, False, False]
shifted = [c * 8 if important else c
for c, important in zip(coeff, roi)]
print("приоритет ROI:", shifted)
print("после обратного сдвига:",
[c // 8 if important else c
for c, important in zip(shifted, roi)])
плоскость 2 реконструкция: [4, 0, 0, 0]
символы:
(0, 'значимость', 1)
(0, 'знак', 1)
(1, 'значимость', 0)
(2, 'значимость', 0)
(3, 'значимость', 0)
плоскость 1 реконструкция: [4, -2, 0, 0]
символы:
(0, 'уточнение', 0)
(1, 'значимость', 1)
(1, 'знак', -1)
(2, 'значимость', 0)
(3, 'значимость', 0)
плоскость 0 реконструкция: [5, -2, 0, 1]
символы:
(0, 'уточнение', 1)
(1, 'уточнение', 0)
(2, 'значимость', 0)
(3, 'значимость', 1)
(3, 'знак', 1)
приоритет ROI: [5, -16, 0, 1]
после обратного сдвига: [5, -2, 0, 1]
Программа показывает значение, знак и уточнение в простом последовательном обходе. Это учебная модель битовых плоскостей, а не нормативный EBCOT-поток: в ней нет всех проходов, контекстов MQ и упаковки пакетов. Она отделяет смысл передаваемых двоичных решений от их энтропийного кодирования. Число напечатанных кортежей не является числом битов готового JPEG 2000.
Разбор: слои качества и область интереса
Кодировщик получает точки, в которых обработку кодового блока допустимо завершить. Каждая дополнительная порция данных стоит некоторое число битов и уменьшает искажение. Выбирая порции в пределах бюджета, он формирует слои качества. Пакеты объединяют вклады нужных блоков с привязкой к компоненте, разрешению, области и слою. Порядок пакетов определяет прогрессию доставки. Это не список независимых копий изображения разного качества.
Например, у двух порций одинаковая цена 10 бит. Одна уменьшает выбранную ошибку на 20, другая на 5. При бюджете одной порции выгоднее первая, если нет других ограничений и зависимостей. При увеличении бюджета можно взять обе. В настоящем распределении учитывают допустимые предшествующие проходы каждого блока: нельзя взять младшее уточнение без сведений, от которых зависит его интерпретация.
ROI, область интереса, задаёт повышенный приоритет определённым участкам. Маску надо связать с коэффициентами DWT: один коэффициент может влиять на несколько пикселов, поэтому взять только прямоугольник той же формы в каждой полосе недостаточно. Один способ приоритета - повысить разрядную значимость нужных коэффициентов сдвигом, а после декодирования вернуть масштаб. В программе модуль −2 сдвинут на три бита и стал −16: он встретится раньше. Показанный сдвиг с известной маской иллюстрирует механизм, но не заменяет нормативные правила ROI и сигнализации JPEG 2000.
Что ломается без этого
Говорят «5/3, значит без потерь», хотя поток обрезан до раннего слоя. Или после точного вейвлетного преобразования округляют коэффициенты с шагом больше единицы. Обратимость одного этапа не гарантирует обратимость всех.
Путают контейнер JP2 с самим кодовым потоком JPEG 2000. Контейнер хранит дополнительные сведения об интерпретации изображения; поддержка одной упаковки не означает поддержку всех частей семейства и профилей. Здесь изучается базовая архитектура Part 1, а не все последующие расширения.
Зачем это в работе
При просмотре большого снимка нужны разные решения: быстро показать обзор, передать выбранную область или точно сохранить все отсчёты. Разделение разрешения, точности и порядка пакетов позволяет сформулировать эти требования отдельно. А при проверке «без потерь» надо восстановить пикселы и сравнить их, а не ограничиться названием преобразования в настройках.
Теперь сам
Пусть коэффициент равен −6, его модуль 110. Что известно после старшей плоскости 2 с переданным знаком? Что получится после плоскости 1? Может ли ранний слой обратимого пути уже гарантировать точное исходное изображение?
Ответ. Сначала восстановим −4, затем −6. Для этого коэффициента последняя плоскость нулевая, но у других она может быть ненулевой. Раннего слоя недостаточно для общего обещания точности: нужны все кодовые данные, несущие непереданную информацию.
Главное
JPEG 2000 организует не только преобразование изображения, но и постепенную передачу значимости, знака и точности коэффициентов. Проверяй весь путь и реально полученные данные, прежде чем делать вывод о разрешении, качестве или восстановлении без потерь.
Комментарии
Пока нет комментариев. Будь первым!
Оставить комментарий