Сжатие данных методами Хафмана и Шеннона-Фано
Типы сжатия данных: с потерями (lossy) и без потерь (lossless). Сжатие с минимальной избыточностью. Кодирование методом Шеннона-Фано. Проверка работы программы по сжатию файлов формата bmp и xls. Реализация на Delphi алгоритма сжатия Шеннона и Хаффмана.
Рубрика | Программирование, компьютеры и кибернетика |
Вид | курсовая работа |
Язык | русский |
Дата добавления | 26.01.2011 |
Размер файла | 2,6 M |
Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже
Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.
Else //иначе
Begin //если найден символ
If (Tree^.left=nil) and (Tree^.right=nil)
and (Tree^.Symbol=i)
Then //HSymbolToCodWord //помечаем символ найден
HSymbolToCodWord:='+'
Else //иначе
HSymbolToCodWord:=''; //символа нет
End;
End;
End;
End;
//вспомогательная функция для определения Кодового слова
//сжатой последовательности битов для исходного байта i (с учетом
//того экстремального случая, когда исходный файл состоит всего из одного
//и того же символа)
Function SymbolToCodWord(Tree: TByte; i: Byte): String;
var
s: String;
Begin //Вызыаем ф-ию поиска кодовых слов
s:=HSymbolToCodWord(Tree, i);
s:=s;
If (s='+'){если функция HSymbolToCodWord вернула строку
содержащую '+' т.е. исходный файл состоит из одного и того же
символа то кодовому слову присваиваем строку из '0' }
Then
SymbolToCodWord:='0'
Else {иначе уменьшаем строку на один символ т.е. убираем '+'
признак того что символ найден}
SymbolToCodWord:=Copy(s,1,length(s)-1);
End;
//процедура записи сжатого потока битов в архив
Procedure WriteInFile(var buffer: String);
var
i,j: Integer;
k: Byte;
buf: Array[1..2*count] of byte;
Begin
i:=Length(buffer) div 8; // узнаем сколько получится
//байт в каждой последовательности
//////////////////////////
For j:=1 to i do //работаем с байтами от превого элемента
//массива до последнего
Begin
buf[j]:=0;//обнуляем тот элемент мссива в
//который будем писать
///////////////////////////
For k:=1 to 8 do//работаем с битами
Begin
If buffer[(j-1)*8+k]='1'{находим в строке тот элементкоторый будем записывать в виде последовательности бит(будем просматривать с (j-1) элемента строки buffer восемь элментов за ним тем самым сформируется строка из восьми '0' и '1'. Эту строку мы будем преобразовывать в байт,который должен будет содержать такуюже последовательность бит)} Then {Преобразование будем производить с помощью операции битового сдвига влево shl и логической опереоции или (or). Делается это так поверяется условие buffer[(j-1)*8+k]='1' если в выделенной строке из восьми символов (мы просматриваем её по циклу от первого элемента до восьмого), элемент, индекс которого равен счётчику цикла к, равен единице, то к соответствующему биту (номер которого в байте равен переменной цикла к) будет применена операция or (0 or 1=1) т.е. это бит примет значение 1. Если в строке будет ноль то и соответствующий бит будет равен нулю. (нам его не требуется устанавливать т.к. в начале работы с каждым байтом мы его обнуляем)}
buf[j]:=buf[j] or (1 shl (8-k));
Application.ProcessMessages;
End;
Application.ProcessMessages;
End; //записываем в файл получивийся буфер
BlockWrite(FileToWrite,buf,i);
Delete(buffer,1,i*8);//удаляем из входного буфера те элементы
//которые уже записаны()
End;
//процедура для окончательной записи остаточной цепочки битов в архив
Procedure WriteInFile_(var buffer: String);
var
a,k: byte;
Begin
{Так как эту процедуру вызывает процедура которая передаёт в буфереотнюдь не один последний байт, то срау вызываем процедуруобычной записи в файл. После работы которой в buffer должнаостася последвательность из не более 8 символов. По этомумы производим проверку и если что то не так то выводим сообщение.
Иначе устанавливаем в переменной а все биты в 1 и далее производимследующие действия: Просматриваем по циклу всё что осталось вbuffer и если найдётся символ '0' то к сответтвующему биту переменной априменяем операцию xor (т.е. 1 xor 1 что даст 0) т.е. оответствующийбит установится в 0 все остальные биты переменной а останутся в том жесостоянии что и были. Оставшиеся биты будут единицами}
WriteInFile(buffer);
If length(buffer)>=8
Then
ShowMessage('ошибка в вычислении буфера')
Else
If Length(buffer)<>0
Then
Begin
a:=$FF;
for k:=1 to Length(buffer) do
If buffer[k]='0'
Then
a:=a xor (1 shl (8-k));
BlockWrite(FileToWrite,a,1);
End;
End;
Type
Integer_=Array [1..4] of Byte;
//перевод числа типа Integer в массив из четырех байт.
Procedure IntegerToByte(i: Integer; var mass: Integer_);
var
a: Integer;
b: ^Integer_;
Begin
b:=@a;// соединяем адресс переменной а с b
a:=i;//в а перегоняем наше значение типа integer
mass:=b^;{разименовываем b и соединяем результат с massв результате работы этого кода число типа Integerперейд в массив из 4 байт. Это требуется для того что ,бы мызапись в файл производим по байтно}
End;
//перевод массива из четырех байт в число типа Integer.
Procedure ByteToInteger(mass: Integer_; var i: Integer);
var
a: ^Integer;
b: Integer_;
Begin
a:=@b;// соединяем адресс переменной b с а
b:=mass;//b присваиваем значение mass
i:=a^;{разименовываем а и соединяем результат с i
в результате работы этого кода массив из 4 байтперейд в число типа Integer. Это требуется для того что бы мымогли узнать наши значения типа Integer}
End;
//процедура создания заголовка архива
Procedure CreateHead;
var
b: Integer_;
//a: Integer;
i: Byte;
Begin
//Записываем размер несжатого файла
IntegerToByte(MainFile.Size,b);
BlockWrite(FileToWrite,b,4);
//Записываем количество оригинальных байт
BlockWrite(FileToWrite,MainFile.Stat.CountByte,1);
{зисываем байты со статистикой (на каждую запись требуется по пять байт. Первый байт содержит сам символ далее идут 4 байта со статистикой (Intege занимает 4 байта)}
For i:=0 to MainFile.Stat.CountByte do
Begin
BlockWrite(FileToWrite,MainFile.Stat.massiv[i]^.Symbol,1);
IntegerToByte(MainFile.Stat.massiv[i]^.SymbolStat,b);
BlockWrite(FileToWrite,b,4);
End;
End;
const
MaxCount=4096;
type
{buffer_ это объект включающий в себя массив из байт ArrOfByteсчётчик байт ByteCount (необходим для учёта промежуточнойзапися разархивируемых байт в файл)и основной счётчик (необходимдля отслеживани какое количество байт должно быть разархивированокак только он стнет равным размеру сжимаемого файла то процессразархивирования первётся)}
buffer_=object
ArrOfByte: Array [1..MaxCount] of Byte;
ByteCount: Integer;
GeneralCount: Integer;
Procedure CreateBuf;//процедура инициализации
Procedure InsertByte(a: Byte);//процедура вставки
//разархивированных байтов в файл
Procedure FlushBuf;
End;
/////////////////////////////
Procedure buffer_.CreateBuf;
Begin
ByteCount:=0;//иициализируем переменные
GeneralCount:=0;
End;
////////////////////////////////////////
Procedure buffer_.InsertByte(a: Byte);
{В переменной а мы передаём значение разархивированного байта,которое получили в вызывающей процедуре}
Begin //до тех пор пока GeneralCount меньше
//размера сжимаемого файла деаем
if GeneralCount<MainFile.Size
Then
Begin
inc(ByteCount); //увеличиваем соответствующие
//счётчики на единицу
inc(GeneralCount);
ArrOfByte[ByteCount]:=a;//загоняем в массив ArrOfByte
//значение полученное в переменной а
//////////////////////////
if ByteCount=MaxCount //если ByteCount=MaxCount
//то записываем содержимое массива в разархивируемый файл
Then
Begin
BlockWrite(FileToWrite,ArrOfByte,ByteCount);
ByteCount:=0;
//Form1.ProgressBar1.Position:=form1.ProgressBar1.Position+1;
End;
End;
End;
////////////////////////////
Procedure Buffer_.FlushBuf;
//Процедура записи остаточной цепочки байт
Begin
If ByteCount<>0
Then
BlockWrite(FileToWrite,ArrOfByte,ByteCount);
End;
//создание деархивированного файла
Procedure CreateDeArc;
var
i,j: Integer;
k: Byte;
//////////////
Buf: Array [1..Count] of Byte;
CountBuf, LastBuf: Integer;
MainBuffer: buffer_;
CurrentPoint: TByte;
Begin
//определяем сколько целых буферов по 4 кбайт в сжатом
//файле без заголовка
CountBuf:=MainFile.FileSizeWOHead div count;
//определяем сколько останеся байт не вошедших
//в целые буферы по 4 кбайт в сжатом файле без заголовка
LastBuf:=MainFile.FileSizeWOHead mod count;
MainBuffer.CreateBuf;//иициализируем переменные
CurrentPoint:=MainFile.Tree;//присваиаем текущую
//позицию на корень дерева
//начинаем расаковку
For i:=1 to CountBuf do
Begin//считываем из сжатого файла данные в буфер
BlockRead(FileToRead,buf,count);
for j:=1 to Count do //по байтно начинаем
//просматривать буфер
Begin
for k:=1 to 8 do//просматриваем биты от 1 до 8
//выеленного байта
Begin {Выделяем байт в массиве. По циклу от 1 до 8просматриваем значения его бит с 7 до 0. Для этого используетсяоперация битового сдвига влево shl и логиеская операция and.
В цикле всё происходит следующим образом: Сначала просматриваетсястарший бит (8-к)=1 и производится логическая операция and,если бит равен 1 то (1 and 1)=1 и программа установит текущую позицию поиска в дереве на правый узел, если же бит равен 0 то (0 and 1)=0 и программа установит текущую позицию поиска в дереве на левый узел. так будет продолжатся до тех пор пока не выполнится условие, которое ознчает нахождение искомого символа ((CurrentPoint^.left=nil) or (CurrentPoint^.right=nil))
После этого будет вызвана процедура вставки байта, после возвращения из которой мы текущую точку опять устанавливаем на корень}
If (Buf[j] and (1 shl (8-k)))<>0
Then
CurrentPoint:=CurrentPoint^.right
Else
CurrentPoint:=CurrentPoint^.left;
if (CurrentPoint^.left=nil) or (CurrentPoint^.right=nil)
Then
Begin
MainBuffer.InsertByte(CurrentPoint^.Symbol);
CurrentPoint:=MainFile.Tree;
End;
Application.ProcessMessages;
End;
Application.ProcessMessages;
End;
End;
If LastBuf<>0
Then
Begin//работа этого блока программы аналогична предидущему
BlockRead(FileToRead,Buf,LastBuf);
for j:=1 to LastBuf do
Begin
for k:=1 to 8 do
Begin
If (Buf[j] and (1 shl (8-k)))<>0
Then
CurrentPoint:=CurrentPoint^.right
Else
CurrentPoint:=CurrentPoint^.left;
if (CurrentPoint^.left=nil) or (CurrentPoint^.right=nil)
Then
Begin
MainBuffer.InsertByte(CurrentPoint^.Symbol);
CurrentPoint:=MainFile.Tree;
End;
Application.ProcessMessages;
End;
Application.ProcessMessages;
End;
End;
MainBuffer.FlushBuf;
End;
//процедура чтения заголовка архива
Procedure ReadHead;
var
b: Integer_; // исходный размер файла
SymbolSt: Integer;//статистика символа
count_, SymbolId, i: Byte;//SymbolId=Symbol просто чтобы
// не путать глобальную переменную с локальной
Begin
try
//узнаем исходный размер файла
BlockRead(FileToRead,b,4);
ByteToInteger(b,MainFile.size);
//узнаем количество оригинальных байтов
BlockRead(FileToRead,count_,1);
{}{}{Вызываем процедуру инициализации объекта}
MainFile.Stat.create;
MainFile.Stat.CountByte:=count_;
//загоняем частоты в массив
for i:=0 to MainFile.Stat.CountByte do
Begin
BlockRead(FileToRead,SymbolId,1);
MainFile.Stat.massiv[i]^.Symbol:=SymbolId;
BlockRead(FileToRead,b,4);
ByteToInteger(b,SymbolSt);
MainFile.Stat.massiv[i]^.SymbolStat:=SymbolSt;
End;
//вызываем процедуру создания дерева
CreateTree(MainFile.Tree,MainFile.stat.massiv,MainFile.Stat.CountByte);
/////////////
//Вызываем процедуру распаковки файла
CreateDeArc;
//////////////
//Вызываем процедуру уничтожения дерева
DeleteTree(MainFile.Tree);
except
ShowMessage('архив испорчен!');
End;
End;
//процедура извлечения архива
Procedure ExtractFile;
Begin
AssignFile(FileToRead,MainFile.Name);
//соединяем наш файл файловй переменой передэтим
//вызываем метод получения имени разархивированого файла
AssignFile(FileToWrite,MainFile.DeArcName);
try
Reset(FileToRead,1);
Rewrite(FileToWrite,1);
//процедура чтения шапки файла
ReadHead;
Closefile(FileToRead);
Closefile(FileToWrite);
Except
ShowMessage('Ошибка распаковки файла');
End;
End;
//вспомогательная процедура для создания архива
Procedure CreateArchiv;
var
buffer: String;//строка в которой будет формироватся
//последовательность из кодовых слов
ArrOfStr: Array [0..255] of String;
i,j: Integer;
//////////////
buf: Array [1..count] of Byte;//массив в который
//будем считывать данные из архивируемого файла
CountBuf, LastBuf: Integer;
Begin
Application.ProcessMessages;
AssignFile(FileToRead,MainFile.Name);
AssignFile(FileToWrite,MainFile.ArcName);
Try
Reset(FileToRead,1);
Rewrite(FileToWrite,1);
//Инициализируем массив строк в котором будут
//хранится кодовые слова
For i:=0 to 255 Do ArrOfStr[i]:='';
//Загоням в массив строк кодовые слова соответсвующие
//своим символам
For i:=0 to MainFile.Stat.CountByte do
Begin
ArrOfStr[MainFile.Stat.massiv[i]^.Symbol]:=
MainFile.Stat.massiv[i]^.CodWord;
Application.ProcessMessages;
End;
//узнаём какое целое количество буферов по 4 кбайт будет содержатся в
//сжимаемом файле
CountBuf:=MainFile.Size div Count;
//Сколько останется байт для записи не вошедших в ранее
//определённое значение CountBuf
LastBuf:=MainFile.Size mod Count;
Buffer:='';//обнуляем буфер
/////////////
CreateHead; //вызываем процедуру создания заголовка файла
/////////////
//фрмируем буфер кодовых слов
for i:=1 to countbuf do
Begin
//считываем из файла по 4 кбайт
BlockRead(FileToRead,buf,Count);
//////////////////////
For j:=1 to count do
Begin
//растим буфер из кодовых слов
buffer:=buffer+ArrOfStr[buf[j]];
//если длина buffer превысит значеие 8*4096 (это означает
//превысит размер выходного буфера размер которого 4096байт)
//мы вызываем процедуру записи в файл
If Length(buffer)>8*count
Then
WriteInFile(buffer);
Application.ProcessMessages;
End;
// ProgressBar1.Position:=100 div countbuf;
End;
//Запись оставшейся цепочки байт
If lastbuf<>0
Then
Begin
//считываем в массив из файла оставшиеся байты
BlockRead(FileToRead,buf,LastBuf);
//растим buffer строку из кодовых слов
For j:=1 to lastbuf do
Begin
buffer:=buffer+ArrOfStr[buf[j]];
If Length(buffer)>8*count
//если его размер превысит значение 8*4096 (а это может иметь
//место), то вызываем процедуру записи в файл
Then
WriteInFile(buffer);
Application.ProcessMessages;
End;
End;
//выываем процедуру записи оставшейся цепочки кодовых слов
WriteInFile_(buffer);
CloseFile(FileToRead);
CloseFile(FileToWrite);
Except
ShowMessage('Ошибка создания архива');
End;
End;
//главная процедура для создания архивного файла
Procedure CreateFile; //(802)
var
i: Byte;
Begin
With MainFile do
Begin
{сортировка массива байтов с частотами (192)}
SortMassiv(Stat.massiv,stat.CountByte);
{поиск числа задействованных байтов из массива
(ACSII) возмжных символов. В CountByte будем хранить
количество этох самых символов }
i:=0;//обнуляем счётчик
While (i<Stat.CountByte) //до тех пор пока счётчик
//меньше количества задействовнных байт CountByte
//и статистика байта (частота появления в файле)
//не равна нулю делаем
and (Stat.massiv[i]^.SymbolStat<>0) do
Begin
Inc(i); //увеличиваем счётчик на единицу
End;
//////////////////////
If Stat.massiv[i]^.SymbolStat=0 //если дошли до символа
//с нулевой встречаемостью в файле то
Then
Dec(i); //уменьшаем счётчик на единицу тоесть возвращаемся
//назад это будет последний элемент
//////////////////////
Stat.CountByte:=i;{присваиваем значение счётчика
CountByte. Это означает что в архивируемом файле используется такое количество из 256 возможных символов. Будет исползоватся для построения древа частот} {создание дерева частот. Передаём в процедуру начальные параметры Tree=nil-эта переменная будет содержать после работы процедуры древо ,Stat.massiv-массив с символами и соответствующей им статистикой,а так же указанием на правое и левой дерево,Stat. CountByte количество используемых символов в архивирумом файле (230)} CreateTree(Tree,Stat.massiv,Stat.CountByte); {запускаем в работу дерево с помощью его нахадим соответствующие кодовые слова. Суть алгоритма вызываем функцию SymbolToCodWord(Tree:TByte(указатель на корень дерева. Он у нас выработался в результате работы процедуры CreateTree, Symbol:byte):
String функция вернёт нам строку содержащую кодовое слово ()}
for i:=0 to Stat.CountByte do
Stat.massiv[i]^.CodWord:=SymbolToCodWord(Tree,stat.massiv[i]^.Symbol);
//пишем сам файл
CreateArchiv;
//Удаляем уже ненужное дерево
DeleteTree(Tree);
//Инициализируем статистику файла
MainFile.Stat.Create;
End;
End;
//Основная процедура сжатия файла
procedure RunEncodeHaff(FileName_: string);
begin
MainFile.Name:=FileName_;//передаём имя
//архивируемого файла в программу
StatFile(MainFile.Name); //запускем процедуру создания
//статистики (частоты появления того или иного символа)
//для файла (строка 274)
CreateFile; //вызов процедуры созданя архивного файла (737)
end;
//Основная процедура разархивирования файла
procedure RunDecodeHaff(FileName_: string);
begin
MainFile.name:=FileName_;//передаём имя
//архивируемого файла в программу
ExtractFile;//Вызываем процедуру извлечения архива
end;
end.
Подобные документы
Краткий обзор основных теорий сжатия. Концепции идей и их реализация. Сжатие данных с использованием преобразования Барроуза-Вилера. Статический алгоритм Хафмана. Локально адаптивный алгоритм сжатия. Алгоритм Зива-Лемпеля (Welch) и метод Шеннона-Фано.
практическая работа [188,5 K], добавлен 24.04.2014Обзор существующих программ сжатия данных без потерь. Анализ методов сжатия: алгоритмов группы, KWE, Lossless JPEG, кодирование Хаффмана. Обзор составляющих компонентов. Разработка кода программы-архиватора, работающей на основе алгоритма Хаффмена.
курсовая работа [487,3 K], добавлен 14.07.2011Общее число неповторяющихся сообщений. Вычисление скорости передачи информации и пропускной способности каналов связи. Определение избыточности сообщений и оптимальное кодирование. Процедура построения оптимального кода по методике Шеннона-Фано.
курсовая работа [59,4 K], добавлен 17.04.2009Изучение методов кодирования Хаффмана, Фано. Модель информационной системы Шеннона. Среднестатистическая информационная емкость сообщений для эргодических источников с заданным распределением частот символов. Формулы Хартли для удельной емкости на символ.
презентация [528,9 K], добавлен 19.10.2014Определение среднего количества информации. Зависимость между символами матрицы условных вероятностей. Кодирование методом Шеннона–Фано. Пропускная способность канала связи. Эффективность кодирования сообщений методом Д. Хаффмана, характеристика кода.
контрольная работа [94,6 K], добавлен 04.05.2015Классификация и основные характеристики метода сжатия данных. Вычисление коэффициентов сжатия и оценка их эффективности. Алгоритмы полиноминальных, экстраполяционных и интерполяционных методов сжатия и их сравнение. Оптимальное линейное предсказание.
курсовая работа [1,1 M], добавлен 17.03.2011Применение алгоритмов, обеспечивающих высокую степень сжатия, для увеличения скорости передачи данных по каналам связи. Особенности и методы нахождения сингулярного разложения. Разработка программы, реализующей сжатие изображения с помощью SVD-сжатия.
дипломная работа [3,3 M], добавлен 13.10.2015Исследование основных видов программ-архиваторов. Сжатие файлов при архивации. Показатель степени сжатия файлов. Оценка функциональности самых популярных программ-упаковщиков. Технические характеристики процессов сжатия. Методы архивации без потерь.
реферат [1,6 M], добавлен 05.12.2013Современные методы цифрового сжатия. Классификация алгоритмов сжатия. Оцифровка аналогового сигнала. Алгоритм цифрового кодирования. Последовательное двойное сжатие. Чересстрочность и квантование. Сокращение цифрового потока. Профили, уровни формата MPEG.
реферат [784,9 K], добавлен 22.01.2013Общее понятие архивации. Особенности программ архиваторов. Основные методы сжатия информации. Методические основы изучения темы "Архивация данных и сжатие информации" на уроках информатики в базовом курсе. Разработка блока уроков по сжатию информации.
курсовая работа [3,0 M], добавлен 03.06.2012