1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
|
\documentclass[a4paper,14pt]{extarticle}
\usepackage[T2A]{fontenc}
\usepackage[english,russian]{babel}
\usepackage[
left=2.5cm, right=1.5cm,
top=1.5cm, bottom=2cm,
]{geometry}
\usepackage{amsmath}
\usepackage{indentfirst}
\usepackage{underscore}
\usepackage{multirow}
\usepackage{float}
\usepackage{setspace}
\singlespacing
\usepackage{graphicx}
\graphicspath{{./images/}}
\setcounter{tocdepth}{3}
\title{Алгоритмы сжатия изображений}
\author{Андрей~Гущин \and Роман~Стаин}
\date{11 ноября 2022 г.}
\begin{document}
\maketitle
\tableofcontents
\section{Представление цифровых изображений}
Для представления изображений в памяти компьютера используется два подхода:
\begin{itemize}
\item растровое представление,
\item векторное представление.
\end{itemize}
Ввиду того, что векторные изображения получаются путём математического описания
элементарных геометрических объектов, обычно называемых \emph{примитивами}
(линии, точки, геометрические фигуры), они занимают крайне малое количество
памяти компьютера и поэтому к ним обычно не применяют алгоритмы сжатия.
В отличие от них, растровые изображения хранятся в виде двумерного массива
чисел, где каждому значению соответствует цветовое значение пикселя. Для
уменьшения размера растрового изображения, помимо сжатия, также используют
уменьшение значения \emph{глубины цвета} (количества допустимых цветов), либо
уменьшения размера изображения в пикселях (масштабирование).
Но так как уменьшение размера изображения, или уменьшение глубины цвета могут
значительно изменить или ухудшить качество исходного изображения, обычно
применяются специализированные алгоритмы сжатия изображений: с потерями и без
потерь. Хотя сжатие с потерями также ухудшает качество изображения, зачастую
на практике изменения не настолько заметны, как в случае с изменением глубины
цвета.
\section{Алгоритмы сжатия изображений без потерь}
Сжатие без потерь часто предпочтительней для искусственно построенных
изображений, таких как графики, иконки программ, либо для специальных случаев,
например, если изображения предназначены для последующей обработки алгоритмами
распознавания изображений.
Основными и самыми популярными алгоритмами сжатия без потерь являются:
\begin{itemize}
\item
\textbf{RLE} --- используется в форматах PCX --- в качестве основного метода
и в форматах BMP, TGA, TIFF в качестве одного из доступных.
\item \textbf{LZW} --- используется в формате GIF
\item \textbf{Deflate} --- используется в формате PNG
\end{itemize}
\subsection{Сжатие по стандарту RLE}
Рассмотрим изображение, содержащее текст чёрного цвета на сплошном белом фоне.
При построчном чтении пикселей такого изображения будут встречаться серии белых
(фон) и чёрных (буквы) пикселей. Буквой B обозначим чёрный пиксель, а буквой W
--- белый. Рассмотрим некую произвольную строку изображения длиной 51 символ:
\begin{center}
\texttt{WWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWBWWWWWWWWWWWWWW}
\end{center}
Посчитаем количество символов:
\begin{enumerate}
\item 4 символа <<B>>;
\item 7 символов <<W>>.
\end{enumerate}
Итого найдено 5 серий. Заменим серии на число повторов и сам повторяющийся
символ:
\begin{center}
\texttt{9W3B24W1B14W}
\end{center}
Получилась последовательность из 12 символов. Исходная последовательность
состояла из 51 символа. Данные были сжаты в $51 / 12 \approx 4.25$ раза.
Возьмём строку, состоящую из большого количества неповторяющихся символов:
\begin{center}
\texttt{ABCABCABCDDDFFFFFF}
\end{center}
После сжатия методом RLE такая строка будет выглядеть так:
\begin{center}
\texttt{1A1B1C1A1B1C1A1B1C3D6F}
\end{center}
Исходная строка состоит из 18 символов, а сжатая --- из 22. Размер данных
увеличился в $22 / 18 \approx 1.22$ раза.
Чтобы после сжатия размер данных не увеличивался, алфавит, в котором записаны
длины серий, делят на две части (обычно равные). Например, алфавит целых чисел
можно разделить на две части: положительные и отрицательные числа. Положительные
числа используют для записи количества повторов одного символа, а отрицательные
--- для записи количества неодинаковых символов, следующих друг за другом.
Посчитаем символы с учётом вышесказанного:
\begin{itemize}
\item сначала друг за другом следуют 9 не одинаковых символов: <<ABCABCABC>>;
\item затем записаны 3 символа <<D>>;
\item наконец записаны 6 символов <<F>>.
\end{itemize}
Сжатая строка запишется в виде:
\begin{center}
\texttt{-9ABCABCABC3D6F}
\end{center}
Исходная строка состоит из 18 символов, а сжатая --- из 15. Размер данных
уменьшился в $18 / 15 = 1.2$ раза.
Допустим, реализация метода RLE для записи длин серий (для подсчёта количества
символов) использует переменную целочисленного типа со знаком <<signed char>>.
В такую переменную можно записать числа от -128 до 127 включительно. Как
же быть, если длина серии равна 128 символам и более? В этом случае серию
разделяют на части так, чтобы длина части не превышала 127 символов. Например,
серия, состоящая из 256 символов <<A>>, будет закодирована следующей строкой
$(256=127+127+2)$:
\begin{center}
\texttt{127A127A2A}
\end{center}
Запись на некотором языке программирования алгоритма RLE с учётом этих
ограничений нетривиальна.
Конечно, кодирование, которое используется для хранения изображений, оперирует с
двоичными данными, а не с символами ASCII, как в рассмотренных примерах, однако
принцип остаётся тем же.
\subsection{Сжатие по стандарту LZW}
Данный алгоритм при кодировании (сжатии) сообщения динамически создаёт словарь
фраз: определённым последовательностям символов (фразам) ставятся в соответствие
группы битов (коды) фиксированной длины. Словарь инициализируется всеми
1-символьными фразами (в случае 8-битных символов --- это 256 фраз). По мере
кодирования алгоритм просматривает текст символ за символом слева направо.
При чтении алгоритмом очередного символа в данной позиции находится строка W
максимальной длины, совпадающая с какой-то фразой из словаря. Затем код этой
фразы подаётся на выход, а строка WK, где K --- это символ, следующий за W во
входном сообщении, вносится в словарь в качестве новой фразы и ей присваивается
какой-то код (так как W выбрана жадно, WK ещё не содержится в словаре). Символ K
используется в качестве начала следующей фразы. Более формально данный алгоритм
можно описать следующей последовательностью шагов:
\begin{enumerate}
\item
Инициализация словаря всеми возможными односимвольными фразами.
Инициализация входной фразы W первым символом сообщения.
\item
Если сообщение закончилось (символ \#), то выдать код для W и завершить
алгоритм.
\item Считать очередной символ K из кодируемого сообщения.
\item
Если фраза WK уже есть в словаре, то присвоить входной фразе W значение WK и
перейти к Шагу 2.
\item
Иначе выдать код W, добавить WK в словарь, присвоить входной фразе W
значение K и перейти к Шагу 2.
\end{enumerate}
Алгоритму декодирования на входе требуется только закодированный текст:
соответствующий словарь фраз легко воссоздаётся посредством имитации работы
алгоритма кодирования.
\subsubsection{Пример кодирования}
\begin{table}[H]
\centering
\begin{tabular}{|c|c|c|r|l|}
\hline
% Первая строка заголовка
\multirow{2}{*}{Символ} &
\multirow{2}{*}{Следующий} &
\multicolumn{2}{|c|}{Вывод} &
\multirow{2}{*}{Расширение словаря} \\ \cline{3-4}
% Вторая строка заголовка
&& Код & \multicolumn{1}{|c|}{Биты} & \\ \hline
% Символ & Следующий & Код & Биты & Расширение словаря \\
NULL & T & & & \\ \hline
T & O & 20 & \texttt{10100} & 27: TO \\ \hline
O & B & 15 & \texttt{101111} & 28: OB \\ \hline
B & E & 2 & \texttt{100010} & 29: BE \\ \hline
E & O & 5 & \texttt{100101} & 30: EO \\ \hline
O & R & 15 & \texttt{101111} & 31: OR \\ \hline
R & N & 18 & \texttt{110010} & 32: RN \\ \hline
N & O & 14 & \texttt{1001110} & 33: NO \\ \hline
O & T & 15 & \texttt{1001111} & 34: OT \\ \hline
T & T & 20 & \texttt{1010100} & 35: TT \\ \hline
TO & B & 27 & \texttt{1011011} & 36: TOB \\ \hline
BE & O & 29 & \texttt{1011101} & 37: BEO \\ \hline
OR & T & 31 & \texttt{1011111} & 38: ORT \\ \hline
TOB & E & 36 & \texttt{1100100} & 39: TOBE \\ \hline
EO & R & 30 & \texttt{1011110} & 40: EOR \\ \hline
RN & O & 32 & \texttt{1100000} & 41: RNO \\ \hline
OT & \# & 34 & \texttt{1100010} & \\ \hline
& & 0 & \texttt{000000} & \\ \hline
\end{tabular}
\end{table}
\subsubsection{Пример декодирования}
\begin{table}[H]
\centering
\begin{tabular}{|r|c|c|l|l|}
\hline
% Первая строка заголовка
\multicolumn{2}{|c|}{Ввод} &
\multirow{2}{*}{Вывод} &
\multicolumn{2}{|c|}{Новая запись} \\ \cline{1-2} \cline{4-5}
% Вторая строка заголовка
\multicolumn{1}{|c|}{Биты} &
Код & &
\multicolumn{1}{|c|}{Полная} &
\multicolumn{1}{|c|}{Частичная} \\ \hline
% Биты & Код & Вывод & Полная & Частичная \\
\texttt{10100} & 20 & T & & 27: T? \\ \hline
\texttt{01111} & 15 & O & 27: TO & 28: O? \\ \hline
\texttt{00010} & 2 & B & 28: OB & 29: B? \\ \hline
\texttt{00101} & 5 & E & 29: BE & 30: E? \\ \hline
\texttt{01111} & 15 & O & 30: EO & 31: O? \\ \hline
\texttt{10010} & 18 & R & 31: OR & 32: R? \\ \hline
\texttt{001110} & 14 & N & 32: RN & 33: N? \\ \hline
\texttt{001111} & 15 & O & 33: NO & 34: O? \\ \hline
\texttt{010100} & 20 & T & 34: OT & 35: T? \\ \hline
\texttt{011011} & 27 & TO & 35: TT & 36: TO? \\ \hline
\texttt{011101} & 29 & BE & 36: TOB & 37: BE? \\ \hline
\texttt{011111} & 31 & OR & 37: BEO & 38: OR? \\ \hline
\texttt{100100} & 36 & TOB & 38: ORT & 39: TOB? \\ \hline
\texttt{011110} & 30 & EO & 39: TOBE & 40: EO? \\ \hline
\texttt{100000} & 32 & RN & 40: EOR & 41: RN? \\ \hline
\texttt{100010} & 34 & OT & 41: RNO & 42: OT? \\ \hline
\texttt{000000} & 0 & \# & & \\ \hline
\end{tabular}
\end{table}
\section{Алгоритмы сжатия с потерями}
Алгоритмы сжатия с потерями могут применяться в тех случаях, когда необходимо
сжать естественное изображение (например, фотографию) в приложениях, где
незначительная потеря качества позволяет существенно увеличить скорость передачи изображения.
Наиболее часто применяемые алгоритмы сжатия с потерями:
\begin{itemize}
\item
Дискретное косинусное преобразование "--- кодирование, основанное на
преобразованиях Фурье.
\item Вейвлет сжатие "--- сжатие за счёт отбрасывания низких амплитуд.
\item Квантование цветов "--- процесс уменьшения количества различных цветов.
\item
Прореживание (субдискретизация) компонентов цветности "--- усреднение или
уменьшение части информации о цветности изображения.
\item
Фрактальное сжатие "--- алгоритм сжатия изображений с потерями, основанный
на применении систем итерируемых функций к изображениям
\end{itemize}
Некоторые из этих алгоритмов применяются в алгоритмах сжатия \textbf{JPEG},
JPEG2000.
\subsection{Сжатие по стандарту JPEG}
\subsubsection{Преобразование цветового пространства}
При сжатии изображение преобразуется из цветового пространства RGB в
\textbf{YCbCr}. Сжатие с потерями использует принцип отделения важной информации
от неважной. Для человеческого глаза изменение яркости заметно сильнее, чем
изменение цвета, поэтому и используется данное цветовое пространство.
Y' "--- компонента яркости, Cb и Cr являются синей и красной цветоразностными
компонентами.
\begin{figure}[H]
\centering
\includegraphics[width=0.999\textwidth]{YCbCr.jpg}
\caption{Цветное изображение и его компоненты Y, Cb и Cr}
\end{figure}
Хорошо видно, что на карте яркости намного больше деталей.
Сигналы Y'CbCr (до нормирования и смещения для перевода сигналов в цифровую
форму) формируются с применением гамма-коррекции из соответствующих RGB
источников следующим образом:
\begin{align*}
Y' &= K_R \cdot R' + (1 - K_R - K_B) \cdot G' + K_B \cdot B' \\
C_B &= \frac{1}{2} \cdot \frac{B' - Y'}{1 - K_B} \\
C_R &= \frac{1}{2} \cdot \frac{R' - Y'}{1 - K_R} \\
\end{align*}
где $K_B$ и $K_R$ коэффициенты, которые обычно выводятся из определения
соответствующего пространства RGB.
Здесь апостроф ' означает компоненты с гамма-коррекцией, поэтому $R'$, $G'$
и $B'$ располагаются в пределах от 0 до 1, где 0 соответствует минимальной
интенсивности (например, для отображения чёрного цвета) и 1 соответствует
максимуму (например, для отображения белого цвета). Результирующее значение
яркости (Y) будет иметь пределы от 0 до 1, а значения цветности (Cb и Cr) будут
расположены в пределах от -0.5 до +0.5.
\subsubsection{Прореживание (субдискретизация) компонентов цветности}
Есть несколько схем прореживания, которые применяются в зависимости от
требований к качеству изображения после его восстановления. Структура
дискретизации сигнала обозначается как соотношение между тремя частями X:a:b
(например, 4:2:2).
\begin{enumerate}
\item
Тип 4:4:4 (отсутствие субдискретизации) "--- каждому пикселю в каждой
строке соответствует собственное уникальное значение компонентов Y, Cb и
Cr.
\item
Тип 4:2:2 "--- объединение по компонентам цветности происходит по
горизонтали в группах по два пикселя.
\item
Тип 4:2:0 "--- изображение разбивается на квадраты $2 \times 2$ пикселей и
в каждом из них все пиксели получают одинаковые значения Cb и Cr.
\item
Тип 4:1:1 "--- объединение по компонентам цветности происходит по
горизонтали в группах по 4 пикселя.
\end{enumerate}
\begin{figure}[H]
\centering
\includegraphics[width=0.999\textwidth]{subd.png}
\caption{Примеры субдискретизации}
\end{figure}
\subsubsection{Дискретное косинусное преобразование}
Далее яркостный компонент Y и отвечающие за цвет компоненты Cb и Cr разбиваются
на блоки $8 \times 8$ пикселей. Каждый такой блок подвергается дискретному
косинусному преобразованию (ДКП, DCT). Его суть заключается в разложении по
спектру пространственных волн. Или другими словами, есть 64 изображения,
совмещая которые можно получить любое другое изображение.
\begin{figure}[H]
\centering
\includegraphics[width=0.5\textwidth]{dct64.png}
\caption{}
\end{figure}
Обозначим такие блоки через $IMG$. Тогда ДКП осуществляется по формуле:
\[ RES = DCT \cdot IMG \cdot DCT^T, \]
где $DCT = \displaystyle \sqrt{\frac{2}{N}} \cdot \cos{\frac{(2j + 1) \cdot i \cdot \pi}{2 \cdot N}}$,
$N = 8, 0 \leq i, j \leq 7$.
Например, если взять матрицу, состоящую из одинаковых значений, то можно
увидеть, что в левом верхнем углу получившейся матрицы сохраняется большое
значение.
До преобразования ДКП:
\begin{equation*}
\begin{pmatrix}
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100 \\
100 & 100 & 100 & 100 & 100 & 100 & 100 & 100
\end{pmatrix}
\end{equation*}
После преобразования ДКП:
\begin{equation*}
\begin{pmatrix}
800 & 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
\end{pmatrix}
\end{equation*}
\subsubsection{Квантование и кодирование}
Далее матрица коэффициентов делится на матрицу квантования, которая зависит от
настроек сжатия. Например, если требуется сохранить 100\% качество, то каждый
коэффициент делится на 1 (то есть остается таким же). Если сохранение проходит
с меньшим качеством, то каждый коэффициент делится на определенное число (в
зависимости от выбранного качества).
Затем производится округление поделённых коэффициентов до целого значения. И при
сильном сжатии многие из них округляются до нуля.
\begin{figure}[H]
\centering
\includegraphics[width=0.45\textwidth]{q1.png}
\caption{Примеры матрицы полученной после квантования}
\end{figure}
Затем матрица коэффициентов выписывается <<зиг-загом>>:
\begin{figure}[H]
\centering
\includegraphics[width=0.45\textwidth]{q2.png}
\caption{}
\end{figure}
Получается последовательность чисел, в конце которой зачастую одни нули: 239,
32, 34, -70, -3, 27, -12, -19, 2, 5, -17, 0, 8, 6, 3, -5, 3, 23, -6, -3, 0, -3,
4, 6, 11, 9, 0, 3, 0, 0, 6, 0, 6, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.
Затем эта последовательность пакуется так, что указывается число нулей, идущих
подряд (алгоритм кодирования длины серии): 239, 32, 34, -70, -3, 27, -12, -19,
2, 5, -17, (0, 1), 8, 6, 3, -5, 3, 23, -6, -3, (0, 1), -3, 4, 6, 11, 9, (0, 1),
3, (0, 2) 6, (0, 1), 6, (0, 6), 3, (0, 24).
Затем коэффициенты кодируются с помощью алгоритма кодирования Хаффмана, чтобы
получить окончательное изображение.
\subsection{Фрактальное сжатие изображений}
Библиотека под названием Fiasco была создана Ульрихом Хафнером. В 2001 году
о ней написали в Linux Journal. Согласно руководству 2000-04, Fiasco можно
использовать для сжатия видео. Также библиотека Netpbm включает в себя Фиаско.
Электронная энциклопедия Microsoft Encarta использует разновидность фрактального
сжатия. Эта энциклопедия выпускалась на компакт-дисках объёмом 650МБ. На диск
записано 7 часов звука, 100 анимационных роликов, примерно 800 масштабируемых
карт, а также 7000 качественных фотографий.
\end{document}
|