АЛГОРИТМЫ СЖАТИЯ

ТеорияПрактикаКонтроль знанийДемонстрация
Содержание
Введение
Классификация
-Критерии оценки
-Надёжность и сложность
-Методы сжатия
-Методы кодирования
Сжатие без потерь
-RLE
-Семейство LZ
-LZ77
-LZSS
-LZ78
-LZW
-LZM
-LZB
-LZH
-LZC
-LZT
-LZMV
-LZJ
-LZFG
-Унарное кодирование
-Метод Хаффмана
-Арифметическое кодирование
-Вероятностное сжатие
-BWT
Сжатие с потерями
-Звук и видео
-Изображения
Алгоритмы сжатия с потерями
-JPEG
-JPEG2000
-Wavelet
-Фрактальный
Предметный указатель

Обзор алгоритмов сжатия без потерь

Алгоритм LZW

Как и LZ77, алгоритм LZ78 был опубликован в сугубо научном журнале и сначала воспринимался читателями скорее как абстракция, нежели то, что можно положить в основу программного продукта. Так было до 1984 года, когда Терри Уэлч (Terry Welch) опубликовал свою работу. Модификация алгоритма LZ78, предложенная Уэлчем, получила название LZW (Lempel-Ziv-Welch).

Алгоритм на удивление прост. Если в двух словах, то LZW-сжатие заменяет строки символов некоторыми кодами. Это делается без какого-либо анализа входного текста. Вместо этого при добавлении каждой новой строки символов просматривается таблица строк. Сжатие происходит, когда код заменяет строку символов. Коды, генерируемые LZW-алгоритмом, могут быть любой длины, но они должны содержать больше бит, чем единичный символ. Первые 256 кодов (когда используются 8-битные символы) по умолчанию соответствуют стандартному набору символов. Остальные коды соответствуют обрабатываемым алгоритмом строкам.

Сжатие
Алгоритм LZW-сжатия в простейшей форме приведен ниже. Каждый раз, когда генерируется новый код, новая строка добавляется в таблицу строк. LZW постоянно проверяет, является ли строка уже известной, и, если так, выводит существующий код без генерации нового.

Процедура LZW-сжатия
СТРОКА = очередной символ из входного потока
WHILE входной поток не пуст DO
  СИМВОЛ = очередной символ из входного потока
  IF СТРОКА+СИМВОЛ в таблице строк THEN
    СТРОКА = СТРОКА+СИМВОЛ
  ELSE 
    вывести в выходной поток код для СТРОКА
    добавить в таблицу строк СТРОКА+СИМВОЛ
    СТРОКА = СИМВОЛ
  END of IF
END of WHILE
вывести в выходной поток код для СТРОКА

Рассмотрим пример для демонстрации алгоритма. Входная строка:

/WED/WE/WEE/WEB/WET

Входная строка является кратким списком английских слов, разделенных символом "/". Как вы можете заметить, анализируя алгоритм, его работа начинается с того, что на первом шаге цикла он выполняет проверку на наличие строки "/W" в таблице. Когда он не находит эту строку, то генерирует код для "/" и добавляет в таблицу строку "/W". Т.к. 256 символов уже определены для кодов 0 - 255, то первой определенной строке может быть поставлен в соответствие код 256. После этого система читает следующую букву ("E"), добавляет вторую подстроку ("WE") в таблицу и выводит код для буквы "W".

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

Входная строка: /WED/WE/WEE/WEB/WET
Вход (символы)Выход (коды)Новые коды и соответствующие строки
/W/256 = /W
EW257 = WE
DE258 = ED
/D259 = D/
WE256260 = /WE
/E261 = E/
WEE260262 = /WEE
/W261263 = E/W
EB257264 = WEB
/B265 = B/
WET260266 = /WET
<EOF>T

Как вы можете заметить, эта таблица быстро заполняется, т.к. новая строка добавляется в таблицу каждый раз, когда генерируется код. В этом явно вырожденном примере было выведено пять закодированных подстрок и семь символов. Если использовать 9-битные коды для вывода, то 19-символьная входная строка будет преобразована в 13.5-символьная выходную строку. Конечно, этот пример был выбран только для демонстрации. В действительности сжатие обычно не начинается до тех пор, пока не будет построена достаточно большая таблица, обычно после прочтения порядка 100 входных байт.

Распаковка
Алгоритму сжатия соответствует свой алгоритм распаковки. Он получает выходной поток кодов от алгоритма сжатия и использует его для точного восстановления входного потока. Одной из причин эффективности LZW-алгоритма является то, что он не нуждается в хранении таблицы строк, полученной при сжатии. Таблица может быть точно восстановлена при распаковке на основе выходного потока алгоритма сжатия. Это возможно потому, что алгоритм сжатия выводит СТРОКОВУЮ и СИМВОЛЬНУЮ компоненты кода прежде чем он поместит этот код в выходной поток. Это означает, что сжатые данные не обременены необходимостью тянуть за собой большую таблицу перевода.

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

