LN - 1 Các bước dưới đây trình bày giải thuật mã hoá Huffman.. 13.2.1 Giải thuật thu gọn Các bước của giải thuật thu gọn được trình bày tốt nhất theo các bước sau đây: Đặt M = N và co
Trang 1Hạn chế thứ hai chỉ ra rằng không có thông báo nào được mã hoá theo cách
mà khi từ mã xuất hiện, bit nối bit, như là một phần của từ mã lớn hơn Ví dụ,
01, 102, và 202 là các từ mã hợp lệ Một dãy của các từ mã xuất hiện có dạng
1111022020101111102 có thể tách ra thành 111-102-202-01-01-111-102 Tất
cả các vấn đề mà chúng ta cần quan tâm khi giải mã là bộ mã gốc Nếu như một bộ mã bao gồm 11, 111, 102, 02 thì khi một thông báo bắt đầu vói 11, ta
sẽ không biết liệu đây là thông báo 11 hay đây là phần bắt đầu của thông báo
111 Nếu một thông báo 11102 xuất hiện thì ta sẽ không biết liệu đây là
111-02 hoặc là 11-1111-02 được truyền đi
Mã Huffman được mã hoá theo hai hạn chế trên đây và gọi là mã có độ dư thừa tối thiểu hay gọi là mã tối ưu Phương pháp mã hoá này theo hai bước: bước thu gọn và bước mở rộng Để xem xét phương pháp mã hoá này ta coi rằng các thông báo để xây dựng từ mã được sắp xếp theo thứ tự xác suất xuất hiện giảm dần
p(0) p(1) p(2) p(N - 1)
Ở đây N là số của các thông báo Như tôi đã chỉ ra ban đầu, cho bộ mã hoá tối ưu thì độ dài của từ mã được xắp xếp theo thứ tự
L(0) L(1) L(2) L(N - 1)
Các bước dưới đây trình bày giải thuật mã hoá Huffman Giải thuật này, cũng như phần lớn các giải thuật khác trong cuốn sách này, được phát triển bởi chính tác giả
13.2.1 Giải thuật thu gọn
Các bước của giải thuật thu gọn được trình bày tốt nhất theo các bước sau đây:
Đặt M = N và coi đây là một mảng tuyến tính có kích thước N - 2
Cho i = 0 đến N - 3 lặp lại các bước sau:
{
Cộng p(M) và p(M - 1) Thay p(M - 1) bằng kết quả thu được
Xác định vị trí, loc, trong M - 1 vị trí đầu tiên của mảng p trong đó p(M - 1)
> p(loc)
Đặt temp = p(M - 1)
Chuyển các giá trị từ p(loc) đến p(M - 2) xuống một vị trí
Đặt giá trị trung gian vào loc
Lưu giá trị trung gian trong mảng tuyến tính v theo
v(N - 2 - i) = loc
Giảm M đi một giá trị
}
Để hiểu giải thuật thu gọn ta xem xét ví dụ sau Giả sử rằng khả năng xuất hiện của các thông tin là:
p = {0.25, 0.25, 0.125, 0.125, 0.0625, 0.0625, 0.0625, 0.0625}
Trang 2Giải thuật thu gọn được trình bày ở trên, cho trường hợp này, trong hình 13.1, từ đó chúng ta có thể viết:
5 6 3 4 1 2
v
Hình 13.1 Giải thuật thu gọn
Mảng tuyến tính v được dùng để xây dựng mã hoá Huffman theo bước mở
rộng được trình bày ở dưới đây
13.3.2 Bước mở rộng
Bước giải thuật này có thể trình bày theo các bước sau:
1) Gán các giá trị ban đầu cho một mảng H theo:
H
H H H
H N
0 1 0 0
0
1 2 3
.
( ) ( ) ( ) ( ) Chú ý là phần tử thứ hai bằng 1 còn các phần tử khác bằng 0
Véc tơ tuyến tính
0.0625 0.0625
0.0625
0.25 0.25 0.25 0.25 0.25
2
3
4
5
6
7
8
0.25 0.25 0.25 0.25 0.25 0.5 0.125 0.125 0.125 0.25
0.125 0.125 0.125
0.0625
0.125 0.0625
0.0625
0.125
0.125
0.125
0.125
0.25
0.25
0.25
0.25
Trang 3v = [v[1] v[2] v[3] v[N - 2]] T
được tính trong bước thu gọn Chú ý là vị trí của các phần tử được cho bằng 1,2,3
2) Đặt M = 2 và i = 1
3) Lưu phần tử ở vị trí v[i] trong mảng H vào một biến trung gian temp
temp = H[v(i)]
4) Dịch chuyển các phần tử các phần tử ở vị trí dưới H[v(i)] một vị trí lên
phía trên Chèn giá trị 0 vào vị trí cuối cùng
5) Sao chép temp tới vị trí thứ M trong H
6) Dịch trái H(M) một bít
1 0 0 1 0 1 0 1 0 1 0 1 0
2 1 1 0 1 1 1 1 1 1 1 1 1 1
3 1 1 0 0 0 0 0 1 0 0 1 0 0 1 0
4 0 1 0 1 0 0 1 1 0 1 1 0 1 1
5 0 1 1 0 0 0 0 0 0 0 0 1 0
6 0 0 1 0 0 1 0 0 0 1 1
7 0 0 1 1 0 0 0 0
8 0 0 0 1
Hình 13.2 Giải thuật mở rộng
7) H[M + 1] = H[M] + 1
8) Tăng M và i lên một
9) Nếu i (N - 2) quay lại bước thứ ba
Nếu không thì đã hoàn thành, và mã nằm trong bảng H
Các bước trên giải thích qua hình 13.2 dùng ví dụ hình 13.1
Các bước trên được lập ra bởi Huffman Lu và Chen đã nhận ra rằng thuật toán của Huffman không phải lúc nào cũng tạo ra một mã có độ dài đơn diệu tăng dần qua ví dụ của họ dưới đây:
Xem xét khả năng xuất hiện thông tin dưới đây:
P
0 5
0 1
0 1
0 1
0 1
0 1
.
Theo giải thuật thu gọn ở trên chúng ta có
Trang 4v
2 2 3 2
và tạo bộ mã
H
0 101 1000 1001 110 111
Bộ mã trên không thoả mãn điều kiện về chiều dài của từ mã đơn điệu tăng dần; tuy nhiên, bộ mã này có thể sử dụng nếu nó thoả mãn điều kiện có khả năng giải mã được Lỗi này có thể sửa được bằng một thay đổi nhỏ theo Lu và Chen trong bước thứ ba từ
p(M - 1) > p(loc) thành p(M - 1) p(loc)
Theo phương pháp này cho ta kết quả
v
1 2 2 2
và tạo ra một bộ mã
H
1 001 010 011 0000 0001 Chú ý là thuật toán Lu và Chen tạo ra bộ mã thì hoàn thiện hơn thuật toán mô
tả ở trên
Trang 5Chương trình dưới đây tạo ra bộ mã dùng các bước thu gọn và mở rộng ở trên Chương trình này sử dụng thuật toán Lu và Chen mô tả ở trên Chương trình cũng tính trung bình độ dài từ Chương trình không dùng trên ảnh, mà chỉ minh hoạ các bước thực hiện việc sinh mã Huffman Chú ý điều kiện dùng trong bước 3 của quá trình thu nhỏ được thay bằng điều kiện của Lu và Chen
Chương trình 13.1 Chương trình ví dụ sinh mã Huffman
/*Program 13.1 "HUFFMAN.C" Example program for
generating the Huffman code.*/
/* Example program to demonstrate the
algorithm for the generation procedure
of the Huffman code */
#include <stdio.h>
#include <conio.h>
/*float p[]={0.2, 0.18, 0.1, 0.1, 0.1, 0.06, 0.06,
0.04, 0.04, 0.04, 0.04, 0.03, 0.01};
int N=13;*/
float p[]={0.5,0.1,0.1,0.1,0.1,0.1};
int N=6;
void main()
{
int i,M,j,loc;
unsigned char v[11],L[13],code[13];
unsigned char ctemp,Ltemp;
float temp,sum,pt[13];
for(j=0;j<N;j++)
pt[i]=p[j];
clrscr();
for(i=0;i<(N-2);i++)
v[i]=0;
/* Contraction */
M=N;
for(i=0;i<(N-2);i++)
{
p[M-2]=p[M-1]+p[M-2];
loc=M-2;
for(j=0;j<(M-1);j++)
{
if(p[M-2]>=p[j])
{
loc=j;
Trang 6break;
}
}
temp=p[M-2];
for(j=M-2;j>=loc;j )
p[j]=p[j-1];
p[loc]=temp;
M ;
v[(N-3)-i]=loc;
}
printf("\n The v vector is given by:\n");
for(j=0; j<(N-2); j++)
printf ("%d\n", v[j]+1);
/*Expansion.*/
for(j=0; j<N; j++)
{
code[j]=0 ;
L[j]=1;
}
printf("\n\n ");
code[0]=0;
code[1]=1;
M=1;
for(i=0; i<(N-2);i++)
{
if(v[i]==M)
{
code[M+1]=(code[M]<<1)+1;
code[M]=(code[M])<<1;
L[M]++;
L[M+1]=L[M];
}
else
{
ctemp=code[v[i]];
Ltemp=L[v[i]];
for(j=v[i];j<M;j++)
{
code[j]=code[j+1];
L[j]=L[j+1];
}
code[M]=ctemp;
L[M]=Ltemp;
code[M+1]=(code[M]<<1)+1;
Trang 7code[M]=code[M]<<1;
L[M]++;
L[M+1]=L[M];
}
M++;
}
printf("Code words Length\n");
for(j=0;j<N;j++)
printf(" %d %d\n",code[j],L[j]); sum=0.0;
for(j=0;j<N;j++)
sum+=pt[j]*(float)L[j];
printf("Lav.=%f",sum);
getch();
}
Độ dài từ trung bình được tính bởi công thức (13.1) Chú ý rằng chương trình cũng tính độ dài các bit của mỗi mã và độ dài từ trung bình Độ dài sẽ mã cần thiết cho việc mã hoá và giải mã các tín hiệu
Bài tâp 13.1
1 Chạy chương trình 13.1 dùng ví dụ cho trong tài liệu của Huffman:
p = {0.2, 0.18, 0.1, 0.1, 0.1, 0.06, 0.06, 0.04, 0.04, 0.04, 0.04, 0.03, 0.01}
2 Đổi giả thiết:
if (p[M - 1] p[j]
thành
if (p[M - 1] > p[j])
trong chương trình Chạy chương trình và so sánh với bộ mã cho bởi Lu
và Chen
3 Dùng ví dụ cho bởi Lu và Chen, chú ý sự khác nhau trong chiều dài từ mã vói hai điều kiện khác nhau
Nhiệm vụ tiếp theo của chúng ta thật rõ ràng Chúng ta cần viết một chương trình C để mã hoá và giải mã ảnh số dùng lược đồ mã Huffman Chương trình
sẽ bao gồm: tính toán khả năng xảy ra của mỗi mức xám và xắp xếp lại theo thứ tự giảm dần của khả năng có thể Tất nhiên, chương trình cũng bao gồm một vector để lưu giữ các thông tin cần thiết về các mức xám theo khả năng của các sự kiện, ví dụ, một bảng tra cứu Chương trình cũng sẽ loại trừ các sự kiện không có khả năng xảy ra Khi các bước ở trên được thực hiện, mã
Trang 8Huffman được sinh ra theo giải thuật được mô tả trên Trong việc mã hoá ảnh
số bạn cần nhớ rằng chương trình sẽ cần nhiều byte trên đĩa Khi viết một thủ tục giải mã ta cần chú ý đến giới hạn này
13.2.3 Mã hoá ảnh số
Trước khi mã hoá ta cần tạo ra hai bảng tra cứu:
1 Một bảng tra cứu (LUT) chứa quan hệ các giá trị mức xám trên ảnh vói
bộ mã hoá Huffman Bảng LUT này có thể phát triển dùng quan hệ: table_code[gray[i]] = code[i]
ở đây code[i] là mã Huffman
2 Một bảng tra cứu xác lập quan hệ giữa các mức xám trên ảnh vói chiều dài từ mã Huffman LUT có thể tạo ra theo mối quan hệ sau:
table_length [ gray[i]] = L[i]
Mã hoá theo các bước sau:
a Mở một file để chứa ảnh đã được mã hoá
b Đặt Len = 0 và aux = 0
aux là một thanh ghi bốn byte để truyền mã
Len chứa số các bít còn lại trong aux
c Đọc giá trị điểm ảnh
d Xác định mã Huffman của nó, code[i], và độ dài của từ mã L[i], dùng hai bảng LUT để tạo ra giá trị ban đầu
e Dịch aux sang trái L[i] bit
f Thực hiện phép logic OR code[i] với aux
g Len = Len + L[i]
h Nếu Len 8 thì chuyển 8 bit cuối đến file đầu ra và giảm Len đi 8
i Nếu chưa hết file thì chuyển đến bước c
k Chuyển các bít còn lại trong thanh ghi aux ra file đầu ra
Để giải mã được ảnh chúng ta cần phải tạo thêm phần header của file Header của file bao gồm cả chiều dài thực sự của file tính theo bit Chú ý là chiều dài thực sự có thể lớn hơn hoặc bằng chiều dài thực sự của file Điều này bởi vì chúng ta chỉ có thể chứa dưới dạng đơn vị byte, còn file ảnh đã mã hoá phải có chiều dài không chia hết cho 8 Phần này chứa đủ thông tin để thiết lập các bảng LUT, dùng cho việc giải mã ảnh Nó bao gồm các mức xám trên ảnh, dạng mã Huffman và chiều dài tương đương của chúng Chú ý rằng các từ mã được sắp xếp theo thứ tự giảm dần theo xác suất xuất hiện của chúng
Chương trình C sau đây sẽ trình bày các bước trên
Chương trình 13.2 "HUCODING" Mã hoá Huffman ảnh số
/*Program 13.2 "HUCODING.C" Huffman coding of
digital images.*/
Trang 9/* This program is for coding a binary file
using Huffman codes */
#include <stdio.h>
#include <conio.h>
#include <io.h>
#include <alloc.h>
#include <string.h>
#include <process.h>
void main()
{
int i,j,N,M,loc,k,ind,xt,yt;
unsigned char *v,*L,*gray, *table_length;
unsigned long int *code, *table_code, ctemp2;
unsigned long int aux1,aux2,Lmask,act_len,flength; unsigned char mask,Len;
int ch;
unsigned char ctemp,Ltemp;
float temp, sum, *pt, *p, big;
unsigned long int *histo;
double nsq;
char file_name1[14], file_name2[14];
FILE *fptr,*fptro;
clrscr();
printf("Enter file name of image >");
scanf("%s",file_name1);
fptr=fopen(file_name1,"rb");
if(fptr==NULL)
{
printf("%s does not exist ",file_name1 ); exit(1);
}
printf("\nEnter file name for compressed image
>");
scanf("%s",file_name2);
k=stricmp(file_name1 ,file_name2);
if (k==0)
{
printf("\nInput and output files cannot share the same name.");
fcloseall();
exit(1);