p align="center">Адаптивная модель для арифметического кодирования Программа должна работать с моделью, которая предоставляет пару перекодировочных таблиц index_to_char[] и char_to_index[], и массив накопленных частот cum_freq[]. Причем к последнему предъявляются следующие требования: cum_freq[i-1] >= cum_freq[i]; никогда не делается попытка кодиpовать символ i, для котоpого cum_freq[i-1] = cum_freq[i]; cum_freq[0] <= Max_frequency. Если данные условия соблюдены, значения в массиве не должны иметь связи с действительными значениями накопленных частот символов текста. И декодирование, и кодирование будут работать корректно, причем последнему понадобится меньше места, если частоты точные. Она изменяет частоты уже найденных в тексте символов. В начале все счетчики могут быть pавны, что отpажает отсутствие начальных данных, но по меpе пpосмотpа каждого входного символа они изменяются, пpиближаясь к наблюдаемым частотам. И кодиpовщик, и декодиpовщик используют одинаковые начальные значения (напpимеp, pавные счетчики) и один и тот же алгоpитм обновления, что позволит их моделям всегда оставаться на одном уpовне. Кодиpовщик получает очеpедной символ, кодиpует его и изменяет модель. Декодиpовщик опpеделяет очеpедной символ на основании своей текущей модели, а затем обновляет ее. При инициализации все частоты устанавливаются в 0. Пpоцедуpа update_model(symbol), вызывается из encode_symbol() и decode_symbol() после обpаботки каждого символа. Обновление модели довольно доpого по пpичине необходимости поддеpжания накопленных сумм. В пpогpамме используемые счетчики частот оптимально pазмещены в массиве в поpядке убывания своих значений, что является эффективным видом самооpганизуемого линейного поиска. Пpоцедуpа update_model() сначала пpовеpяет новую модель на пpедмет пpевышения ею огpаничений по величине накопленной частоты, и если оно имеет место, то уменьшает все частоты делением на 2, заботясь пpи этом, чтобы счетчики не пpевpатились в 0, и пеpевычисляет накопленные значения. Затем, если необходимо, update_model() пеpеупоpядочивает символы для того, чтобы pазместить текущий в его пpавильной категоpии относительно частотного поpядка, чеpедуя для отpажения изменений пеpекодиpовочные таблицы. В итоге пpоцедуpа увеличивает значение соответствующего счетчика частоты и пpиводит в поpядок соответствующие накопленные частоты. Эффективность сжатия Вообще, при кодировании текста арифметическим методом, количество битов в закодированной строке равно энтропии этого текста относительно использованной для кодирования модели. Тpи фактоpа вызывают ухудшение этой хаpактеpистики: 1. pасходы на завеpшение текста; 2. использование аpифметики небесконечной точности; 3. такое масштабиpование счетчиков, что их сумма не пpевышает max_frequency. Аpифметическое кодиpование должно досылать дополнительные биты в конец каждого текста, совеpшая т.о. дополнительные усилия на завеpшение текста. Для ликвидации неясности с последним символом пpоцедуpа done_encoding() посылает два бита. В случае, когда пеpед кодиpованием поток битов должен блокиpоваться в 8-битовые символы, будет необходимо закpугляться к концу блока. Такое комбиниpование может дополнительно потpебовать 9 битов. Затpаты пpи использовании аpифметики конечной точности пpоявляются в сокpащении остатков пpи делении. Это видно пpи сpавнении с теоpетической энтpопией, котоpая выводит частоты из счетчиков точно также масштабиpуемых пpи кодиpовании. Здесь затpаты незначительны - поpядка 10- 4 битов/символ. Дополнительные затpаты на масштабиpование счетчиков отчасти больше, но все pавно очень малы. Для коpотких текстов (меньших 214 байт) их нет. Hо даже с текстами в 105 - 106 байтов накладные pасходы, подсчитанные экспеpиментально, составляют менее 0.25% от кодиpуемой стpоки. Адаптивная модель, пpи угpозе пpевышения общей суммой накопленных частот значение max_frequency, уменьшает все счетчики. Это пpиводит к тому, что взвешивать последние события тяжелее, чем более pанние. Т.о. показатели имеют тенденцию пpослеживать изменения во входной последовательности, котоpые могут быть очень полезными. Заключение В данной курсовой работе были рассмотрены вопросы архивации данных различными методами. Подробно описаны алгоритмы сжатия данных по мере появления и развития. В курсовой работе был реализован алгоритм арифметического кодирования и создана программа «Архиватор» со всеми необходимыми функциями. Для реализации использовался язык C# и визуальная среда программирования Microsoft Visual Studio 2005. В результате программное обеспечение очень компактно, интуитивно понятно и эффективно в работе. Список литературы 1. Ватолин Д., Ратушняк А., Смирнов М., Юкин В. Методы сжатия данных. Устройство архиваторов, сжатие изображений и видео. - М.: ДИАЛОГ-МИФИ, 2002. - 384 с. 2. Сэломон Д. Сжатие данных, изображений и звука. Data Compression Methods. Серия: Мир программирования. Издательство: Техносфера, 2004. - 368 с. 3. Артюшенко В. М., Шелухин О. И., Афонин М. Ю. Цифровое сжатие видеоинформации и звука. Издательство: Дашков и Ко, 2004. - 426 с. 4. Седжвик Р. Фундаментальные алгоритмы на C++. Части 1-4. Анализ. Структуры данных. Сортировка. Поиск. Издательство: ДиаСофт, 2002. - 688 с. Приложение 1. Программный код // Количество бит для кода const int bits_in_register = 16; // Максимально возможное значение кода const int top_value = (int)(((long)1 << bits_in_register) - 1); // Диапазоны const int first_qtr = (top_value / 4 + 1); const int half = (2 * first_qtr); const int third_qtr = (3 * first_qtr); // Количество символов алфавита const int no_of_chars = 256; // Специальный символ Конец файла const int eof_symbol = (no_of_chars + 1); // Всего символов в модели const int no_of_symbols = (no_of_chars + 1); // Порог частоты для масштабирования const int max_frequency = 16383; // Таблицы перекодировки public int[] index_to_char = new int[no_of_symbols]; public int[] char_to_index = new int[no_of_chars]; // Таблицы частот public int[] cum_freq = new int[no_of_symbols + 1]; public int[] freq = new int[no_of_symbols + 1]; // Регистры границ и кода public static long low, high; public static long value; // Поддержка побитовых операций с файлами public static long bits_to_follow; // Буфер public static int buffer; // Количество бит в буфере public static int bits_to_go; // Количество бит после конца файла public static int garbage_bits; // Указатель на входной файл FileStream datain; // Указатель на выходной файл FileStream dataout; //-------------------------------------------------------------- // Инициализация адаптивной модели public void start_model () { int i; // Установки таблиц перекодировки for ( i = 0; i < no_of_chars; i++) { char_to_index [i] = i + 1; index_to_char [i + 1] = i; } // Установка счетчиков накопленных частот for ( i = 0; i <= no_of_symbols; i++) { freq [i] = 1; cum_freq[i] = no_of_symbols - i; } freq [0] = 0; } //------------------------------------------------------------ // Обновление модели очередным символом void update_model(int symbol) { // Новый индекс int i; int ch_i, ch_symbol; int cum; // Проверка на переполнение счетчика частоты if (cum_freq[0] == max_frequency) { cum = 0; /* Масштабирование частот при переполнении (если счетчики частот достигли своего максимума, то делим на пополам) */ for (i = no_of_symbols; i >= 0; i--) { freq[i] = (freq[i] + 1) / 2; cum_freq[i] = cum; cum += freq[i]; } } /* Обновление перекодировочных таблиц в случае перемещения символа */ for (i = symbol; freq[i] == freq[i - 1]; i--) ; if (i < symbol) { ch_i = index_to_char[i]; ch_symbol = index_to_char[symbol]; index_to_char[i] = ch_symbol; index_to_char[symbol] = ch_i; char_to_index[ch_i] = symbol; char_to_index[ch_symbol] = i; } // Увеличить значение счетчика частоты для символа freq[i] += 1; // Обновление значений в таблицах частот while (i > 0) { i -= 1; cum_freq[i] += 1; } } //------------------------------------------------------------ // Инициализация побитового ввода void start_inputing_bits () { bits_to_go = 0; garbage_bits = 0; } //------------------------------------------------------------ // Ввод очередного бита сжатой информации int input_bit () { int t; // Чтение байта если буфер пуст if (bits_to_go == 0) { buffer = datain.ReadByte(); if (buffer == -1) { /* Помещение битов после конца файла, с проверкой небольшого их количества */ garbage_bits += 1; if (garbage_bits > bits_in_register - 2) { Application.Exit(); } eof = buffer; } bits_to_go = 8; } // Выдача очередного бита с правого конца t = buffer & 1; buffer >>= 1; bits_to_go -= 1; return t; } //------------------------------------------------------------ // Инициализация побитового вывода public void start_outputing_bits () { buffer = 0; bits_to_go = 8; } //------------------------------------------------------------ // Вывод очередного бита сжатой информации public void output_bit(int bit) { // Бит - в начало буфеpа buffer >>= 1; if (bit == 1) buffer |= 0x80; bits_to_go -= 1; // Вывод полного буфера if (bits_to_go == 0) { dataout.WriteByte((byte)buffer); bits_to_go = 8; } } //------------------------------------------------------------ // Очистка буфера побитового вывода public void done_outputing_bits () { dataout.WriteByte((byte)(buffer >> bits_to_go)); } //------------------------------------------------------------ // Вывод указанного бита и отложенных ранее public void output_bit_plus_follow(int bit) { output_bit(bit); while (bits_to_follow > 0) { output_bit(~bit + 2); bits_to_follow--; } } //------------------------------------------------------------ // Инициализация регистров границ и кода перед началом сжатия public void start_encoding() { // Полный кодовый интервал low = 0L; high = top_value; bits_to_follow = 0L; } //------------------------------------------------------------ // Очистка побитового вывода public void done_encoding () { /* Вывод двух бит, определяющих четверть, лежащую в текущем интервале */ bits_to_follow++; if (low < first_qtr) output_bit_plus_follow (0); else output_bit_plus_follow (1); } //------------------------------------------------------------ /* Инициализация регистров перед декодированием. Загрузка начала сжатого сообщения*/ void start_decoding () { int i; int a; value = 0L; // Воод бит для заполнения значения кода for (i = 1; i <= bits_in_register; i++) { a = input_bit(); value = 2 * value + a; } // Текущий интервал равен исходному low = 0L; high = top_value; } //------------------------------------------------------------ // Кодирование очередного символа public void encode_symbol(int symbol) { // Ширина текущего кодового интервала long range; range = (long)(high - low) + 1; // Пересчет значений границ high = low + (range*cum_freq[symbol - 1]) / cum_freq[0] - 1; low = low + (range*cum_freq[symbol]) / cum_freq[0]; // Вывод битов for ( ; ; ) { // Если в нижней половине if (high < half) output_bit_plus_follow(0); // Если в верхней половине else if (low >= half) { output_bit_plus_follow(1); low -= half; high -= half; } /* Если текущий интервал содержит середину, то вывод еще одного обратного бита позже */ else if (low >= first_qtr && high < third_qtr) { bits_to_follow += 1; low -= first_qtr; high -= first_qtr; } else break; // Расширить текущий рабочий кодовый интервал low = 2 * low; high = 2 * high + 1; } } //------------------------------------------------------------ // Декодирование очередного символа int decode_symbol () { // Ширина интервала long range; // Накопленная частота int cum; // Декодируемый символ int symbol; int a; // Определение текущего масштаба частот range = (long) (high - low) + 1; // Hахождение значения накопленной частоты для value cum=(int)((((long)(value-low)+1)*cum_freq[0]-1)/ range); // Поиск соответствующего символа в таблице частот for (symbol = 1; cum_freq [symbol] > cum; symbol++); // Пересчет границ high = low + (range*cum_freq[symbol - 1]) / cum_freq[0] - 1; low = low + (range * cum_freq [symbol]) / cum_freq [0]; // Удаление очередного символа из входного потока for (;;) { // Расширение нижней половины if (high < half) { } // Расширение верхней половины else if (low >= half) { value -= half; low -= half; high -= half; } // Расширение середины else if (low >= first_qtr && high < third_qtr) { value -= first_qtr; low -= first_qtr; high -= first_qtr; } else break; // Увеличение масштаба интервала low = 2 * low; high = 2 * high + 1; // Добавить новый бит a = input_bit(); value = 2 * value + a; } return symbol; } //-------------------------------------------------------------- // Собственно адаптивное арифметическое кодирование public void encode(string infile, string outfile) { int ch, symbol; try { dataout = new FileStream(outfile, FileMode.Create); } catch (IOException exc) { return; } try { datain = new FileStream(infile, FileMode.Open); } catch (FileNotFoundException exc) { return; } start_model(); start_outputing_bits(); start_encoding(); // Цикл обработки символов for ( ; ; ) { try { // Чтение исходного символа ch = datain.ReadByte(); } catch (Exception exc) { return; } // Выход при достижении конца файла if (ch == -1) break; // Найти рабочий символ symbol = char_to_index[ch]; // Закодировать символ encode_symbol(symbol); // Обновить модель update_model(symbol); } // Закодировать символ конца файла encode_symbol(eof_symbol); // Завершение кодирования done_encoding(); done_outputing_bits(); dataout.Close(); datain.Close(); } //------------------------------------------------------------ // Собственно адаптивное арифметическое декодирование void decode(string infile, string outfile) { int ch, symbol; try { dataout = new FileStream(outfile, FileMode.Create); } catch (IOException exc) { return; } try { datain = new FileStream(infile, FileMode.Open); } catch (FileNotFoundException exc) { return; } start_model (); start_inputing_bits (); start_decoding (); // Цикл обработки сиволов for (;;) { // Получаем индекс символа symbol = decode_symbol (); if (symbol == eof_symbol) break; // Получаем декодированный символ ch = index_to_char [symbol]; // Записываем в выходной файл dataout.WriteByte((byte)ch); // Обновляем модель update_model (symbol); } dataout.Close(); datain.Close(); } Приложение 2. Интерфейс программы Примечание. Для работы программы необходим Microsoft .NET Framework 2.0.
Страницы: 1, 2, 3, 4
|