Процедура LZW-распаковки:
читать СТАРЫЙ_КОД
вывести СТАРЫЙ_КОД
WHILE входной поток не пуст DO
  читать НОВЫЙ_КОД
  СТРОКА = перевести НОВЫЙ_КОД
  вывести СТРОКУ
  СИМВОЛ = первый символ СТРОКИ
  добавить в таблицу перевода СТАРЫЙ_КОД+СИМВОЛ
  СТАРЫЙ_КОД = НОВЫЙ_КОД
END of WHILE

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

Входные коды: / W E D 256 E 260 261 257 B 260 T
ВходСТАРЫЙ КОДСТРОКАСИМВОЛНовый вход таблицы
НОВЫЙ КОДВыход
///
W/WW256 = /W
EWEE257 = WE
DEDD258 = ED
256D/W/259 = D/
E256EE260 = /WE
260E/WE/261 = E/
261260E/E262 = /WEE
257261WEW263 = E/W
B257BB264 = WEB
260B/WE/265 = B/
T260TT266 = /WET

Выходной поток идентичен входному потоку алгоритма сжатия. Отметим, что первые 256 кодов уже определены для перевода одиночных символов, также как и в алгоритме сжатия.

Ловушка
К несчастью прекрасный, простой алгоритм распаковки, является все таким слишком простым. В алгоритме сжатия существуют некоторые исключительные ситуации, которые создают проблемы при распаковке. Если существует строка, представляющая пару (СТРОКА СИМВОЛ) и уже определенную в таблице, а просматриваемый входной поток содержит последовательность СТРОКА СИМВОЛ СТРОКА СИМВОЛ СТРОКА, алгоритм сжатия выведет код прежде, чем распаковщик получит возможность определить его.

Простой пример иллюстрирует это. Предположим, строка "JOEYN" определена в таблице с кодом 300. Когда последовательность "JOEYNJOEYNJOEY" появляется в таблице, выходной поток алгоритма сжатия выглядит следующим образом:

Входная строка : ...JOEYNJOEYNJOEY...
Вход(символы)Выход(коды)Новые коды и соотв. строки
JOEYN288 = JOEY300 = JOEYN
AN301 = NA
.........
JOEYNJ300 = JOEYN400 = JOEYNJ
JOEYNJO400401 = JOEYNJO

Когда распаковщик просматривает входной поток, он сначала декодирует код 300, затем выводит строку "JOEYN" и добавляет определение для, скажем, кода 399 в таблицу, хотя он уже мог там быть. Затем читает следующий входной код, 400, и обнаруживает, что его нет в таблице. Это уже проблема. К счастью, это произойдет только в том случае, если распаковщик встретит неизвестный код. Так как это фактически единственная коллизия, то можно без труда усовершенствовать алгоритм.

Модифицированный алгоритм предусматривает специальные действия для еще неопределенных кодов. В примере на рис. 6 распаковщик обнаруживает код 400, который еще не определен. Так как этот код не известен, то декодируется значение СТАРОГО_КОДА, равное 300. Затем распаковщик добавляет значение СИМВОЛА, равное "J", к строке. Результатом является правильный перевод кода 400 в строку "JOEYNJ".

Процедура LZW-распаковки:
читать СТАРЫЙ_КОД
вывести СТАРЫЙ_КОД
СИМВОЛ = СТАРЫЙ_КОД
WHILE входной поток не пуст DO
  читать НОВЫЙ_КОД
  IF NOT в таблице перевода НОВЫЙ_КОД THEN
    СТРОКА = перевести СТАРЫЙ_КОД
    СТРОКА = СТРОКА+СИМВОЛ
  ELSE
    СТРОКА = перевести НОВЫЙ_КОД
  END of IF
  вывести СТРОКУ
  СИМВОЛ = первый символ СТРОКИ
  добавить в таблицу перевода СТАРЫЙ_КОД+СИМВОЛ
  СТАРЫЙ_КОД = НОВЫЙ_КОД
END of WHILE

Результаты
Степень сжатия определяется различными факторами. LZW-сжатие выделяется среди прочих, когда встречается с потоком данных, содержащим повторяющиеся строки любой структуры. По этой причине он работает весьма эффективно, когда встречает английский текст. Уровень сжатия может достигать 50% и выше. Соответственно, сжатие видеоформ и копий экранов показывает еще большие результаты.

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


НазадК cодержаниюВперёд
2006 All Rights Reserved