Метод сжатия jpeg. Смотреть что такое "JPEG" в других словарях. Введение основных понятий и принципов работы

  • Tutorial

UPD. Был вынужден убрать моноширинное форматирование. В один прекрасный день хабрапарсер перестал воспринимать форматирование внутри тегов pre и code. Весь текст превратился в кашу. Администрация хабра не смогла мне помочь. Теперь неровно, но хотя бы читабельно.

Вам когда-нибудь хотелось узнать как устроен jpg-файл? Сейчас разберемся! Прогревайте ваш любимый компилятор и hex-редактор, будем декодировать это:

Специально взял рисунок поменьше. Это знакомый, но сильно пережатый favicon Гугла:

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

Даже не зная, как происходит кодирование, мы уже можем кое-что извлечь из файла.
- маркер начала. Он всегда находится в начале всех jpg-файлов.
Следом идут байты . Это маркер, означающий начало секции с комментарием. Следующие 2 байта - длина секции (включая эти 2 байта). Значит в следующих двух - сам комментарий. Это коды символов ":" и ")", т.е. обычного смайлика. Вы можете увидеть его в первой строке правой части hex-редактора.

Немного теории

Очень кратко по шагам:
Давайте подумаем, в каком порядке могут быть закодированы эти данные. Допустим, сначала полностью, для всего изображения, закодирован канал Y, затем Cb, потом Cr. Все помнят загрузку картинок на диал-апе. Если бы они кодировались именно так, нам бы пришлось ждать загрузки всего изображения, прежде чем оно появится на экране. Так же будет неприятно, если потерятся конец файла. Вероятно, существуют и другие весомые причины. Поэтому закодированные данные располагаются поочередно, небольшими частями.

Напоминаю, что каждый блок Y ij , Cb ij , Cr ij - это матрица коэффициентов ДКП, закодированная кодами Хаффмана. В файле они располагаются в таком порядке: Y 00 Y 10 Y 01 Y 11 Cb 00 Cr 00 Y 20

Чтение файла

После того, как мы извлекли комментарий, будет легко понять, что:
  • Файл поделен на секторы, предваряемые маркерами.
  • Маркеры имеют длину 2 байта, причем первый байт .
  • Почти все секторы хранят свою длину в следующих 2 байта после маркера.
Для удобства подсветим маркеры:
FF D8 FF FE 00 04 3A 29 FF DB 00 43 00 A0 6E 78



FF FF FF FF FF FF FF FF FF FF FF FF FF FF DB 00
43 01 AA B4 B4 F0 D2 F0 FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF C0 00 11 08 00 10 00 10 03 01 22 00 02
11 01 03 11 01 FF C4 00 15 00 01 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 03 02 FF C4 00 1A
10 01 00 02 03 01 00 00 00 00 00 00 00 00 00 00
00 01 00 12 02 11 31 21 FF C4 00 15 01 01 01 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 FF
C4 00 16 11 01 01 01 00 00 00 00 00 00 00 00 00
00 00 00 00 11 00 01 FF DA 00 0C 03 01 00 02 11
03 11 00 3F 00 AE E7 61 F2 1B D5 22 85 5D 04 3C
82 C8 48 B1 DC BF FF D9

Маркер : DQT - таблица квантования.

FF DB 00 43 00 A0 6E 78
8C 78 64 A0 8C 82 8C B4 AA A0 BE F0 FF FF F0 DC
DC F0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
FF FF FF FF FF FF FF FF FF FF FF FF FF

Заголовок секции всегда занимает 3 байта. В нашем случае это . Заголовок состоит из:
Длина: 0x43 = 67 байт
Длина значений в таблице: 0 (0 - 1 байт, 1 - 2 байта)
[_0] Идентификатор таблицы: 0
Оставшимися 64-мя байтами нужно заполнить таблицу 8x8.



Приглядитесь, в каком порядке заполнены значения таблицы. Этот порядок называется zigzag order:

Маркер : SOF0 - Baseline DCT

Этот маркер называется SOF0, и означает, что изображение закодировано базовым методом. Он очень распространен. Но в интернете не менее популярен знакомый вам progressive-метод, когда сначала загружается изображение с низким разрешением, а потом и нормальная картинка. Это позволяет понять что там изображено, не дожидаясь полной загрузки. Спецификация определяет еще несколько, как мне кажется, не очень распространенных методов.

FF C0 00 11 08 00 10 00 10 03 01 22 00 02
11 01 03 11 01

Длина: 17 байт.
Precision: 8 бит. В базовом методе всегда 8. Как я понял, это разрядность значений каналов.
Высота рисунка: 0x10 = 16
Ширина рисунка: 0x10 = 16
Количество компонентов: 3. Чаще всего это Y, Cb, Cr.

1-й компонент:
Идентификатор: 1
Горизонтальное прореживание (H 1): 2
[_2] Вертикальное прореживание (V 1): 2
Идентификатор таблицы квантования: 0

2-й компонент:
Идентификатор: 2
Горизонтальное прореживание (H 2): 1
[_1] Вертикальное прореживание (V 2): 1

3-й компонент:
Идентификатор: 3
Горизонтальное прореживание (H 3): 1
[_1] Вертикальное прореживание (V 3): 1
Идентификатор таблицы квантования: 1

Теперь посмотрите, как определить насколько прорежено изображение. Находим H max =2 и V max =2 . Канал i будет прорежен в H max /H i раз по горизонтали и V max /V i раз по вертикали.

Маркер : DHT (таблица Хаффмана)

Эта секция хранит коды и значения полученные кодированием Хаффмана .

FF C4 00 15 00 01 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 03 02

длина: 21 байт.
класс: 0 (0 - таблица DC коэффициэнтов, 1 - таблица AC коэффициэнтов).
[_0] идентификатор таблицы: 0
Длина кода Хаффмана: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
Количество кодов:
Количество кодов означает количество кодов такой длины. Обратите внимание, что секция хранит только длины кодов, а не сами коды. Мы должны найти коды сами. Итак, у нас есть один код длины 1 и один - длины 2. Итого 2 кода, больше кодов в этой таблице нет.
С каждым кодом сопоставлено значение, в файле они перечислены следом. Значения однобайтовые, поэтому читаем 2 байта.
- значение 1-го кода.
- значение 2-го кода.

Построение дерева кодов Хаффмана

Мы должны построить бинарное дерево по таблице, которую мы получили в секции DHT. А уже по этому дереву мы узнаем каждый код. Значения добавляем в том порядке, в каком указаны в таблице. Алгоритм прост: в каком бы узле мы ни находились, всегда пытаемся добавить значение в левую ветвь. А если она занята, то в правую. А если и там нет места, то возвращаемся на уровень выше, и пробуем оттуда. Остановиться нужно на уровне равном длине кода. Левым ветвям соответствует значение 0 , правым - 1 .
Замечание:
Не нужно каждый раз начинать с вершины. Добавили значение - вернитесь на уровень выше. Правая ветвь существует? Если да, идите опять вверх. Если нет - создайте правую ветвь и перейдите туда. Затем, с этого места, начинайте поиск для добавления следующего значения.

Деревья для всех таблиц этого примера:


UPD (спасибо ): В узлах первого дерева (DC, id =0) должны быть значения 0x03 и 0x02

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

Маркер : SOS (Start of Scan)

Байт в маркере означает - «ДА! Наконец-то то мы перешли непосредственно к разбору секции закодированного изображения!». Однако секция символично называется SOS.

  FF DA 00 0C 03 01 00 02 11
03 11 00 3F 00

Длина заголовочной части (а не всей секции): 12 байт.
Количество компонентов сканирования. У нас 3, по одному на Y, Cb, Cr.

1-й компонент:
Номер компонента изображения: 1 (Y)
Идентификатор таблицы Хаффмана для DC коэффициэнтов: 0
[_0] Идентификатор таблицы Хаффмана для AC коэффициэнтов: 0

2-й компонент:
Номер компонента изображения: 2 (Cb)

[_1]

3-й компонент:
Номер компонента изображения: 3 (Cr)
Идентификатор таблицы Хаффмана для DC коэффициэнтов: 1
[_1] Идентификатор таблицы Хаффмана для AC коэффициэнтов: 1

Данные компоненты циклически чередуются.

На этом заголовочная часть заканчивается, отсюда и до конца (маркера ) закодированные данные.


0

Нахождение DC-коэффициента.
1. Читаем последовательность битов (если встретим 2 байта , то это не маркер, а просто байт ) . После каждого бита сдвигаемся по дереву Хаффмана (с соответствующим идентификатором) по ветви 0 или 1, в зависимости от прочитанного бита. Останавливаемся, если оказались в конечном узле.
10 1011101110011101100001111100100

2. Берем значение узла. Если оно равно 0, то коэффициент равен 0, записываем в таблицу и переходим к чтению других коэффициентов. В нашем случае - 02. Это значение - длина коэффициента в битах. Т. е. читаем следующие 2 бита, это и будет коэффициент.
10 10 11101110011101100001111100100

3. Если первая цифра значения в двоичном представлении - 1, то оставляем как есть: DC_coef = значение. Иначе преобразуем: DC_coef = значение-2 длина значения +1 . Записываем коэффициент в таблицу в начало зигзага - левый верхний угол.

Нахождение AC-коэффициентов.
1. Аналогичен п. 1, нахождения DC коэффициента. Продолжаем читать последовательность:
10 10 1110 1110011101100001111100100

2. Берем значение узла. Если оно равно 0, это означает, что оставшиеся значения матрицы нужно заполнить нулями. Дальше закодирована уже следующая матрица. Первые несколько дочитавших до этого места и написавших об этом мне в личку, получат плюс в карму. В нашем случае значение узла: 0x31.
Первый полубайт: 0x3 - именно столько нулей мы должны добавить в матрицу. Это 3 нулевых коэффициэнта.
Второй полубайт: 0x1 - длина коэффициэнта в битах. Читаем следующий бит.
10 10 1110 1 110011101100001111100100

3. Аналогичен п. 3 нахождения DC-коэффициента.

Как вы уже поняли, читать AC-коэффициенты нужно пока не наткнемся на нулевое значение кода, либо пока не заполнится матрица.
В нашем случае мы получим:
10 10 1110 1 1100 11 101 10 0 0 0 1 11110 0 100
и матрицу:





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

[-4 1 1 1 0 0 0 0] [ 5 -1 1 0 0 0 0 0]
[ 0 0 1 0 0 0 0 0] [-1 -2 -1 0 0 0 0 0]
[ 0 -1 0 0 0 0 0 0] [ 0 -1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [-1 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

[-4 2 2 1 0 0 0 0]
[-1 0 -1 0 0 0 0 0]
[-1 -1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

Ой, я забыл сказать, что закодированные DC-коэффициенты - это не сами DC-коэффициенты, а их разности между коэффициентами предыдущей таблицы (того же канала)! Нужно поправить матрицы:
DC для 2-ой: 2 + (-4) = -2
DC для 3-ой: -2 + 5 = 3
DC для 4-ой: 3 + (-4) = -1

[-2 1 1 1 0 0 0 0] [ 3 -1 1 0 0 0 0 0] [-1 2 2 1 0 0 0 0]
………

Теперь порядок. Это правило действует до конца файла.

… и по матрице для Cb и Cr:

[-1 0 0 0 0 0 0 0]
[ 1 1 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

Так как тут только по одной матрице, DC-коэфициенты можно не трогать.

Вычисления

Квантование

Вы помните, что матрица проходит этап квантования? Элементы матрицы нужно почленно перемножить с элементами матрицы квантования. Осталось выбрать нужную. Сначала мы просканировали первый компонент, его компонента изображения = 1. Компонент изображения с таким идентификатором использует матрицу квантования 0 (у нас она первая из двух). Итак, после перемножения:


[ 0 120 280 0 0 0 0 0]
[ 0 -130 -160 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

Аналогично получаем еще 3 матрицы Y-канала…

[-320 110 100 160 0 0 0 0] [ 480 -110 100 0 0 0 0 0]
[ 0 0 140 0 0 0 0 0] [-120 -240 -140 0 0 0 0 0]
[ 0 -130 0 0 0 0 0 0] [ 0 -130 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [-140 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

[-160 220 200 160 0 0 0 0]
[-120 0 -140 0 0 0 0 0]
[-140 -130 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]

… и по матрице для Cb и Cr.

[-170 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 180 210 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]
[ 0 0 0 0 0 0 0 0] [ 0 0 0 0 0 0 0 0]

Обратное дискретно-косинусное преобразование

Формула не должна доставить сложностей*. S vu - наша полученная матрица коэффициентов. u - столбец, v - строка. s yx - непосредственно значения каналов.

*Вообще говоря, это не совсем правда. Когда я смог декодировать и отобразить на экране рисунок 16x16, я взял изображение размером 600x600 (кстати, это была обложка любимого альбома Mind.In.A.Box - Lost Alone). Получилось не сразу - всплыли различные баги. Вскоре я мог любоваться корректно загруженной картинкой. Только очень огорчала скорость загрузки. До сих пор помню, она занимала 7 секунд. Но это и неудивительно, если бездумно пользоваться приведенной формулой, то для вычисления одного канала одного пикселя потребуется нахождения 128 косинусов, 768 умножений, и сколько-то там сложений. Только вдумайтесь - почти тысяча непростых операций только на один канал одного пиксела! К счастью, тут есть простор для отимизации (после долгих экспериментов уменьшил время загрузки до предела точности таймера 15мс, и после этого сменил изображение на фотографию в 25 раз большей площадью. Возможно, напишу об этом отдельной статьей).

Напишу результат вычисления только первой матрицы канала Y (значения округлены):


[ 87 72 50 36 37 55 79 95]
[-10 5 31 56 71 73 68 62]
[-87 -50 6 56 79 72 48 29]

И 2-х оставшихся:
Cb Cr
[ 60 52 38 20 0 -18 -32 -40] [ 19 27 41 60 80 99 113 120]
[ 48 41 29 13 -3 -19 -31 -37] [ 0 6 18 34 51 66 78 85]
[ 25 20 12 2 -9 -19 -27 -32] [-27 -22 -14 -4 7 17 25 30]
[ -4 -6 -9 -13 -17 -20 -23 -25] [-43 -41 -38 -34 -30 -27 -24 -22]
[ -37 -35 -33 -29 -25 -21 -18 -17] [-35 -36 -39 -43 -47 -51 -53 -55]
[ -67 -63 -55 -44 -33 -22 -14 -10] [ -5 -9 -17 -28 -39 -50 -58 -62]
[ -90 -84 -71 -56 -39 -23 -11 -4] [ 32 26 14 -1 -18 -34 -46 -53]
[-102 -95 -81 -62 -42 -23 -9 -1] [ 58 50 36 18 -2 -20 -34 -42]

  1. О, пойду-ка поем!
  2. Да я вообще не въезжаю, о чем речь.
  3. Раз значение цветов YCbCr получены, осталось преобразовать в RGB, типа так: YCbCrToRGB(Y ij , Cb ij , Cr ij) , Y ij , Cb ij , Cr ij - наши полученные матрицы.
  4. 4 матрицы Y, и по одной Cb и Cr, так как мы прореживали каналы и 4 пикселям Y соответствует по одному Cb и Cr. Поэтому вычислять так: YCbCrToRGB(Y ij , Cb , Cr )
Если вы выбрали 1 и 4, то я рад за вас. Либо вы все правильно поняли, либо скоро будете получать удовольствие от еды.

YCbCr в RGB

R = Y + 1.402 * Cr
G = Y - 0.34414 * Cb - 0.71414 * Cr
B = Y + 1.772 * Cb
Не забудьте прибавить по 128. Если значения выйдут за пределы интервала , то присвоить граничные значения. Формула простая, но тоже отжирает долю процессорного времени.

Вот полученные таблицы для каналов R, G, B для левого верхнего квадрата 8x8 нашего примера:
255 248 194 148 169 215 255 255
255 238 172 115 130 178 255 255
255 208 127 59 64 112 208 255
255 223 143 74 77 120 211 255
237 192 133 83 85 118 184 222
177 161 146 132 145 162 201 217
56 73 101 126 144 147 147 141
0 17 76 126 153 146 127 108

231 185 117 72 67 113 171 217
229 175 95 39 28 76 139 189
254 192 100 31 15 63 131 185
255 207 115 46 28 71 134 185
255 241 175 125 112 145 193 230
226 210 187 173 172 189 209 225
149 166 191 216 229 232 225 220
72 110 166 216 238 231 206 186

255 255 249 203 178 224 255 255
255 255 226 170 140 187 224 255
255 255 192 123 91 138 184 238
255 255 208 139 103 146 188 239
255 255 202 152 128 161 194 232
255 244 215 200 188 205 210 227
108 125 148 172 182 184 172 167
31 69 122 172 191 183 153 134

Конец

Вообще я не специалист по JPEG, поэтому вряд ли смогу ответить на все вопросы. Просто когда я писал свой декодер, мне часто приходилось сталкиваться с различными непонятными проблемами. И когда изображение выводилось некорректно, я не знал где допустил ошибку. Может неправильно проинтерпретировал биты, а может неправильно использовал ДКП. Очень не хватало пошагового примера, поэтому, надеюсь, эта статья поможет при написании декодера. Думаю, она покрывает описание базового метода, но все-равно нельзя обойтись только ей. Предлагаю вам ссылки, которые помогли мне:

Сжатие методом JPEG является самым распространенным и эффективным способом сжатия. В 1992 году стал международным стандартом в области ГИ. JPEG – аббревиатура группы экспертов создавших стандарт (Joint Photographic Experts Group).

В основе метода лежит поиск разницы между соседними пикселями. Кодирование осуществляется в несколько этапов.

1. Конвертирование цветовой модели изображения (обычно RGB) в цветовую модель YUV, некоторый аналог модели Lab, где яркостная составляющая отделена от цветовой. В модели RGB изменение любого компонента цвета приводит к изменению яркости пикселя. В модели YUV компонента Y – компонента яркости, а компоненты U, V – хранят информацию о цвете.

Y = 0,299 x R + 0,587 x G + 0,114 x B

U = (B – Y) / 0,433 +128

V = (R – Y) / 0,355 + 128

2. Подвыборка – соседние пиксели группируются попарно в каналах U и V. Разделение яркости и цвета позволяет уделять больше внимание яркости, чем данным о цвете. Этот процесс осуществляется для компонент с различной частотой.

Используется два метода подвыборки 4:1:1 и 4:2:2. Так как каждый цвет кодируется 3 байтами, для передачи цвета 4 пикселей (12 байт в RGB) требуется 6 байт и 8 байт соответственно. Т.е. YUV411 сокращает объем данных в два раза, а YUV422 в 1,5 раз. С точки зрения математики происходит значительная потеря информации, но человеческий глаз ее не воспринимает, ввиду избыточности информации в самом изображении.

3. Группировка пикселей в блоки, обычно размером 8х8. В каждой выборке определяется запись изменений частот (как часто меняются яркость и цвет пикселей), так называемое дискретное косинусное преобразование (DCT). Таким образом, яркость заменяется на частоту появления той или иной яркости. На этом этапе размер файла может увеличиться, но следующие этапы это устраняют.

4. Квантование – удаление малозначительной для глаза информации. Все составляющие делятся на коэффициенты относительной важности и округляются до целого.

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

5. Этап Zig-Zag . Этап назван так вследствие того, что пиксели собираются в последовательность по размерам (сначала располагаются пиксели, отвечающие за более крупные объекты). Кодировщик движется как бы зигзагом.

6. Сжатие методом RLE.

7. Сжатие методом JPEG.

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

Вопросы для самопроверки.

1. Для чего необходимы алгоритмы сжатия данных?

2. Что такое сжатие "без потерь" и сжатие "с потерями"?

3. Опишите основные алгоритмы сжатия графической информации "без потерь".

4. Опишите алгоритм сжатия методом JPEG.

Голосование: 22, 4

Введение

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

В то время уже были достаточно распространены среди пользователей персональных компьютеров такие графические форматы, как BMP, PCX, GIF. Но даже уменьшение объема графической информации в два раза оказалось недостаточным для современных графических систем. В связи с этим с конца 80х годов две крупнейшие в мире организации стандартов CCITT и ISO объединили свои усилия для выработки единого стандарта формата графического файла, сжатого с потерями. Новый стандарт получил свое название JPEG по имени группы разработчиков Joint Photographic Experts Group.

Сделаем небольшое замечание: JPEG прежде всего является методом сжатия. Его нельзя рассматривать в качестве полноценного стандарта представления изображений. Поэтому в нем не задаются такие специфические параметры изображения, как геометрический размер пикселя, пространство цветов или чередование битовых строк. То же можно сказать и о JPEG2000, и о JPEG-LS — это методы сжатия, а не полноценные стандарты.

1. JPEG

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


Рис. 1.
  • Препроцессинг — этап, на котором выполняется предварительная обработка изображения, приводящая его к удобному для последующего кодирования виду.
  • Дискретное косинусное преобразование (ДКП) используется кодером JPEG для преобразования изображения от его пространственного представления к спектральному.
  • Округление (квантование) — этап, на котором происходит основная потеря информации за счет округления несущественных, высокочастотных ДКП-коэффициентов.
  • Сжатие — кодирование полученных данных стандартными методами (кодирование повторов, арифметическое кодирование и т.д.)

Если изображение содержит более одной компоненты, то они кодируются по отдельности. В связи с этим, на данном этапе выполняется перевод графического изображения из его компонентного представления в цветоразностное, яркостное представление (ICT — Irreversible Color Transform). В связи с тем, что человеческий глаз более восприимчив к яркостному сигналу, чем к цветовому, это преобразование позволит добиться больших результатов сжатия при меньших визуальных потерях. Далее будет рассматриваться кодирование одной отдельной компоненты.

Рис. 2.

Рис. 3.

Помимо ICT преобразования, на данном этапе исходное изображение разбивается на малые квадратные блоки и выполняется сдвиг основания значений цвета относительно нуля для корректного пространственного представления изображения: -> [-2 p-1 , 2 p-1 - 1] . Эти шаги важны для эффективной работы кодера на следующем этапе.

1.2. ДКП

Являясь ключевым шагом алгоритма сжатия, дискретное косинусное преобразование (далее ДКП) представляет собой разновидность преобразования Фурье и, также как и последнее, имеет обратное преобразование (ОДКП). Если рассматривать изображение как совокупность пространственных волн, где оси X и Y соответствуют ширине и высоте картинки, а по оси Z откладываются значения цвета соответствующих пикселей, то можно перейти от пространственного представления картинки к ее спектральному представлению и обратно. ДКП преобразует матрицу пикселей размера N x N в матрицу частотных коэффициентов соответствующего размера.



Рис. 4.

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

Из формул (рис. 4) видно, что вычисление одного элемента результирующей матрицы требует O(N 2) времени, поэтому почти невозможно выполнить преобразование всей матрицы целиком. Группа разработчиков JPEG предложила оптимальный вариант решения этой проблемы: разбивать исходную матрицу на квадраты стандартного размера 8x8 и выполнять преобразование каждого из них. Использование блоков большего размера позволит улучшить качество сжатия, но не до бесконечности, так как слишком мала вероятность того, что сильно отдаленные точки похожи друг на друга.

Стоит отметить, что в ходе вычислений используется только 32 заранее вычисленных значения косинусов, что позволяет заметно увеличить скорость работы преобразования. Это уже, несомненно, приводит к частичной потери информации, но ее объемы относительно несущественны.

Небольшого увеличения производительности можно добиться, если при вычислениях использовать только целочисленную арифметику, что, правда, является актуальным только для старых вычислительных машин, так как в современных компьютерах стоимость операций над числами с плавающей запятой не отличается от операций над целыми. Также использование целочисленной арифметике негативно сказывается на качестве сжимаемого изображения, что делает этот метод неприемлемым для современных компьютеров. Так как ДКП является разновидностью преобразования Фурье, то все методы увеличения производительности преобразования Фурье могут быть использованы и здесь.

1.3. Округление

Следующим этапом, на котором и происходит основная потеря информации, является округление или квантование. Как видно, ДКП не выполняет какого-либо сжатия или кодирования. Основной его задачей является преобразование исходного изображения к виду, удобному для последующих операций над ним.

Округлением называется процесс уменьшения объема информации, необходимого для хранения матрицы ДКП, с частичной потерей точности. По стандарту JPEG для этого используется матрица округления (МО). Каждому элементу исходной матрицы ДКП соответствует элемент МО. Результирующая матрица получается делением исходной матрица на МО. При этом низкочастотным значениям в матрице ДКП соответствуют меньшие коэффициенты МО, что позволяет оставлять более значимую, низкочастотную информацию и отбрасывать менее важную высокочастотную. В связи с тем, что низкочастотные компоненты сосредоточены в левом верхнем углу матрицы ДКП, значения МО растут слева направо и сверху вниз.


3 5 7 9 11 13 15 17
5 7 9 11 13 15 17 19
7 9 11 13 15 17 19 21
9 11 13 15 17 19 21 23
11 13 15 17 19 21 23 25
13 15 17 19 21 23 25 27
15 17 19 21 23 25 27 29
17 19 21 23 25 27 29 31

Пример матрицы округления с фактором качества равным 2.

Результаты округления и качества восстановленного изображения напрямую зависят от выбранной матрицы округления. Стандарт JPEG позволяет использовать любую МО, однако ISO в ходе долгих экспериментальных тестирований разработала набор матриц, позволяющих добиться оптимальных результатов.

1.4. Сжатие

Последний этап работы алгоритма кодирования JPEG — это сжатие. После обработки матрицы ДКП с помощью МО, в результирующей матрице появляется большое количество нулей, особенно в высокочастотной области (правый нижний угол).

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

Рис. 5.

Наконец, на третьем и заключительном шаге полученный результат сжимается, как обычные данные с помощью алгоритма Хаффмана или арифметического кодирования в зависимости от реализации. Этот этап носит название «кодирование энтропии» (в терминологии JPEG).

1.5. Декодирование

Так как ДКП является преобразованием Фурье, к нему существует обратное дискретное косинусное преобразование (ОДКП). Алгоритм декодирования повторяет алгоритм кодирования в обратном порядке.

2. JPEG2000

Изначально новый стандарт разрабатывался как база для будущего стандарта сжатия без потерь JPEG-LS, но позднее был отвергнут в связи с появлением более эффективных алгоритмов. В связи с развитием технологий стандарт JPEG постепенно терял свою актуальность. Разработчики JPEG2000 надеялись создать стандарт, который исправил бы многие ошибки уже существующих стандартов. Среди их задач были:

  • Устранение неэффективного сжатия в области низких частот . Существующие алгоритмы неплохо справлялись со сжатием среднечастотных и высокочастотных областей, но в области низких частот они показывали плохие результаты.
  • Сжатие с потерями и без потерь . На момент разработки не существовало стандарта, позволяющего сжимать с потерями и без потерь в едином сжимающем потоке.
  • Обработка больших изображений . Существующие алгоритмы не позволяли эффективно сжимать изображения размером более 64Kx64K без разбиения на тайлы.
  • Единая структура алгоритма сжатия . Текущая реализация JPEG поддерживала 44 модификации, большая часть которых была специфичной для некоторых приложений и не поддерживалась большей частью декодеров.
  • Помехоустойчивость . Во время разработки JPEG сетевые технологии не были еще достаточно развиты, и проектировщики JPEG не задумывались над помехоустойчивостью при передаче изображений по небезопасным каналам и возможностью восстановления изображения в случае его повреждения в результате передачи.
  • Компьютерно-сгенерированные изображения . Исходные алгоритмы неплохо работали на цифровых фотографиях и изображениях, полученных с помощью цифровой фотокамеры или сканера, но неэффективно обрабатывали изображения, созданные на компьютере, например, с помощью графических редакторов.
  • Сложные документы . JPEG показывал очень плохие результаты при обработке сложных двумерных изображений (в частности изображений текста).

На следующей диаграмме представлены основные шаги работы кодера JPEG2000.


Рис. 6.


Рис. 7.

В отличие от JPEG кодер JPEG2000 не требует разбиения изображения на малые квадратные блоки, так как используемое в ходе работы алгоритма ДВП (дискретное вейвлетное преобразование) работает на фрагментах любого размера. С другой стороны иногда, в случае, если объем памяти, доступный кодеру для работы, меньше, чем объем памяти, необходимый для кодирования всего изображения, выполняется разбиение изображения на квадратные тайлы, которые кодируются независимо друг от друга. Далее будет рассматриваться кодирование одного тайла. Остальные шаги аналогичны JPEG.

Рис. 8.

2.2. ДВП

JPEG2000 использует дискретное вейвлетное преобразование (Discrete Wavelet Transformation), для разбиения изображения на высокочастотные и низкочастотные области. ДВП обрабатывает каждую строку и столбец исходного изображения с помощью частотного фильтра.

Рис. 9.

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

  • LL – низкие частоты по строкам и столбцам
  • HL – высокие частоты по строкам и низкие по столбцам
  • LH – низкие частоты по строкам и высокие по столбцам
  • HH – высокие частоты по строкам и столбцам

По стандарту количество этапов может быть от 0 до 32. Для обычного изображения используют от 4-х до 8-ми этапов. На каждом следующем этапе обрабатывается только низкочастотная область (LL), так как в высокочастотных областях обычно не содержится важной информации.


Рис. 10.

Рис. 11.

2.3. Округление

Для округления коэффициентов ДВП используется постоянный квантователь с мертвой зоной. (рис. 14) Для каждого фрагмента используется постоянное значение шага округления для всех коэффициентов этого фрагмента. Формула вычисления округленных значений представлена на рисунке 12. Здесь y - исходное значение коэффициента, sign(y) определяет знак коэффициента, а Δb - значение шага округления. Мертвая зона квантователя - это интервал диапазоном 2Δb около нуля, она дает большее количество нулей на выходе.

2.4. Кодирование

Кодирование полученных округленных коэффициентов выполняется поблочно. По стандарту JPEG2000 непосредственно перед кодированием фрагменты разбиваются на достаточно малые блоки (например, размером 32x32 или 64x64) так, чтобы все блоки одного фрагмента были одинакового размера. Разбиение на блоки выполняется для того, чтобы осуществить более гибкую организацию сжатой информации для повышения помехоустойчивости и так далее.


Рис. 16.

В JPEG2000 каждый блок кодируется по отдельности. Алгоритм кодирования обходит матрицу коэффициентов округления каждого блока полосами, как показано на рисунке 17. Блоки разбиваются на блоки с номинальной высотой 4. Далее полосы сканируются сверху вниз, а колонки в каждой полосе обходятся слева направо.


Рис. 17.

В процессе кодирования коэффициенты в блоке виртуально представляются в виде битовых плоскостей. Одну из таких плоскостей составляют знаки коэффициентов; остальные плоскости соответствуют различным разрядам величин коэффициентов (положение бита в плоскости соответствует положению коэффициента в блоке). Кодирование осуществляется по плоскостям: сначала кодируется плоскость, соответствующая старшему разряду коэффициентов, затем следующая по убыванию, и т.д. Может случиться так, что N наиболее приоритетных битовых плоскостей (НПБ-плоскостей), не будут содержать единиц. В этом случае НПБ-плоскостью становится первая по порядку плоскость, содержащая хотя бы одну единицу. Предшествующие ей пустые плоскости опускаются при кодировании, а информация о их количестве заносится в заголовок блока.

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

Для каждого бита плоскости, если соответствующий коэффициент еще не является значимым, и если хоть один соседний коэффициент уже является значимым, осуществляется кодирование факта значимости для текущего коэффициента, то есть фактически осуществляется кодирование значения данного бита текущей кодируемой плоскости. Если кодируемый бит оказался ненулевым, сразу после его обработки кодируется соответствующий бит битовой плоскости знаков коэффициентов (кодирование знака).

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

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

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

2.5. Организация данных

Важным преимуществом рассматриваемого стандарта является возможность доступа к отдельным элементам изображения без полного декодирования его представления. Обеспечивается такая возможность, во-первых, разбиением исходного изображения на непересекающиеся области (тайлы), которые кодируются как отдельные изображения, а во-вторых, представлением кода отдельного тайла в виде частей (слоев), каждая из которых является суммарным кодом коэффициентов, соответствующих некоторой его (тайла) области. Слои в свою очередь делятся на так называемые пакеты, содержащие код блоков коэффициентов на разных уровнях декомпозиции. Для того, чтобы декодировать какую-либо область изображения, достаточно определить, каким тайлам она принадлежит, и какие слои, относящиеся к этим тайлам, содержат код блоков коэффициентов, необходимых для восстановления требуемой области.



Рис. 20.

Безусловно, «удобное» представление изображения не может быть выгодным с точки зрения эффективности сжатия. Действительно, с уменьшением размера структурных элементов (тайлов, областей тайлов, образующих слои и др.) эффективность сжатия несколько снижается. Стандарт в данном случае оставляет нам выбор: с одной стороны, мы имеем возможность получать информационные представления, позволяющие достаточно быстро извлекать и редактировать части изображения, с другой стороны, стандарт не препятствует созданию информационных представлений, эффективных по объему.

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

Достижение высокого качества сжатия, безусловно, было одной из главных задач при создании стандарта, и здесь разработчики добились явного прогресса. Стандарт JPEG2000 превосходит по эффективности стандарт JPEG примерно в 2 раза при сжатии с потерями и на 5-20% при сжатии без потерь. Конечно, эффективность при сжатии без потерь в данном случае оказывается не такой высокой, как, скажем, у стандарта JPEG-LS, однако она вполне приемлема. Что же касается эффективности сжатия с потерями, здесь стандарт позволяет получать результаты, близкие к наилучшим на сегодняшний день результатам для подобного рода методов.

3. JPEG-LS

Формат JPEG-LS был основан на формате LOCO-I (Low Complexity Lossless Compression for Images). Алгоритм сжатия без потерь LOCO-I, принятый за основу при разработке стандарта JPEG-LS, впервые предусматривал не только lossless, но и near lossless режим (сжатие с ограниченными, задаваемыми пользователем потерями). В отличие от JPEG2000 lossless mode, JPEG-LS получился по-настоящему удачным: при большей эффективности сжатия новый стандарт обеспечивает высокую скорость компрессии/декомпрессии и не слишком требователен к ресурсам компьютера.

Важно понимать, что формат JPEG-LS:

  • не является расширением или модификацией метода JPEG;
  • не использует ни DCT (ДКП), ни арифметическое кодирование;
  • использует слабое квантование только в моде «почти без потерь»

3.1. Введение основных понятий и принципов работы

Сжатие данных без потерь состоит из двух отдельных независимых частей: моделирования (modeling) и кодирования (coding). Определим некоторые термины, которые будем активно использовать в дальнейшем:

Кодер (Encoder) «отвечает» за процесс кодирования, а именно: получает на вход исходное изображение в цифровом формате и все необходимые параметры, определенные стандартом, и с помощью специального набора процедур создает набор данных, содержащих сжатое изображение Декодер (Decoder) «отвечает» за процесс декодирования и преобразование фрагментов, а именно: получая на вход данные со сжатым изображением и все необходимые параметры, выводит реконструированное изображение

Декодер JPEG-LS мало отличается от кодера, поэтому этот алгоритм сжатия можно назвать почти симметричным. Приведем упрощенную схему, показывающую принципы кодирования:



Рис. 21.

Немного информации об исходном изображении : как ниже показано на схеме (рис. 22), исходное изображение может состоять из Nf компонент. Каждая компонента Ci содержит двумерный массив пикселей (samples) из x i столбцов и y i строк. Размеры компонент зависят от двух параметров: X и Y, где X - максимум среди x i значений, а Y - максимум среди y i значений всех компонент. (В стандарте JPEG-LS целая глава посвящена отличиям в работе с мультикомпонентными изображениями по сравнению с однокомпонентными, однако в этой статье мы остановимся лишь на работе однокомпонентными изображениями).



Рис. 22.

На рисунке отмечена ориентация каждой компоненты: top (верх), bottom (низ), left (лево), и right (право). Порядок, в котором пиксели подаются на обработку процедурам кодирования, определен так: left-to-right (слева направо) и top-to-bottom (сверху вниз) по компоненте.

Для прогнозирования текущего пикселя x используются пиксели контекста a, b, c, d. В зависимости от контекста кодер выбирает моду: серийную (run mode) или регулярную (regular mode) . Серийная мода выбирается, если y и z скорее всего будут совпадать, регулярная – в противном случае. Сделаем тут замечание, связанное с наличием опции «почти без потерь» : при включении этой опции серийная мода будет выбрана, если y и z будут почти совпадать в соответствии с параметром допустимого отклонения NEAR.

В случае использования серийной моды мы начинаем просмотр текущей строки с пикселя x и находим наибольшую длину серии пикселей, совпадающих с контекстным пикселем a. Таким образом, в пределах текущей строки мы получаем серию одинаковых пикселей, совпадающих по значению с известным нам пикселем a. Осталось только закодировать длину серии. (Это делается с помощью массива J из 32 элементов). Вы уже могли догадаться, что при включенной опции «почти без потерь» выбирается серия пикселей, близких к a с помощью параметра NEAR.

Теперь рассмотрим наши действия в случае использования регулярной моды. Для вычисления прогноза пикселя x (Px) используются величины пикселей a, b и c. Затем вычисляется так называемая ошибка прогноза (Errval). Ее значение равно разности значения x и Px. Errval корректируется некоторым членом, зависящим от контекста, а затем кодируется с помощью кодов Голомба. Код Голомба зависит от a, b, c, d и Errval этих же пикселей, которые хранятся в специальных массивах A и N. При включении опции «почти без потерь» перед кодированием ошибка прогноза ещё дополнительно квантуется.


Рис. 23.

3.2. Кодер

В основном JPEG-LS используется как метод сжатия информации без потерь, следовательно, восстановленный файл изображения обычно идентичен исходному файлу. В моде почти без потерь исходный и реконструированный образ могут отличаться. Будем обозначать реконструированный пиксель Rp, а исходный пиксель - p.

На стадии инициализации кодер выполняет следующие операции:

  • Вычисляются параметры RANGE = floor((MAXVAL + 2 * NEAR) / (2 * NEAR + 1)) + 1, qbpp = ceil(log RANGE), bpp = max(2, ceil(log(MAXVAL + 1))), LIMIT = 2 * (bpp + max(8, bpp)) . (В случае кодирования без потерь NEAR = 0, RANGE = MAXVAL + 1 . Если включена мода «почти без потерь», NEAR > 0). MAXVAL и NEAR - параметры, задаваемые приложением, реализующим алгоритм.
  • Инициализируются индексные массивы N , A , B и C . Поясним их предназначение: N используется для хранения частоты вхождения каждого контекста, A — для накопления величины ошибки предсказания, B — для вычисления систематического отклонения, C — для хранения величин корректирования ошибки прогноза.
  • Инициализируются переменные для серийной моды (run mode) RUNindex=0 и J = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9,10,11,12,13,14,15} .
  • Инициализируются две вспомогательные переменные Nn , Nn=0 для кодирования пикселя прерывания серии.

Введем некоторые функции и переменные, которые будут использоваться в дальнейшем:

GetNextSample() Функция: получает информацию о следующем пикселе исходного изображения и устанавливает соответствующие значения переменных x, a, b, c, d, Ix, Ra, Rb, Rc, Rd . Если считанный пиксель лежит в конце строки, то GetNextSample() устанавливает EOLine = 1 . Во всех остальных случаях EOLine = 0 . Значения Ra, Rb, Rc, Rd наследуют свои значения от вычисленного прежде значения Rx . EOLine Глобальная переменная: устанавливается функцией GetNextSample(): равна 1, если текущий пиксель - последний в строке, равна 0 - в противном случае. AppendToBitStream(a,b) Функция: добавляет неотрицательное число в двоичной форме в поток из закодированных битов, используя b бит. Наиболее значимые биты добавляются первыми. Quantize(a) Функция: используется для квантования ошибки предсказания в режиме «почти без потерь». ComputeRx() Функция: возвращает реконструированное значение Rx для текущего пикселя (использует квантованную «ошибку предсказания»).

Из приведенного изображения (рис. 23) ясно, что немалую роль в кодировании пикселя x играют пиксели a, b, c и d. Попробуем разобраться, что происходит, когда эти пиксели отсутствуют. Так при кодировании верхней строки контекстные пиксели с, b и d отсутствуют, поэтому их значения считаются нулевыми. Если текущий пиксель находится в начале или конце строки, то пиксели a, с или d не определены. В этом случае для a и d используется реконструированное значение Rb пикселя b (или нуль для верхней строки), а для c используется реконструированное значение a при кодировании первого символа предыдущей строки. Таким образом, кодер должен выполнить часть работы декодера, реконструируя некоторые пиксели.

Кодер начинает работу со следующих трех шагов:

После установления контекста Q, кодер прогнозирует пиксель х. Сначала производится вычисление прогноза Рх с помощью так называемого «правила края» (edge-detecting predictor):

if (Rc > = max(Ra, Rb)) Px = min(Ra, Rb);
else {
if (Rc <= min(Ra, Rb))
Px= max(Ra, Rb);
else
Px = Ra + Rb - Rc;
}

Поясним суть «правила края». Для этого рассмотрим случай b < а. При этом условии «правило края» выбирает b в качестве прогноза х во многих случаях, когда вертикальный край изображения находится непосредственно слева от х. Аналогично, пиксель а выбирается в качестве прогноза х во многих случаях, когда горизонтальный край находится непосредственно над х. Если край не обнаруживается, то «правило края» вычисляет прогноз в виде а + b - с, что имеет простую геометрическую интерпретацию. Если каждый пиксель является точкой трехмерного пространства, то прогноз а + b - с помещает Рх на ту же плоскость, что и точки а, b и с.

Следующий шаг — корректировка прогноза (prediction correction from the bias) с помощью числа SIGN (зависящего от трех зонных чисел Qi), корректирующих величин C(Q) (выводимых из систематических смещений, и здесь не обсуждаемых) и параметра MAXVAL.

if (SIGN == +1)
Px = Px + C(Q);
else
Px = Px - C(Q);

If (Px > MAXVAL)
Px = MAXVAL;
else if (Px < 0)
Px = 0;

После того, как прогноз Рх найден, кодер вычисляет ошибку прогноза Errval в виде разности х - Рх, но меняет знак, если величина SIGN отрицательная.

В моде почти без потерь ошибка квантуется, и кодер использует это реконструированное значение Rx пикселя х так же, как это будет делать декодер. Основной шаг квантования заключается в следующем:

if (Errval > 0)
Errval = (Errval + NEAR) / (2 * NEAR + 1);
else
Errval = - (Errval - NEAR) / (2 * NEAR + 1);

При этом используется параметр NEAR, однако имеются некоторые детали, которые здесь не приводятся. Основной шаг реконструкции состоит в нахождении Rx = Px + SIGN * Errval * (2 * NEAR + 1) .

Ошибка прогноза (после возможного квантования) претерпевает сокращение области (modulo reduction). (После этого она готова для главного этапа кодирования).

if (Errval < 0)
Errval = Errval + RANGE;
if (Errval >= ((RANGE + 1) / 2))
Errval = Errval - RANGE;

Коды Голомба (основной параметр был обозначен через b). В JPEG-LS этот параметр обозначается m. Если число m уже выбрано, то код Голомба неотрицательного целого числа n состоит из двух частей: унарного кода целой части числа n/m и двоичного представления n mod m . Этот код является идеальным для целых чисел, имеющих геометрическое распределение (то есть, когда вероятность числа n равна (1 - r) * r n , 0 < r < 1) . Для каждого геометрического распределения найдется такое число m, что код Голомба, построенный по m, имеет наименьшую возможную среднюю длину. Простейший случай, когда m равно степени 2 (m = 2 k), приводит к простым операциям кодирования/декодирования. Код числа n состоит в этом случае из k младших разрядов числа n, перед которыми стоит унарный код числа, составленного из остальных старших разрядов числа n. Этот специальный код Голомба обозначается через G(k) .

Для примера вычислим код G(2) числа n = 19 = 10011 2 . Поскольку k = 2, то m = 4. Начнем с двух младших разрядов, 11 2 , числа n. Они равны 3, что то же самое, что n mod m (3 = 19 mod 4) . Оставшиеся старшие разряды, 100 2 дадут число 4, которое равно целой части n/m (19/4 = 4.75). Унарный код 4 равен 00001, значит код G(2) числа n = 19 равен 00001|11.

На практике всегда имеется конечное число неотрицательных целых чисел. Обозначим наибольшее число через I. Наибольшая длина G(0) равна I + 1, а поскольку I может быть велико, желательно лимитировать размер кода Голомба. Это делается с помощью специального кода Голомба LG(k, glimit) , который зависит от двух параметров k и glimit. Сначала следует сформировать число q из самых старших разрядов числа n. Если q < glimit- - 1 , то код LG(k, glimit) совпадает с кодом LG(k]. В противном случае, приготавливается унарный код числа glimit - ceil(log I) - 1 (то есть, glimit - ceil(log I) - 1 нулей, за которыми стоит единственная 1). Это действует как код esc, после которого стоит двоичный код n - 1 из ceil(log I) бит.

Ошибки прогнозов не обязательно являются положительными числами. Они равны некоторым разностям, которые могут быть нулевыми или отрицательными. Однако коды Голомба были построены для положительных чисел. Поэтому перед кодированием отрицательные значения ошибок следует отразить на множество неотрицательных чисел. Для этого используется отображение:
MErrval =
2 * Errval если Errval >= 0,
2 * |Errval| если Errval < 0.

Это отображение перемежает отрицательные и положительные величины в виде последовательности 0, -1, +1, -2, +2, -3,... .

В нижеприведенной таблице перечислены некоторые ошибки прогноза, отображенные значения и их коды LG(2, 32) при условии, что алфавит имеет размер 256 (то есть, I = 255 и ceil(log I) = 8).

Таблица: ошибки прогнозов, отображения и коды LG(2, 32)

Ошибка прогноза Отображенное значение Код
0 0 1 00
-1 1 1 01
1 2 1 10
-2 3 1 11
2 4 01 00
-3 5 01 01
3 6 01 10
-4 7 01 11
4 8 001 00
-5 9 001 01
5 10 001 10
-6 11 001 11
6 12 0001 00
...
50 100 000000000000
000000000001
01100011

Теперь необходимо обсудить выбор параметра k для кодов Голомба. Это делается адаптивно. Параметр k зависит от контекста, и его значение обновляется каждый раз, когда обнаруживается пиксель с этим контекстом. Вычисление k можно выразить простой строкой:
for (k=0; (N[Q]< где А и N - массивы индексов от 0 до 364. В этой формуле используется контекст Q в качестве индекса двух массивов. В начале k инициализируется нулем, а затем совершается цикл. На каждой итерации цикла элемент массива N[Q] сдвигается влево на k разрядов и сравнивается с A[Q]. Если сдвинутое значение N[Q] больше или равно A[Q], то выбирается текущее значение k. В противном случае, k увеличивается на 1, и тест повторяется.

После нахождения числа k, ошибка прогноза Errval преобразуется с помощью в число MErrval, которое кодируется с помощью кода LG(k, LIMIT). Число LIMIT является параметром. Обновление массивов А и N (вместе со вспомогательным массивом B) иллюстрирует следующий фрагмент кода (параметр RESET устанавливается приложением):

B[Q] = B[Q] + Errval * (2 * NEAR + 1);
A[Q] = A[Q] + abs(Errval);
if (N[Q] == RESET) {
A[Q] = A[Q]>>1;
B[Q] = B[Q]>>1;
N[Q] = N[Q]>>1;
}
N[Q] = N[Q] + 1;

Теперь поговорим о просчитывании систематического отклонения прогноза. Значение C[Q], корректирующее прогноз, должно быть обновлено в конце кодирования пикселя x. Для этого необходимы две переменные — B[Q] и N[Q]. N[Q] — это количество вхождений контекста Q с момента инициализации. B[Q] — систематическое отклонение, позволяющее обновлять значение C[Q] как максимум один раз за итерацию. Итак, прогнозирующее значение C[Q] вычисляется в соответствии со следующим кодом:

if (B[Q] <= -N[Q]) {
B[Q] = B[Q] + N[Q];
if (C[Q] > MIN_C)
C[Q] = C[Q] - 1;
if (B[Q] <= -N[Q])
B[Q] = -N[Q] + 1;
}
else if (B[Q] > 0) {
B[Q] = B[Q] - N[Q];
if (C[Q] < MAX_C)
C[Q] = C[Q] + 1;
if (B[Q] > 0)
B[Q] = 0;
}

Константы MIN_C и MAX_C — это минимальное и максимальное возможное значение индексного массива C, равные соответственно -128 и 127.

Кодирование в серийной моде делается иначе. Напомним, что кодер выбирает эту моду, когда обнаруживает последовательные пиксели x, чьи значения Ix совпадают и равны восстановленной величине Ra контекстного пикселя a. Для опции «почти без потерь» пиксели в серии должны иметь значения Ix, которые удовлетворяют неравенству |Ix - Ra| <= NEAR . Серия не должна выходить за пределы текущей строки. Длина серии кодируется (сам пиксель кодировать не нужно, поскольку он равен Ra), и если конец серии находится раньше конца строки, то после ее закодированной длины будет сразу записан код следующего пикселя (который прерывает серию). Две основные задачи кодера в этой моде состоят

  1. в отслеживании серии и кодировании ее длины;
  2. в кодировании пикселя, прервавшего серию.

Отслеживание серии можно проводить следующим образом:

RUNval = Ra;
RUNcnt = 0;
while (abs(Ix - RUNval) <= NEAR) {
RUNcnt = RUNcnt + 1;
Rx = RUNval;
if (EOLine == 1)
break;
else
GetNextSample();
}

Поясним некоторые введенные величины: RUNcnt — это счетчик повторяющихся пикселей (для серийной моды), а RUNval - текущее значение реконструированного повторяющегося пикселя.

Опишем процесс кодирования серий. Первый фрагмент кода описывает кодирование для сегментов серий длины rm:

while (RUNcnt >= (1< AppendToBitStream(1, 1);
RUNcnt = RUNcnt - (1< if (RUNindex < 31))
RUNindex = RUNindex + 1;
}

Следующий же код иллюстрирует кодирование для сегментов серий длины меньше, чем rm:

if (EOLine == 0) {
AppendToBitStream(0, 1);
AppendToBitStream(RUNcnt, J);
if (RUNindex > 0)) {
RUNindex = RUNindex - 1;
}
else if (RUNcnt > 0)
AppendToBitStream(1, 1);

Здесь кодер использует таблицу J, состоящую из 32 записей, обозначаемых rk. J инициализируется величинами
0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 9, 10, 11, 12, 13, 14, 15 .

Для каждого значения rk обозначим rm = 2 rk . Числа rm (их всего 32) называются порядком кода. Первые 4 величины rk имеют rm = 2 0 = 1. Для второй четверки rm = 2 1 = 2, а для следующей четверки rm = 2 2 = 4. Для последнего числа rm = 2 15 = 32768. Кодер выполняет процедуру, описанную , для нахождения длины серии, которая сохраняется в переменной RUNlen . Затем эта переменная кодируется разбиением на слагаемые, величины которых равны последовательным числам rm. Например, если RUNlen=6 , то его представляют в виде 6 = 1 + 1 + 1 + 1 + 2 с помощью первых пяти чисел rm. Оно кодируется с помощью 5 бит. Запись производится инструкцией AppendToBitStream(l,l) . Каждый раз, когда пишется 1, соответствующая величина rm вычитается из RUNlen . Если RUNlen было равно в начале 6, то она последовательно уменьшается до 5, 4, 3, 2 и 0.

Может случиться, что длина RUNlen серии не равна целой сумме чисел rm. Например, RUNlen = 7 . В этом случае в качестве кода записывается пять битов 1, за которыми следует префиксный бит и остаток от RUNlen (в нашем примере это 1), который запишется в файл в виде числа из rk бит (текущее значение rk из нашего примера равно 2). Эта последняя операция выполняется вызовом процедуры AppendToBitStream (RUNcnt, J) . Префиксным битом служит 0, если серия прерывается в строке другим пикселем. Если же серия идет до конца строки, то префиксный бит равен 1.

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

Рассмотрим ситуацию, когда ход кодирования прерван концом строки пикселей: как будет кодироваться новый пиксель, вызывающий прерывание? Этот вопрос решается кодированием разницы между значением Ix в текущей позиции x и реконструированным значением пикселей a или b (напомним, что это соседние пиксели по отношению к x - см. рис. 23). В этом случае рассматриваются две различные ситуации: первая, когда abs(Ra - Rb) <= NEAR , вторая - в противном случае. По сути кодирование пикселя прерывания серии происходит теми же методами, что и кодирование нового пикселя в регулярной моде с тем лишь дополнением, что Ix должно отличаться от Ra на величину большую NEAR, иначе ход кодирования будет продолжен. Опишем операции, которые должны быть выполнены:

if (abs(Ra - Rb) <= NEAR)
RItype = 1;
else
RItype = 0;
if (RItype == 1)
Px = Ra;
else
Px = Rb;
Errval = Ix - Rb;

Фрагмент кода выше определяет индекс RItype и ошибку предсказания для пикселя x. Затем следует в случае необходимости изменить знак Errval, а для опции «почти без потерь» также провести квантование ошибки предсказания:

if ((RItype == 0) && (Ra > Rb)) {
Errval = -Errval;
SIGN = -1;
else
SIGN = 1;
if (NEAR > 0) {
Errval = Quantize(Errval);
Rx = ComputeRx();
}
else
Rx = Ix;
Errval = ModRange(Errval, RANGE);

Теперь вычислим вспомогательную переменную TEMP, которая будет использоваться для вычисления параметра k в кодах Голомба.

if (RItype == 0)
TEMP = A;
else
TEMP = A + (N>>1);

Установим Q = RItype + 365 . Параметр k для кодов Голомба будем вычислять следующим образом: for (k=0; (N[Q]<

if (Errval < 0) {
Nn[Q] = Nn[Q] + 1;
A[Q] = A[Q] + ((EMErrval + 1 -RItype)>>1);
if (N[Q] == RESET) {
A[Q] = A[Q]>>1;
N[Q] = N[Q]>>1;
Nn[Q] = Nn[Q]>>1;
}
N[Q] = N[Q] + 1;

На этом и завершим описание кодера JPEG-LS. Отметим, что оно, безусловно, неполное, но мы и не ставили перед собой цели — скопировать стандарт этого метода. Все опущенные детали вы сможете найти в стандарте. Сейчас же перейдем к краткому описанию принципов работы декодера.

3.3. Декодер

Как упоминалось ранее, метод JPEG-LS почти симметричный, поэтому копировать с небольшими изменениями описание кодера мы не будем — эту информацию можно прочитать и в стандарте. Остановимся лишь на том, как происходит декодирование в серийной моде. После того, как вычислены все величины для текущего пикселя, считывается новый бит R из потока битов. Если он равен 1, то:

  1. Изображение дополняется 2 J|RUNindex| пикселями со значением Ra.
  2. Если на предыдущем шаге изображение уже было дополнено 2 J|RUNindex| пикселями и RUNindex < 31, то RUNindex увеличивается на 1. Если последний пиксель в строке ещё не декодирован, то мы снова считываем биты, в противном случае переходим к вычислению всех требуемых величин.

Если же бит равен 0, то:

  1. Считывается J|RUNindex| бит из битового потока и преобразовывается в число, а изображение дополняется пикселями со значениями Ra в количестве, соответствующем вычисленному числу.
  2. Если RUNindex > 0, то RUNindex уменьшается на 1.
  3. Декодируется пиксель прерывания серии и снова начинается вычисление всех необходимых величин.

3.4. Формат файла

Сжатый файл состоит:

  • из сегментов данных, содержащих коды Голомба и длины серий;
  • из сегментов маркеров (информация необходимая декодеру);
  • из сегмента «остальных» маркеров (некоторые зарезервированные маркеры JPEG).

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

3.5. Коды Голомба

Мы уже не раз упоминали коды Голомба. Что же это такое? Код Голомба неотрицательного целого числа «может быть эффективным кодом Хаффмана». Он зависит от выбора некоторого параметра b. Принцип кодирования таков:

  • вычисляются две величины
    q = floor((n - 1) / b) и
    r = n - qb - 1 ;
  • происходит построение кода из двух частей: первая часть — q в унарном коде, вторая часть — двоичное выражение для r , состоящее из floor(log 2 b) бит для малых остатков и из ceil(log 2 b) бит для больших.

Мы не приводим математическое обоснование использования кодов Голомба в JPEG-LS, отметим лишь, что, если входной поток данных состоит из целых чисел, причем вероятность числа n равна P(n) = (1 - p) n - 1 p (0 <= p <= 1) , то коды Голомба будут оптимальными кодами для этого потока данных, если выбрать параметр b следующим образом:
(1 - p) b + (1 - p) b + 1 <= 1 <= (1 - p) b - 1 + (1 - p) b .

3.6. Заключение

Формат JPEG-LS разрабатывался, прежде всего, для хранения изображений в медицинских целях, то есть для тех случаев, когда важно иметь большое изображение без малейших потерь качества. Как уже говорилось, за основу был взят формат LOCO-I, разработанный в стенах «HP Labs». Затем он был доработан совместными усилиями «HP» и «Mitsubishi». Обе компании разрешили использовать их патенты на этот формат без оплаты лицензии, поэтому JPEG-LS можно встретить и в обычных программах для PC.

Поясню на собственном примере. Может быть и поможете мне в понимании некоторых вещей. Задача поставленная передо мной самим собой следующая. Передать кадр (по команде) из WEB камеры в память сотового телефона с последующей передачей на другой сотовый. Из Вашей статьи не понятно, на какой формат следует забазироваться, доступность алгоритма. Далее - сосинусное преобразование - только поверхностное толкование, а где посмотреть детальный алгоритм с конкретным примером (скажете учи мат. анализ, но и там почти нет конкретных примеров, а если есть, то пропущены целые куски расчетов. Может есть конкретная методичка, так сошлитесь. Структуру организации файла вообще выкинули и даже ссылок не указали. "В получаемой матрице низкочастотные компоненты расположены ближе к левому верхнему углу, а более высокочастотные смещаются вправо вниз", мне кажется, что она так делается, а не получается (может ошибаюсь!).

Вопрос: как из JPG кадра отловить например только нужную информацию для дальнейшего декодирования в разрешении экрана телефона, не применяя PC, используя МК. Достаточно черно-белого варианта кадра. На какие FFxx надо обратить внимание и записать только ту информацию. Где взять структуру кадра WEB камеры. Я понимаю, что вопрос сложен, многопланов. Что например на МК не сделать расшифровку кадра и сжать затем с нужным разрешением, но вот вырезать хотя-бы верхний угол с нужным форматом это наверное можно.

Буду благодарен за информацию.

Что умею = программировать на VB, МК. Самостоятельная действующая интерактивная разработка управлением по сот.телефону несколькими реле, аудиоконтроль с использованием сотового телефона.

>> Вторым шагом является непосредственно применение >>алгоритма кодирования повторов (LZW)

может, RLE?

Разумеется, на этом шаге JPEG (см. контект), — RLE. Спасибо за обнаружение погрешности.

Старый добрый JPEG, несмотря на массу неоспоримых достоинств, все же имеет и существенные ограничения. Снять их был призван новый метод сжатия изображений, разработки которого велись уже давно. Теперь, когда JPEG2000 стал официально признанным форматом, это должно послужить началу его активной поддержки различными производителями ПО.

Наверняка многих работающих с графикой на компьютере интересует вопрос: а как удается изображение, занимающее весьма впечатляющий объем в памяти ПК, втиснуть в гораздо меньший размер на диске? Помнится, на заре своей издательской деятельности слово «компрессия» для меня было таким загадочным и удивительным… В самом деле, каким образом происходит сжатие изображений — ведь без него сейчас немыслимо представить ни Сеть, ни цифровую фотографию, ни цветную полиграфию?

Итак, сжатие. Оно может как приводить к потере качества, так и не приводить. Последний случай — это такие методы, как RLE (Run Length Encoding, кодирование длин серий, в результате которого образуются пары типа (skip , value , где skip — это число подряд идущих нулей, а value — следующее за ними значение) и LZW (компрессия методом Lempel-Ziff-Welch), реализованные в форматах PSD, GIF и TIFF. Широко используются они и архиваторами типа RAR и ZIP. Средняя степень компрессии сжатия без потерь — 2-3 раза.

Если нужно сжать изображение сильнее, без потери качества не обойтись. Каковы принципы? Во-первых, любое изображение содержит определенную избыточность, удаление которой не приведет к заметному изменению качества картинки. Во-вторых, человеческий глаз более восприимчив к изменениям яркости, нежели цвета. Поэтому для разных каналов изображения применяются различные степени сжатия — информация теряется, но визуально это не заметно. Кроме того, чувствительность глаза к мелким элементам изображения невелика, что позволяет без ущерба для качества их удалить. Так можно сжимать изображение (даже если ухудшение качества становится уже заметным) вплоть до приемлемого порога. Степень деградации качества определяется для каждого конкретного случая. Для полиграфии допустимы лишь минимальные искажения, а для размещения в Интернете (в зависимости от предназначения) — гораздо большие.

Наибольшую популярность среди методов компрессии с потерями получил JPEG, который даже при тридцатикратном сжатии сохраняет достаточное качество картинки. Кстати, в большинстве современных методов сжатия данных (например, Layer-4, известный как mp3, а также MPEG) реализованы механизмы, аналогичные JPEG. Давайте познакомимся поближе с этим форматом, тем более что не так давно была окончательно утверждена его новейшая реализация JPEG2000, в которую вошли все дополнения, внесенные в JPEG/MPEG за десять лет его развития.

JPEG

Название алгоритма компрессии — аббревиатура от Joint Photographic Expert Group, инициативной группы, образованной из экспертов ITU (International Telecommunication Union) и ISO (International Organization for Standartization). Именно поэтому в ее названии присутствует приставка Joint. В 1992 г. JPEG был объявлен международным стандартом в области графических изображений.

При компрессии методом JPEG качество теряется всегда. При этом всегда есть выбор: отдать предпочтение качеству в ущерб объему (размер файла сожмется приблизительно в три раза) или же наоборот, добиться минимального размера изображения, при котором оно еще останется узнаваемым (степень компрессии может достигать 100). Сжатие, при котором различие в качестве между получающимся изображением и оригиналом еще остается незаметным, дает 10-20-кратное сокращение размера файла.

Область применения

JPEG лучше всего компрессирует полноцветные и монохромные изображения фотографического качества. Если же требуется сохранить картинку с индексной палитрой, то сначала она конвертируется в полноцветную. При компрессии методом JPEG нужно иметь в виду, что все зависит от характера изображений: гораздо меньший объем будут занимать те, где изменения цвета незначительны и нет резких цветовых переходов. JPEG применяется всюду, где нужно хранить фотоизображения: в цифровых фотоаппаратах, полиграфии (EPS DCS 2.0), немыслим без него и Интернет.

Существует несколько разновидностей JPEG-компрессии, мы же рассмотрим только две из них, использующиеся в стандартном пакете для работы с растровыми изображениями Adobe Photoshop, — baseline и progressive . Два других способа — ariphmetic и loseless — экзотика, в силу ряда причин не получившая широкого распространения.

Как происходит сжатие

1. Первый этап заключается в конвертировании цветовой модели изображения (обычно RGB) в модель, где яркостная и цветовая составляющие разнесены (например, YCbCr или YUV), что позволяет оптимально подойти к выбору степеней компрессии для каждого канала (с учетом особенностей восприятия глазом). Преобразование происходит следующим образом:

Y = 0,299xR+0,587*G+0,114xB Cb = (B-Y)/0,866/2+128 Cr = (R-Y)/0,701/2+128

2. На следующем этапе происходит т. н. префильтрация , при которой соседние пиксели отдельно в каждом из каналов Cb и Cr группируются попарно в горизонтальном и вертикальном направлениях, а яркостный канал Y оставляется без изменений. После этого вся группа из четырех пикселов получает усредненное значение соответствующих компонент Cb и Cr. Для краткости такую схему можно обозначить как 4:1:1 (такая же форма представления принята в DRAW — окно экспорта в jpeg). С учетом того, что каждый пиксел кодируется 3 байтами (по 256 уровней для каждого из трех каналов), в результате объем данных автоматически сокращается в 2 раза (вместо 12 байт для передачи 4 пикселов достаточно передать всего 4+1+1 = 6 байт). С точки зрения математики такое преобразование приводит к существенной потере информации, но человеческий глаз потери не воспринимает, поскольку в обычных фотографических изображениях присутствует существенная избыточность.

3. Полученная информация, прошедшая стадию первичной «очистки», отдельно в каждом канале снова группируется в блоки, но уже размером 8x8, после чего для них применяется основное сжатие — т. н. дискретное косинусное преобразование , для краткости — DCT (discrete cosine transform). В результате информация о распределении яркости пикселов преобразуется в другой вид, где она описывается распределением, основанном на частоте появления той или иной яркости пикселов. DCT имеет ряд преимуществ перед другими преобразованиями (например, перед преобразованием Фурье), обеспечивая лучшее восстановление информации.

Вместо массива из 64 значений (8x8 пикселов) для каждого блока, из которых состоит изображение, мы получаем массив из 64 частот. Рассмотрим работу DCT на примере. Допустим, яркость пикселов в одном блоке нашего изображения имеет вид, представленный на рис. 1 слева, тогда результат преобразования будет таким, как показано справа.

1

Несмотря на значительную точность, некоторая потеря информации на данном этапе все же происходит — именно поэтому JPEG всегда приводит к потере качества. Основная цель преобразования — выяснить общую картину распределения крупных (на рисунке — сверху слева) и мелких (внизу справа) объектов, что пригодится потом, при устранении малозначимой информации.

4. Следующий этап — удаление малозаметной глазу информации из блока, или квантование (quantization). Все составляющие делятся на различные коэффициенты, определяющие значимость каждой из них для качественного восстановления исходного изображения, и результат округляется до целого значения. Именно эта процедура вносит наибольшие потери качества, снижая конечный объем изображения. Высокочастотные составляющие квантуются грубо, а низкочастотные — точнее, поскольку наиболее заметны. Дабы несколько сгладить понижение качества, в канале яркости используются меньшие коэффициенты деления, чем в каналах цветности. Но чаще (это делается для ускорения расчетов) вместо специально подобранных значений берется всего одно — то, которое вводит пользователь при выборе степени компрессии.

Вот, например, как выглядит окно Photoshop при сохранении изображения c помощью операции Save for web, где параметр Quality (вернее, производная от него) — тот самый коэффициент округления (рис. 2).

В результате квантования получается набор составляющих, по которым исходное изображение восстанавливается с заданной точностью (рис. 3).

4

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

5. После выполнения основной работы по сжатию изображения дальнейшие преобразования сводятся к второстепенным задачам: оставшиеся составляющие собираются в последовательность таким образом, чтобы сначала располагались отвечающие за крупные детали, а потом — за все более мелкие. Если посмотреть на рисунок, то движение кодировщика похоже на зигзагообразную линию. Этап так и называется — ZigZag (рис. 5).

5

Затем получившаяся последовательность сжимается: сначала обычным RLE, затем методом Хаффмана.

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

Вот, в общем, и все преобразования. А теперь давайте подсчитаем, какая компрессия была достигнута в нашем примере. Мы получили 7 значений, по которым восстановится первоначальное изображение размером 8x8. Итак, компрессия от применения DCT-преобразования в обоих каналах цветности составила 8x8/7 ≈ 9 раз. Отведем на канал яркости не семь, а 11 коэффициентов, что даст 8x8/11 ≈ 6. Для всех трех каналов получится (9+9+6)/3=8 раз. Снижение качества при «прореживании» изображения, произошедшего на второй стадии, дает дополнительно двойной прирост (схема 4-1-1, учитывающая особенности кодирования яркостной составляющей), что даст итоговый результат — 16 раз. Это грубый подсчет, не учитывающий некоторых аспектов, но отражающий реальную картину. Чтобы получить тридцатикратное сокращение размера файла, нужно оставить всего 3-4 составляющие.

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

Недостатки JPEG

  1. Невозможность достичь высоких степеней сжатия за счет ограничения на размер блока (только 8x8).
  2. Блочность структуры на высоких степенях компрессии.
  3. Закругление острых углов и размывание тонких элементов в изображении.
  4. Поддерживаются только RGB-изображения (использовать JPEG для CMYK-изображений можно только в формате EPS через DCS).
  5. Изображение нельзя отобразить до тех пор, пока оно не загрузится полностью.

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

JPEG2000

С 1997 г. были начаты работы, направленные на создание универсальной системы кодирования, которая снимала бы все ограничения, накладываемые JPEG, и могла эффективно работать со всеми типами изображений: черно-белыми, в градациях серого, полноцветными и многокомпонентными, причем независимо от содержания (будут ли это фотографии, достаточно мелкий текст или даже чертежи). В его разработке принимали участие наряду с международными стандартизирующими организациями такие гранды промышленности, как Agfa, Canon, Fujifilm, Hewlett-Packard, Kodak, LuraTech, Motorola, Ricoh, Sony и др.

Поскольку новый алгоритм претендовал на универсальный, ему дополнительно ставилась задача использования различных способов передачи данных (в реальном режиме времени и при узкой полосе пропускания), что особенно критично в мультимедийных приложениях, например, в реал-трансляциях через Интернет.

Основные требования, предъявляемые к формату JPEG2000:

  1. Достижение повышенной по сравнению с JPEG степени компрессии.
  2. Поддержка монохромных изображений, что позволит применять его для компрессии изображений с текстом.
  3. Возможность сжатия вообще без потерь.
  4. Вывод изображений с постепенным улучшением детализации (как в progressive GIF).
  5. Использование в изображении приоритетных областей, для которых качество может устанавливаться выше, чем в остальной части изображения.
  6. Декодирование в реальном режиме времени (без задержек).

Принцип сжатия

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

6
Сначала точно так же, как и для JPEG, происходит конвертирование изображения в систему YCrCb, после чего — первичное удаление избыточной информации (путем уже известного объединения соседних пикселей в блоки 2x2). Затем все изображение делится на части одинакового размера (tile), над каждой из которых независимо от других и будут происходить дальнейшие преобразования (это снижает требования к объему памяти и вычислительным ресурсам). Далее каждый канал проходит фильтрацию низкочастотным и высокочастотным фильтрами отдельно по строкам и по рядам, в результате чего после первого прохода в каждой части формируются четыре более мелких изображения (subband). Все они несут информацию об исходном изображении, но их информативность сильно отличается (рис. 6).

Например, изображение, полученное после низкочастотной фильтрации по строкам и рядам (вверху слева), несет наибольшее количество информации, а полученное после высокочастотной — минимальное. Информативность у изображений, полученных после НЧ-фильтрации строк и ВЧ для столбцов (и наоборот), средняя. Наиболее информативное изображение опять подвергается фильтрации, а полученные составляющие, как и при jpeg-компрессии, квантуются. Так происходит несколько раз: для сжатия без потерь цикл обычно повторяется 3 раза, с потерями — разумным компромиссом между размером, качеством и скоростью декомпрессии считается 10 итераций. В результате получается одно маленькое изображение и набор картинок с мелкими деталями, последовательно и с определенной точностью восстанавливающих его до нормального размера. Очевидно, что наибольшая степень компрессии получается на крупных изображениях, поскольку можно установить большее количество циклов.

Практическая реализация

С тех пор, как были заложены основы компрессии методом JPEG2000, ряд компаний разработал достаточно эффективные алгоритмы ее реализации.

Среди крупных разработчиков ПО можно отметить Corel (кстати, она одна из первых внедрила в свои пакеты поддержку формата wi, основанного на волновых преобразованиях, за что ей честь и хвала) — все изображения, поставляемые на компакт-дисках с пакетом CorelDRAW вплоть до девятой версии, сжимались именно таким способом.

Позже к ней подтянулась и Adobe. Часть идей, заложенных в JPEG2000, была применена разработчиками Photoshop 6 в виде продвинутых опций при сохранении изображения в формате JPEG (обычном, основанном на косинусном преобразовании). Среди них — прогрессивный JPEG (параметр Progressive в окне Save for Web). Этот алгоритм предназначен, главным образом, для систем реального времени и работает точно так же, как и прогрессивный GIF. Сначала появляется грубая копия изображения, состоящая всего из нескольких блоков большого размера, а со временем, когда подгружаются остальные данные, структура начинает просматриваться все четче, пока, наконец, конечное изображение не восстановится полностью. В отличие от GIF, такой алгоритм создает большую нагрузку на просмотрщик, поскольку ему придется полностью выполнять весь цикл преобразований для каждой передаваемой версии.

Из других дополнений отметим включение в файл нескольких JPEG-сжатых изображений с разной степенью компрессии, разрешением и даже цветовыми моделями. Соответственно, в Photoshop 6 появилась возможность выделять в изображении отдельные области и применять для них другие установки компрессии (Region-Of-Interest , впервые такой механизм был предложен еще в 1995 г.), используя более низкие значения в таблице квантования. Для этого задается требуемая область (например, в виде нового канала в изображении) и нажимается пиктограмма маски возле пункта Quality (Качество). В появившемся окне можно экспериментировать с изображением, передвигая ползунки, — готовый результат отображается на экране, позволяя быстро находить необходимый компромисс между качеством и размером.

Специализированные конверторы и просмотрщики

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

Специализированные решения от других компаний доступны в виде коммерческих разработок. Одни реализованы в виде отдельных программ (JPEG 2000 разработки Aware), другие — в виде дополнительных модулей для наиболее распространенных растровых редакторов (ImagePress JPEG2000 разработки Pegasus Imaging и модуль LEAD JPEG2000 от LEAD Technologies). На их фоне выделяется компания LuraTech, давно занимающаяся этим вопросом. Она продвигает свою технологию LuraWave в самодостаточном продукте LuraWave SmartCompress (доступна уже третья версия) и предлагает модули для Photoshop, Paintshop, Photopaint. Отличительная особенность — более высокая скорость работы (практически мгновенное преобразование) даже с картинками размером в несколько мегабайт. Соответственно и цена этого модуля самая высокая — 79 долл.

Чтобы просматривать JPEG2000-изображения браузерами, необходимо установить специальный модуль-просмотрщик (все разработчики предлагают его бесплатно). Вставка изображения в html-документ, как и любого plug-in, сводится к использованию конструкции EMBED (с дополнительными параметрами). Например, означает, что будет использоваться прогрессивный метод переда- чи изображения. То есть в нашем примере (файл размером 139 Кбайт) сначала передаются только 250 байт, на основании которых будет построено грубое изображение, затем, после дозагрузки 500 байт, изображение обновляется (так продолжается до достижения значения LIMIT).

Если вы захотите получить более качественное изображение, нужно выбрать пункт Improve из меню, всплывающего по правой кнопке (рис. 9). За четыре докачки все изображение будет загружено полностью.

9

Выводы

Итак, JPEG2000 объективно показывает лучшие результаты, чем JPEG только на высоких степенях сжатия. При компрессии в 10-20 раз особой разницы не заметно. Сможет ли он вытеснить или просто составить конкуренцию широко распространенному формату? В ближайшее время — вряд ли, в большинстве случаев соотношение качество/размер, обеспечиваемое JPEG, вполне приемлемо. А те 10-20% дополнительной компрессии, которые дает JPEG2000 при визуально одинаковом качестве, вряд ли приведут к росту его популярности.

Зато к новому формату проявляют пристальный интерес компании-производители цифро- вых камер, поскольку размеры светочувствительных матриц с каждым годом неуклонно увеличиваются, и помещать изображения в память становится все труднее. И вот тогда новый формат получит большее распространение, и кто знает, возможно, через какое-то время JPEG2000 сравняется с JPEG. Во всяком случае, Analog Micro Devices недавно выпустила специализированный чип, в котором компрессия/декомпрессия по новой технологии реализованы на аппаратном уровне, а министерство обороны США уже сейчас активно использует новый формат для записи фотоснимков, полученных со спутников-шпионов.

Факты и домыслы

1. JPEG теряет качество при открытии и повторном сохранении файла.

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

2. JPEG теряет качество при редактировании файла.

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

3. Результат компрессии с одинаковыми параметрами в разных программах будет одинаков.

Неправда. Разные программы по-разному трактуют вводимые пользователем значения. Например, в одной программе указывается качество сохраняемого изображения (как, например, в Photoshop), в другой — степень его компрессии (обратная величина).

4. При установке максимального качества изображение сохраняется без каких-либо потерь качества.

Неправда. JPEG сжимает с потерями всегда. Но установка, например, 90% качества вместо 100% дает сокращение размера файла большее, чем воспринимаемое глазом ухудшение качества.

5. Любой файл JPEG можно открыть в любом редакторе, понимающем формат JPEG.

Неправда. Такую разновидность JPEG, как прогрессивный (progressive JPEG), некоторые редакторы не понимают.

6. JPEG не поддерживает прозрачность.

Правда. Иногда может казаться, что какая-то часть изображения прозрачна, но на самом деле ее цвет просто подобран так, чтобы он совпадал с цветом фона в html-странице.

7. JPEG сжимает лучше, чем GIF.

Неправда. У них разная область применения. В общем случае, типичная «гифовская» картинка после конвертирования в JPEG будет иметь больший объем.

JPEG2000 против JPEG

7
1. При двадцати-тридцатикратном сжатии JPEG2000 и JPEG дают приблизительно одинаковое качество (кстати говоря, Photoshop не может сжать обычную фотографию больше этого предела).

2. При большем сжатии качество JPEG2000 существенно выше, чем у JPEG, что позволяет без особых потерь сжимать до 50 раз, а с некоторыми потерями (речь идет об изображениях для Интернет) — до 100 и даже до 200.

3. При больших степенях компрессии в тех областях, где происходит плавное изменение цвета, изображение не приобретает характерную для простого JPEG блочную структуру. JPEG2000 также несколько размазывает и закругляет острые контуры — см. фотографии (рис. 7 и 8).

На нем представлены результаты компрессии тестового файла с разными степенями компрессии (слева — сохраненные в Photoshop в формате JPG, справа — в формате JPEG2000). Для изображения на рис. 7 были выбраны степени компрессии 20, 40, 70 и 145 (их можно явно указывать при сохранении в JPEG2000), степень сжатия JPG выбиралась из того расчета, чтобы размер файла был таким же, как после сжатия по JPEG2000. Как говорится, результаты налицо. Для чистоты был проведен второй эксперимент на изображении с более четкими деталями (со степенями компрессии 10, 20, 40 и 80). Преимущество опять же на стороне JPEG2000 (рис. 8).

8

4. Поскольку, по сути, в одном JPEG2000-файле хранятся копии с разным разрешени

ем, для тех, кто делает галереи изображений в Интернете, отпадает необходимость создавать для них thumbnails.

5. Особый интерес представляет компрессия без искажений (режим loseless). Так, тестовый файл при LZW-сжатии из Photoshop занял 827 Кбайт, а сжатый JPEG2000 — 473 Кбайт.

6. По сравнению с JPEG его более продвинутый тезка потребляет значительно больше системных ресурсов. Но существенно возросшая за последние пару лет мощь компьютеров позволяет успешно решать задачи сжатия изображений новым методом.

7. Отсутствие поддержки JPEG2000 в браузерах. Чтобы просматривать такие изображения, нужно скачать довольно большой дополнительный модуль (1,2 Мбайта).

8. Отсутствие бесплатного ПО для сохранения изображений в новом формате.

Журналов в свободном доступе.

На ту же тему:


Проблемы алгоритмов архивации с потерями

Первыми для архивации изображений стали применяться привычные алгоритмы. Те, что использовались и используются в системах резервного копирования, при создании дистрибутивов и т.п. Эти алгоритмы архивировали информацию без изменений. Однако основной тенденцией в последнее время стало использование новых классов изображений. Старые алгоритмы перестали удовлетворять требованиям, предъявляемым к архивации. Многие изображения практически не сжимались, хотя “на взгляд” обладали явной избыточностью. Это привело к созданию нового типа алгоритмов - сжимающих с потерей информации. Как правило, коэффициент архивации и, следовательно, степень потерь качества в них можно задавать. При этом достигается компромисс между размером и качеством изображений.

Одна из серьезных проблем машинной графики заключается в том, что до сих пор не найден адекватный критерий оценки потерь качества изображения. А теряется оно постоянно - при оцифровке, при переводе в ограниченную палитру цветов, при переводе в другую систему цветопредставления для печати, и, что для нас особенно важно, при архивации с потерями. Можно привести пример простого критерия: среднеквадратичное отклонение значений пикселов (L 2 мера, или root mean square - RMS):

По нему изображение будет сильно испорчено при понижении яркости всего на 5% (глаз этого не заметит - у разных мониторов настройка яркости варьируется гораздо сильнее). В то же время изображения со “снегом” - резким изменением цвета отдельных точек, слабыми полосами или “муаром” будут признаны “почти не изменившимися” (Объясните, почему?). Свои неприятные стороны есть и у других критериев.

Рассмотрим, например, максимальное отклонение:

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

Мера, которую сейчас используют на практике, называется мерой отношения сигнала к шуму (peak-to-peak signal-to-noise ratio - PSNR).

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

Лучше всего потери качества изображений оценивают наши глаза. Отличной считается архивация, при которой невозможно на глаз различить первоначальное и разархивированное изображения. Хорошей - когда сказать, какое из изображений подвергалось архивации, можно только сравнивая две находящихся рядом картинки. При дальнейшем увеличении степени сжатия, как правило, становятся заметны побочные эффекты, характерные для данного алгоритма. На практике, даже при отличном сохранении качества, в изображение могут быть внесены регулярные специфические изменения. Поэтому алгоритмы архивации с потерями не рекомендуется использовать при сжатии изображений, которые в дальнейшем собираются либо печатать с высоким качеством, либо обрабатывать программами распознавания образов. Неприятные эффекты с такими изображениями, как мы уже говорили, могут возникнуть даже при простом масштабировании изображения. Алгоритм JPEG

JPEG - один из самых новых и достаточно мощных алгоритмов. Практически он является стандартом де-факто для полноцветных изображений . Оперирует алгоритм областями 8х8, на которых яркость и цвет меняются сравнительно плавно. Вследствие этого, при разложении матрицы такой области в двойной ряд по косинусам (см. формулы ниже) значимыми оказываются только первые коэффициенты. Таким образом, сжатие в JPEG осуществляется за счет плавности изменения цветов в изображении.

Алгоритм разработан группой экспертов в области фотографии специально для сжатия 24-битных изображений. JPEG - Joint Photographic Expert Group - подразделение в рамках ISO - Международной организации по стандартизации. Название алгоритма читается ["jei"peg]. В целом алгоритм основан на дискретном косинусоидальном преобразовании (в дальнейшем ДКП), применяемом к матрице изображения для получения некоторой новой матрицы коэффициентов. Для получения исходного изображения применяется обратное преобразование.

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

Для этого используется квантование коэффициентов (quantization). В самом простом случае - это арифметический побитовый сдвиг вправо. При этом преобразовании теряется часть информации, но могут достигаться большие коэффициенты сжатия.

Как работает алгоритм

Итак, рассмотрим алгоритм подробнее. Пусть мы сжимаем 24-битное изображение.

Шаг 1.

Переводим изображение из цветового пространства RGB, с компонентами, отвечающими за красную (Red), зеленую (Green) и синюю (Blue) составляющие цвета точки, в цветовое пространство YCrCb (иногда называют YUV).

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

Упрощенно перевод из цветового пространства RGB в цветовое пространство YCrCb можно представить с помощью матрицы перехода:

Обратное преобразование осуществляется умножением вектора YUV на обратную матрицу.

Шаг 2.

Разбиваем исходное изображение на матрицы 8х8. Формируем из каждой три рабочие матрицы ДКП - по 8 бит отдельно для каждой компоненты. При больших коэффициентах сжатия этот шаг может выполняться чуть сложнее. Изображение делится по компоненте Y - как и в первом случае, а для компонент Cr и Cb матрицы набираются через строчку и через столбец. Т.е. из исходной матрицы размером 16x16 получается только одна рабочая матрица ДКП. При этом, как нетрудно заметить, мы теряем 3/4 полезной информации о цветовых составляющих изображения и получаем сразу сжатие в два раза. Мы можем поступать так благодаря работе в пространстве YCrCb. На результирующем RGB изображении, как показала практика, это сказывается несильно.

Шаг 3.

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

В упрощенном виде это преобразование можно представить так:

Шаг 4.

Производим квантование. В принципе, это просто деление рабочей матрицы на матрицу квантования поэлементно. Для каждой компоненты (Y, U и V), в общем случае, задается своя матрица квантования q (далее МК). На этом шаге осуществляется управление степенью сжатия, и происходят самые большие потери. Понятно, что, задавая МК с большими коэффициентами, мы получим больше нулей и, следовательно, большую степень сжатия.

С квантованием связаны и специфические эффекты алгоритма. При больших значениях коэффициента gamma потери в низких частотах могут быть настолько велики, что изображение распадется на квадраты 8х8. Потери в высоких частотах могут проявиться в так называемом “эффекте Гиббса”, когда вокруг контуров с резким переходом цвета образуется своеобразный “нимб”.

Шаг 5 .

Переводим матрицу 8x8 в 64-элементный вектор при помощи “зигзаг”-сканирования, т.е. берем элементы с индексами (0,0), (0,1), (1,0), (2,0)...

Таким образом, в начале вектора мы получаем коэффициенты матрицы, соответствующие низким частотам, а в конце - высоким.

Шаг 6.

Свертываем вектор с помощью алгоритма группового кодирования. При этом получаем пары типа (пропустить, число), где “пропустить” является счетчиком пропускаемых нулей, а “число” - значение, которое необходимо поставить в следующую ячейку. Так, вектор 42 3 0 0 0 -2 0 0 0 0 1 ... будет свернут в пары (0,42) (0,3) (3,-2) (4,1) ... .

Шаг 7.

Свертываем получившиеся пары кодированием по Хаффману с фиксированной таблицей.

Процесс восстановления изображения в этом алгоритме полностью симметричен. Метод позволяет сжимать некоторые изображения в 10-15 раз без серьезных потерь.


Конвейер операций, используемый в алгоритме JPEG.

Существенными положительными сторонами алгоритма является то, что:

  1. Задается степень сжатия.
  2. Выходное цветное изображение может иметь 24 бита на точку.
Отрицательными сторонами алгоритма является то, что:
  1. При повышении степени сжатия изображение распадается на отдельные квадраты (8x8). Это связано с тем, что происходят большие потери в низких частотах при квантовании, и восстановить исходные данные становится невозможно.
  2. Проявляется эффект Гиббса - ореолы по границам резких переходов цветов.
Как уже говорилось, стандартизован JPEG относительно недавно - в 1991 году. Но уже тогда существовали алгоритмы, сжимающие сильнее при меньших потерях качества. Дело в том, что действия разработчиков стандарта были ограничены мощностью существовавшей на тот момент техники. То есть даже на персональном компьютере алгоритм должен был работать меньше минуты на среднем изображении, а его аппаратная реализация должна быть относительно простой и дешевой. Алгоритм должен был быть симметричным (время разархивации примерно равно времени архивации).

Последнее требование сделало возможным появление таких игрушек, как цифровые фотоаппараты - устройства, размером с небольшую видеокамеру, снимающие 24-битовые фотографии на 10-20 Мб флэш карту с интерфейсом PCMCIA. Потом эта карта вставляется в разъем на вашем лэптопе и соответствующая программа позволяет считать изображения. Не правда ли, если бы алгоритм был несимметричен, было бы неприятно долго ждать, пока аппарат “перезарядится” - сожмет изображение.

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

Широкое применение JPEG долгое время сдерживалось, пожалуй, лишь тем, что он оперирует 24-битными изображениями. Поэтому для того, чтобы с приемлемым качеством посмотреть картинку на обычном мониторе в 256-цветной палитре, требовалось применение соответствующих алгоритмов и, следовательно, определенное время. В приложениях, ориентированных на придирчивого пользователя, таких, например, как игры, подобные задержки неприемлемы. Кроме того, если имеющиеся у вас изображения, допустим, в 8-битном формате GIF перевести в 24-битный JPEG, а потом обратно в GIF для просмотра, то потеря качества произойдет дважды при обоих преобразованиях. Тем не менее, выигрыш в размерах архивов зачастую настолько велик (в 3-20 раз!), а потери качества настолько малы, что хранение изображений в JPEG оказывается очень эффективным.

Несколько слов необходимо сказать о модификациях этого алгоритма. Хотя JPEG и является стандартом ISO, формат его файлов не был зафиксирован. Пользуясь этим, производители создают свои, несовместимые между собой форматы, и, следовательно, могут изменить алгоритм. Так, внутренние таблицы алгоритма, рекомендованные ISO, заменяются ими на свои собственные. Кроме того, легкая неразбериха присутствует при задании степени потерь. Например, при тестировании выясняется, что “отличное” качество, “100%” и “10 баллов” дают существенно различающиеся картинки. При этом, кстати, “100%” качества не означают сжатие без потерь. Встречаются также варианты JPEG для специфических приложений.

Как стандарт ISO JPEG начинает все шире использоваться при обмене изображениями в компьютерных сетях. Поддерживается алгоритм JPEG в форматах Quick Time, PostScript Level 2, Tiff 6.0 и, на данный момент, занимает видное место в системах мультимедиа.

Характеристики алгоритма JPEG:

Класс изображений: Полноцветные 24 битные изображения или изображения в градациях серого без резких переходов цветов (фотографии).

Симметричность: 1

Характерные особенности: В некоторых случаях, алгоритм создает “ореол” вокруг резких горизонтальных и вертикальных границ в изображении (эффект Гиббса). Кроме того, при высокой степени сжатия изображение распадается на блоки 8х8 пикселов.

Фрактальный алгоритм

Идея метода

Фрактальная архивация основана на том, что мы представляем изображение в более компактной форме - с помощью коэффициентов системы итерируемых функций (Iterated Function System - далее по тексту как IFS). Прежде, чем рассматривать сам процесс архивации, разберем, как IFS строит изображение, т.е. процесс декомпрессии.

Строго говоря, IFS представляет собой набор трехмерных аффинных преобразований, в нашем случае переводящих одно изображение в другое. Преобразованию подвергаются точки в трехмерном пространстве (х_координата, у_координата, яркость).

Наиболее наглядно этот процесс продемонстрировал Барнсли в своей книге “Fractal Image Compression”. Там введено понятие Фотокопировальной Машины, состоящей из экрана, на котором изображена исходная картинка, и системы линз, проецирующих изображение на другой экран:

  • Линзы могут проецировать часть изображения произвольной формы в любое другое место нового изображения.
  • Области, в которые проецируются изображения, не пересекаются .
  • Линза может менять яркость и уменьшать контрастность .
  • Линза может зеркально отражать и поворачивать свой фрагмент изображения.
  • Линза должна масштабировать (уменьшать)свой фрагмент изображения.

Расставляя линзы и меняя их характеристики, мы можем управлять получаемым изображением. Одна итерация работы Машины заключается в том, что по исходному изображению с помощью проектирования строится новое, после чего новое берется в качестве исходного. Утверждается, что в процессе итераций мы получим изображение, которое перестанет изменяться. Оно будет зависеть только от расположения и характеристик линз, и не будет зависеть от исходной картинки. Это изображение называется “неподвижной точкой ” или аттрактором данной IFS. Соответствующая теория гарантирует наличие ровно одной неподвижной точки для каждой IFS.

Поскольку отображение линз является сжимающим, каждая линза в явном виде задает самоподобные области в нашем изображении. Благодаря самоподобию мы получаем сложную структуру изображения при любом увеличении. Таким образом, интуитивно понятно, что система итерируемых функций задает фрактал (нестрого - самоподобный математический объект).

Наиболее известны два изображения, полученных с помощью IFS: “треугольник Серпинского” и “папоротник Барнсли”. “Треугольник Серпинского” задается тремя, а “папоротник Барнсли” четырьмя аффинными преобразованиями (или, в нашей терминологии, “линзами”). Каждое преобразование кодируется буквально считанными байтами, в то время как изображение, построенное с их помощью, может занимать и несколько мегабайт.

Упражнение: Укажите в изображении 4 области, объединение которых покрывало бы все изображение, и каждая из которых была бы подобна всему изображению (не забывайте о стебле папоротника).

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

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

Определение.

где a, b, c, d, e, f действительные числа и называется двумерным аффинным преобразованием .

Определение. Преобразование , представимое в виде

где a, b, c, d, e, f, p, q, r, s, t, u действительные числа и называется трехмерным аффинным преобразованием.

Определение . Пусть - преобразование в пространстве Х. Точка такая, что называется неподвижной точкой (аттрактором) преобразования.

Определение . Преобразование в метрическом пространстве (Х, d) называется сжимающим, если существует число s: , такое, что

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

Теорема. (О сжимающем преобразовании)

Пусть в полном метрическом пространстве (Х, d ). Тогда существует в точности одна неподвижная точка этого преобразования, и для любой точки последовательность сходится к .

Более общая формулировка этой теоремы гарантирует нам сходимость.

Определение. Изображением называется функция S, определенная на единичном квадрате и принимающая значения от 0 до 1 или

Пусть трехмерное аффинное преобразование , записано в виде

и определено на компактном подмножестве декартова квадрата x. Тогда оно переведет часть поверхности S в область , расположенную со сдвигом (e,f) и поворотом, заданным матрицей

При этом, если интерпретировать значение S как яркость соответствующих точек, она уменьшится в p раз (преобразование обязано быть сжимающим) и изменится на сдвиг q .

Определение . Конечная совокупность W сжимающих трехмерных аффинных преобразований , определенных на областях , таких, что и , называется системой итерируемых функций (IFS).

Системе итерируемых функций однозначно сопоставляется неподвижная точка - изображение. Таким образом, процесс компрессии заключается в поиске коэффициентов системы, а процесс декомпрессии - в проведении итераций системы до стабилизации полученного изображения (неподвижной точки IFS). На практике бывает достаточно 7-16 итераций. Области в дальнейшем будут именоваться ранговыми , а области - доменными .

Построение алгоритма

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

В учебном варианте алгоритма , изложенном далее, сделаны следующие ограничения на области:

  1. Все области являются квадратами со сторонами, параллельными сторонам изображения. Это ограничение достаточно жесткое. Фактически мы собираемся аппроксимировать все многообразие геометрических фигур лишь квадратами.
  2. При переводе доменной области в ранговую уменьшение размеров производится ровно в два раза . Это существенно упрощает как компрессор, так и декомпрессор, т.к. задача масштабирования небольших областей является нетривиальной.
  3. Все доменные блоки - квадраты и имеют фиксированный размер . Изображение равномерной сеткой разбивается на набор доменных блоков.
  4. Доменные области берутся “через точку” и по Х, и по Y , что сразу уменьшает перебор в 4 раза.
  5. При переводе доменной области в ранговую поворот куба возможен только на 0 0 , 90 0 , 180 0 или 270 0 . Также допускается зеркальное отражение. Общее число возможных преобразований (считая пустое) - 8.
  6. Масштабирование (сжатие) по вертикали (яркости) осуществляется в фиксированное число раз - в 0,75.
Эти ограничения позволяют:
  1. Построить алгоритм, для которого требуется сравнительно малое число операций даже на достаточно больших изображениях.
  2. Очень компактно представить данные для записи в файл. Нам требуется на каждое аффинное преобразование в IFS:
  • два числа для того, чтобы задать смещение доменного блока. Если мы ограничим входные изображения размером 512х512, то достаточно будет по 8 бит на каждое число.
  • три бита для того, чтобы задать преобразование симметрии при переводе доменного блока в ранговый.
  • 7-9 бит для того, чтобы задать сдвиг по яркости при переводе.
Информацию о размере блоков можно хранить в заголовке файла. Таким образом, мы затратили менее 4 байт на одно аффинное преобразование. В зависимости от того, каков размер блока, можно высчитать, сколько блоков будет в изображении. Таким образом, мы можем получить оценку степени компрессии.

Например, для файла в градациях серого 256 цветов 512х512 пикселов при размере блока 8 пикселов аффинных преобразований будет 4096 (512/8x512/8). На каждое потребуется 3.5 байта. Следовательно, если исходный файл занимал 262144 (512х512) байт (без учета заголовка), то файл с коэффициентами будет занимать 14336 байт. Коэффициент архивации - 18 раз. При этом мы не учитываем, что файл с коэффициентами тоже может обладать избыточностью и архивироваться методом архивации без потерь, например LZW.

Отрицательные стороны предложенных ограничений:

  1. Поскольку все области являются квадратами, невозможно воспользоваться подобием объектов, по форме далеких от квадратов (которые встречаются в реальных изображениях достаточно часто.)
  2. Аналогично мы не сможем воспользоваться подобием объектов в изображении, коэффициент подобия между которыми сильно отличается от 2.
  3. Алгоритм не сможет воспользоваться подобием объектов в изображении, угол между которыми не кратен 90 0 .
Такова плата за скорость компрессии и за простоту упаковки коэффициентов в файл.

Сам алгоритм упаковки сводится к перебору всех доменных блоков и подбору для каждого соответствующего ему рангового блока. Ниже приводится схема этого алгоритма.

for (all range blocks) {
min_distance = MaximumDistance;
R ij = image->CopyBlock(i,j);
for (all domain blocks) { // С поворотами и отр.
current=Координаты тек. преобразования;
D=image->CopyBlock(current);
current_distance = R ij .L2distance(D);
if(current_distance < min_distance) {
// Если коэффициенты best хуже:
min_distance = current_distance;
best = current;
}
} //Next range
Save_Coefficients_to_file(best);
} //Next domain

Как видно из приведенного алгоритма, для каждого рангового блока делаем его проверку со всеми возможными доменными блоками (в том числе с прошедшими преобразование симметрии), находим вариант с наименьшей мерой L 2 (наименьшим среднеквадратичным отклонением) и сохраняем коэффициенты этого преобразования в файл. Коэффициенты - это (1) координаты найденного блока, (2) число от 0 до 7, характеризующее преобразование симметрии (поворот, отражение блока), и (3) сдвиг по яркости для этой пары блоков. Сдвиг по яркости вычисляется как:

,

где r ij - значения пикселов рангового блока (R ), а d ij - значения пикселов доменного блока (D ). При этом мера считается как:

.

Мы не вычисляем квадратного корня из L 2 меры и не делим ее на n, поскольку данные преобразования монотонны и не помешают нам найти экстремум, однако мы сможем выполнять на две операции меньше для каждого блока.

Посчитаем количество операций, необходимых нам для сжатия изображения в градациях серого 256 цветов 512х512 пикселов при размере блока 8 пикселов:

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

Схема алгоритма декомпрессии изображений

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

В качестве начального может быть взято абсолютно любое изображение (например, абсолютно черное), поскольку соответствующий математический аппарат гарантирует нам сходимость последовательности изображений, получаемых в ходе итераций IFS, к неподвижному изображению (близкому к исходному). Обычно для этого достаточно 16 итераций.

Прочитаем из файла коэффициенты всех блоков;
Создадим черное изображение нужного размера;
Until(изображение не станет неподвижным){
For(every range (R)){
D=image->CopyBlock(D_coord_for_R);
For(every pixel(i,j ) in the block{
R ij = 0.75D ij + o R ;
} //Next pixel
} //Next block
}//Until end

Поскольку мы записывали коэффициенты для блоков R ij (которые, как мы оговорили, в нашем частном случае являются квадратами одинакового размера) последовательно , то получается, что мы последовательно заполняем изображение по квадратам сетки разбиения использованием аффинного преобразования.

Как можно подсчитать, количество операций на один пиксел изображения в градациях серого при восстановлении необычайно мало (N операций “+”, 1 операций “* ”, где N - количество итераций, т.е. 7-16). Благодаря этому, декомпрессия изображений для фрактального алгоритма проходит быстрее декомпрессии, например, для алгоритма JPEG, в котором на точку приходится (при оптимальной реализации операций обратного ДКП и квантования) 64 операции “+” и 64 операции “? ” (без учета шагов RLE и кодирования по Хаффману!). При этом для фрактального алгоритма умножение происходит на рациональное число, одно для каждого блока. Это означает, что мы можем, во-первых, использовать целочисленную рациональную арифметику, которая существенно быстрее арифметики с плавающей точкой. Во-вторых, умножение вектора на число - более простая и быстрая операция, часто закладываемая в архитектуру процессора (процессоры SGI, Intel MMX...), чем скалярное произведение двух векторов, необходимое в случае JPEG. Для полноцветного изображения ситуация качественно не изменяется, поскольку перевод в другое цветовое пространство используют оба алгоритма.

Оценка потерь и способы их регулирования

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

Для фрактального алгоритма компрессии, как и для других алгоритмов сжатия с потерями, очень важны механизмы, с помощью которых можно будет регулировать степень сжатия и степень потерь. К настоящему времени разработан достаточно большой набор таких методов. Во-первых, можно ограничить количество аффинных преобразований, заведомо обеспечив степень сжатия не ниже фиксированной величины. Во-вторых, можно потребовать, чтобы в ситуации, когда разница между обрабатываемым фрагментом и наилучшим его приближением будет выше определенного порогового значения, этот фрагмент дробился обязательно (для него обязательно заводится несколько “линз”). В-третьих, можно запретить дробить фрагменты размером меньше, допустим, четырех точек. Изменяя пороговые значения и приоритет этих условий, мы будем очень гибко управлять коэффициентом компрессии изображения в диапазоне от побитового соответствия до любой степени сжатия. Заметим, что эта гибкость будет гораздо выше, чем у ближайшего “конкурента” - алгоритма JPEG.

Характеристики фрактального алгоритма :

Коэффициенты компрессии: 2-2000 (Задается пользователем).

Класс изображений: Полноцветные 24 битные изображения или изображения в градациях серого без резких переходов цветов (фотографии). Желательно, чтобы области большей значимости (для восприятия) были более контрастными и резкими, а области меньшей значимости - неконтрастными и размытыми.

Симметричность: 100-100000

Характерные особенности: Может свободно масштабировать изображение при разархивации, увеличивая его в 2-4 раза без появления “лестничного эффекта”. При увеличении степени компрессии появляется “блочный” эффект на границах блоков в изображении.

Рекурсивный (волновой) алгоритм

Английское название рекурсивного сжатия - wavelet. На русский язык оно переводится как волновое сжатие, и как сжатие с использованием всплесков. Этот вид архивации известен довольно давно и напрямую исходит из идеи использования когерентности областей. Ориентирован алгоритм на цветные и черно-белые изображения с плавными переходами. Идеален для картинок типа рентгеновских снимков. Коэффициент сжатия задается и варьируется в пределах 5-100. При попытке задать больший коэффициент на резких границах, особенно проходящих по диагонали, проявляется “лестничный эффект” - ступеньки разной яркости размером в несколько пикселов.

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

Так два числа a 2i и a 2i +1 всегда можно представить в виде b 1 i =(a 2i +a 2i +1 )/2 и b 2 i =(a 2i -a 2i +1 )/2. Аналогично последовательность a i может быть попарно переведена в последовательность b 1,2 i .

Разберем конкретный пример: пусть мы сжимаем строку из 8 значений яркости пикселов (a i ): (220, 211, 212, 218, 217, 214, 210, 202). Мы получим следующие последовательности b 1 i , и b 2 i : (215.5, 215, 215.5, 206) и (4.5, -3, 1.5, 4). Заметим, что значения b 2 i достаточно близки к 0. Повторим операцию, рассматривая b 1 i как a i . Данное действие выполняется как бы рекурсивно, откуда и название алгоритма. Мы получим из (215.5, 215, 215.5, 206): (215.25, 210.75) (0.25, 4.75). Полученные коэффициенты, округлив до целых и сжав, например, с помощью алгоритма Хаффмана с фиксированными таблицами, мы можем поместить в файл.

Заметим, что мы применяли наше преобразование к цепочке только два раза. Реально мы можем позволить себе применение wavelet- преобразования 4-6 раз. Более того, дополнительное сжатие можно получить, используя таблицы алгоритма Хаффмана с неравномерным шагом (т.е. нам придется сохранять код Хаффмана для ближайшего в таблице значения). Эти приемы позволяют достичь заметных коэффициентов сжатия.

Упражнение: Мы восстановили из файла цепочку (215, 211) (0, 5) (5, -3, 2, 4) (см. пример). Постройте строку из восьми значений яркости пикселов, которую воссоздаст алгоритм волнового сжатия.

Алгоритм для двумерных данных реализуется аналогично. Если у нас есть квадрат из 4 точек с яркостями a 2 i, 2 j , a 2 i +1 , 2 j , a 2 i, 2 j +1 , и a 2 i +1 , 2 j +1 , то

Исходное B 1 B 2
изображение B 3 B 4

Используя эти формулы, мы для изображения 512х512 пикселов получим после первого преобразования 4 матрицы размером 256х256 элементов:

-- В первой, как легко догадаться, будет храниться уменьшенная копия изображения. Во второй - усредненные разности пар значений пикселов по горизонтали. В третьей - усредненные разности пар значений пикселов по вертикали. В четвертой - усредненные разности значений пикселов по диагонали. По аналогии с двумерным случаем мы можем повторить наше преобразование и получить вместо первой матрицы 4 матрицы размером 128х128. Повторив наше преобразование в третий раз, мы получим в итоге: 4 матрицы 64х64, 3 матрицы 128х128 и 3 матрицы 256х256. На практике при записи в файл, значениями, получаемыми в последней строке (), обычно пренебрегают (сразу получая выигрыш примерно на треть размера файла - 1- 1/4 - 1/16 - 1/64...).

К достоинствам этого алгоритма можно отнести то, что он очень легко позволяет реализовать возможность постепенного “прояв–ления” изображения при передаче изображения по сети. Кроме того, поскольку в начале изображения мы фактически храним его уменьшенную копию, упрощается показ “огрубленного” изображения по заголовку.

В отличие от JPEG и фрактального алгоритма данный метод не оперирует блоками, например, 8х8 пикселов. Точнее, мы оперируем блоками 2х2, 4х4, 8х8 и т.д. Однако за счет того, что коэффициенты для этих блоков мы сохраняем независимо, мы можем достаточно легко избежать дробления изображения на “мозаичные” квадраты.

Характеристики волнового алгоритма :

Коэффициенты компрессии: 2-200 (Задается пользователем).

Класс изображений: Как у фрактального и JPEG.

Симметричность: ~1.5

Характерные особенности: Кроме того, при высокой степени сжатия изображение распадается на отдельные блоки.

Заключение

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

Алгоритм Особенности изображения, за счет которых происходит сжатие
RLE Подряд идущие одинаковые цвета: 2 2 2 2 2 2 15 15 15
LZW Одинаковые подцепочки: 2 3 15 40 2 3 15 40
Хаффмана Разная частота появления цвета: 2 2 3 2 2 4 3 2 2 2 4
CCITT-3 Преобладание белого цвета в изображении, большие области, заполненные одним цветом
Рекурсивный Плавные переходы цветов и отсутствие резких границ
JPEG Отсутствие резких границ
Фрактальный Подобие между элементами изображения
Алгоритм К-ты сжатия Симметричность по времени На что
ориентирован
Потери Размерность
RLE 32, 2, 0.5 1 3,4-х битные Нет 1D
LZW 1000, 4, 5/7 1.2-3 1-8 битные Нет 1D
Хаффмана 8, 1.5, 1 1-1.5 8 битные Нет 1D
CCITT-3 213(3), 5, 0.25 ~1 1-битные Нет 1D
JBIG 2-30 раз ~1 1-битные Нет 2D
Lossless JPEG 2 раза ~1 24-битные, серые Нет 2D
JPEG 2-20 раз ~1 24-битные, серые Да 2D
Рекурсивное сжатие 2-200 раз 1.5 24-битные, серые Да 2D
Фрактальный 2-2000 раз 1000-10000 24-битные, серые Да 2.5D