You are on page 1of 12

CHUYÊN ĐỀ 3: MÃ HÓA VÀ GIẢI MÃ NGUỒN

3.1 THỜI GIAN


Hướ ng dẫ n đầ u giờ : 0,5 giờ Thí nghiệm: 2,5 giờ
3.2 MỤC ĐÍCH, YÊU CẦU
Sinh viên:
- Hiểu đượ c cơ sở lý thuyết và ứ ng dụ ng mã nguồ n.
- Biết cá ch tạ o ra mã nguồ n sử dụ ng nguyên lý mã Huffman
- Phâ n tích và kiểm nghiệm lý thuyết dự a trên phầ n mềm mã hó a
nguồ n dù ng kỹ thuậ t Huffman.
3.3 CƠ SỞ LÝ THUYẾT
3.3.1 Cơ sở lý thuyết
Thô ng thườ ng, hầ u hết các tậ p tin trong má y tính có rấ t nhiều
thô ng tin dư thừ a, việc thự c hiện nén tậ p tin thự c chấ t là mã hoá lạ i
cá c tậ p tin để loạ i bỏ cá c thô ng tin dư thừ a. Nó i chung khô ng thể có
phương phá p nén tổ ng quá t nà o cho kết quả tố t đố i vớ i tấ t cả cá c loạ i
tậ p tin, kỹ thuậ t nén tậ p tin thườ ng đượ c á p dụ ng cho cá c tậ p tin vă n
bả n trong đó có mộ t số kí tự nà o đó có xá c suấ t xuấ t hiện nhiều hơn
cá c kí tự khá c, cá c tậ p tin ả nh bitmap có thể có nhữ ng mả ng lớ n đồ ng
nhấ t, cá c tậ p tin dù ng để biểu diễn â m thanh dướ i dạ ng số hoá và cá c
tín hiệu tương tự có thể có cá c mẫ u đượ c lặ p lạ i nhiều lầ n. Ðố i vớ i các
tậ p tin nhị phâ n như tậ p tin chương trình thì sau khi nén cũ ng khô ng
tiết kiệm đượ c nhiều.
Ngoà i ra, trong mộ t số trườ ng hợ p để nâ ng cao hệ số nén ngườ i
ta có thể bỏ bớ t mộ t số thô ng tin củ a tậ p tin (Ví dụ như kỹ thậ t nén
ả nh JPEG).
Trong khoa họ c má y tính và lý thuyết thô ng tin, mã hó a Huffman
là mộ t thuậ t toá n mã hó a dù ng để nén dữ liệu. Nó dự a trên bả ng tầ n
suấ t xuấ t hiện cá c kí tự cầ n mã hó a để xâ y dự ng mộ t bộ mã nhị phâ n
cho cá c kí tự đó sao cho dung lượ ng (số bit) sau khi mã hó a là nhỏ
nhấ t.
3.3.2 Mã nguồn
Khái niệm

1/20 Trang
Mã hó a nguồ n chính là nén dữ liệu từ nguồ n tín hiệu trướ c khi
truyền đi để giả m lượ ng dữ liệu phả i truyền đồ ng thờ i thu nhỏ cỡ tậ p
tin giú p cho việc truyền thô ng có hiệu quả hơn.

2/20 Trang
Phân loại và ứng dụng
Có mộ t số phương phá p nén đượ c dù ng phổ biến như: Phương
phá p mã hoá độ dà i loạ t (Run-Length Encoding), Phương phá p nén
LZW, mã hó a Huffman,… Tuy nhiên, thuậ t toá n Huffman có ưu điểm là
hệ số nén tương đố i cao, phương phá p thự c hiện tương đố i đơn giả n,
đò i hỏ i ít bộ nhớ , có thể xâ y dự ng dự a trên cá c mả ng bé hơn 64KB.
Nhượ c điểm củ a nó là phả i chứ a cả bả ng mã và o tậ p tin nén thì phía
nhậ n mớ i có thể giả i mã đượ c do đó hiệu suấ t nén chỉ cao khi ta thự c
hiện nén các tậ p tin lớ n.
3.3.3 Mã Huffman
Cá c tậ p tin củ a má y tính đượ c lưu dướ i dạ ng các kí tự có chiều
dà i khô ng đổ i là 8 bits. Trong nhiều tậ p tin, xá c suấ t xuấ t hiện các kí tự
nà y là nhiều hơn cá c kí tự khá c, từ đó ta thấ y ngay rằ ng nếu chỉ dù ng
mộ t và i bit để biểu diễn cho cá c kí tự có xác suấ t xuấ t hiện lớ n và dù ng
nhiều bit hơn để biểu diễn cho cá c kí tự có xá c suấ t xuấ t hiện nhỏ thì
có thể tiết kiệm đượ c độ dà i tậ p tin mộ t cách đá ng kể. Ví dụ , để mã hoá
mộ t chuỗ i như sau:
"ABRACADABRA"
Nếu mã hoá chuỗ i trên trong dạ ng mã nhị phâ n 4 bit ta sẽ có độ
dà i dãy bit cầ n mã hó a cho chuỗ i ký tự trên là 44.
Ðể giả i mã thô ng điệp nà y, chỉ đơn giả n là đọ c ra 4 bit ở từ ng thờ i
điểm và chuyển đổ i nó tương ứ ng vớ i việc mã hoá nhị phâ n đã đượ c
định nghĩa ở trên. Trong mã chuẩ n nà y, chữ D xuấ t hiện chỉ mộ t lầ n sẽ
cầ n số lượ ng bit giố ng chữ A xuấ t hiện nhiều lầ n.
Ta có thể gá n cá c chuỗ i bit ngắ n nhấ t cho các kí tự đượ c dù ng
nhiều nhấ t, giả sử ta gá n: A là 0, B là 1, R là 01, C là 10 và D là 11 thì
chuỗ i trên đượ c biễu diễn như sau:
0 1 01 0 10 0 11 0 1 01 0
Ví dụ nà y chỉ dù ng 15 bit so vớ i 55 bit như ở trên, nhưng nó
khô ng thự c sự là mộ t mã vì phả i lệ thuộ c và o khoả ng trố ng để phâ n
cá ch cá c kí tự . Nếu khô ng có dấ u phâ n cá ch thì ta khô ng thể giả i mã
đượ c thô ng điệp nà y. Ta cũ ng có thể chọ n cá c từ mã sao cho thô ng
điệp có thể đượ c giả i mã mà khô ng cầ n dấ u phâ n cách, ví dụ như: A là
11, B là 00, C là 010, D là 10 và R là 011, các từ mã nà y gọ i là cá c từ mã
có tính prefix (Khô ng có từ mã nà o là tiền tố củ a từ mã khá c). Vớ i cá c
từ mã nà y, ta có thể mã hoá thô ng điệp trên như sau:
1100011110101110110001111

3/20 Trang
Vớ i chuỗ i đã mã hoá nà y ta hoà n toà n có thể giả i mã đượ c mà
khô ng cầ n dấ u phâ n cách. Nhưng bằ ng cá ch nà o để tìm ra bả ng mã
mộ t cá ch tố t nhấ t ? Và o nă m 1952, D.Huffman đã phá t minh ra mộ t
cá ch tổ ng quá t để tìm ra bả ng mã nà y như sau:
- Bướ c đầ u tiên trong việc xâ y dự ng mã Huffman là đếm số lầ n xuấ t
hiện củ a mỗ i kí tự trong tậ p tin sẽ đượ c mã hoá .
- Bướ c tiếp theo là xâ y dự ng mộ t câ y nhị phâ n vớ i các tầ n suấ t đượ c
chứ a trong cá c nú t. Hai nú t có tầ n số bé nhấ t đượ c tìm thấ y và mộ t nú t
mớ i đượ c tạ o ra vớ i hai nú t con là cá c nú t đó vớ i giá trị tầ n số củ a nú t
mớ i bằ ng tổ ng tầ n suấ t củ a hai nú t con. Tiếp theo hai nú t mớ i vớ i tầ n
suấ t nhỏ nhấ t lạ i đượ c tìm thấ y và mộ t nú t mớ i nữ a lạ i đượ c tạ o ra
theo cá ch trên. Lặ p lạ i như vậ y cho đến khi tấ t cả cá c nú t đượ c tổ hợ p
thà nh mộ t câ y duy nhấ t.
- Sau khi có câ y nhị phâ n, bả ng mã Huffman đượ c phá t sinh bằ ng cách
thay thế cá c tầ n suấ t ở nú t đáy bằ ng cá c kí tự tương ứ ng.
Ưu điểm củ a phương phá p mã hoá Huffman là đạ t đượ c hệ số
nén cao (Hệ số nén tuỳ thuộ c và o cấ u trú c củ a cá c tậ p tin). Nhượ c
điểm củ a phương phá p nà y là bên nhậ n muố n giả i mã đượ c thô ng điệp
thì phả i có mộ t bả ng mã giố ng như bả ng mã ở bên gử i, do đó khi nén
cá c tậ p tin bé hệ số nén khô ng đượ c cao.
Ví dụ:
Mã hó a cho chuỗ i ký tự a từ A đến H vớ i xá c suấ t xuấ t hiện củ a cá c ký
tự như sau:

Ký tự A B C D E F G H

Xá c suấ t (p(m)) 0.1 0.18 0.4 0.05 0.06 0.1 0.07 0.04

Entropy củ a nguồ n là :
8
1
H = ∑ p( m)log 2 = 2.55 (bit/ký tự ) (8.1)
m=1 p (m)

Nếu mỗ i ký tự trên đượ c mã hó a thà nh 3 bit thì hiệu suấ t mã


hó a sẽ giữ nguyên khô ng thay đổ i là 85%.
Mã hó a Huffman thự c hiện mã hó a sử dụ ng ít bit hơn cho cá c ký
tự có xá c suấ t xuấ t hiện cao vì chú ng đượ c truyền đi thườ ng xuyên
hơn và ngượ c lạ i nhiều bit hơn cho cá c ký tự có xác suấ t xuấ t hiện
thấ p nên có thể tă ng đượ c hiệu suấ t.

4/20 Trang
Thự c hiện cá c bướ c như sau:
1. Sắ p xếp cá c ký tự theo thứ tự xá c suấ t giả m dầ n.
2. Gá n cho hai ký tự có xá c suấ t xuấ t hiện thấ p nhấ t vớ i hai nhá nh
(0) và (1) củ a câ y mã . Từ hai ký tự có xác suấ t thấ p nhấ t giả m
cò n mộ t ký tự vớ i xá c suấ t bằ ng tổ ng củ a hai xác suấ t.
3. Lặ p lạ i từ bướ c (1) cho đến khi chỉ cò n lạ i mộ t ký tự duy nhấ t
vớ i xá c suấ t là 1.
4. Duyệt cây mã để tìm ra từ mã tương ứ ng vớ i từ ng ký tự củ a
nguồ n.
Quy ướ c gá n cho nhá nh đi ra từ ký hiệu có xác suấ t cao hơn là 1
và nhá nh kia là 0 thì ta có thể vẽ lạ i câ y mã Huffman vừ a đượ c lậ p như
hình 2.1

Hình 3.1 Cây mã Huffman

5/20 Trang
Nhìn và o câ y mã ta thấ y kết quả mã hó a nguồ n tin như sau:

Ký tự A B C D E F G H

Từ mã 100 110 0 1110 1010 1111 1011 1110


1 0

Độ dài từ mã trung bình bây giờ là:


L = 3*0.1 + 3*0.18 + 1*0.4 + 5*0.05 + 4*0.06 + 4*0.1 + 4*0.07 + 5*0.04
= 2.61 (bit/ký tự)
Như vậy độ lợi mã hóa là:
H 2.55
¿ ∗100 %= ∗100 %=97.7 %
L 2.61
Qua ví dụ trên ta thấy hiệu suất mã hóa tăng lên 97.7 so với 85%
khi mã hóa Huffman
Ta có thể ký hiệu bất cứ nhánh nào là 0 hay 1, nên với phương pháp
này không chỉ cho một bộ mã duy nhất, thứ tự trọng số của các nút sẽ thay
đổi tất nhiên hiệu suất mã không thay đổi.
3.3.4 Giải mã
Thuật giải nén Huffman:
- Bước 1: Xây dựng lại cây Huffman từ thông tin được lưu
- Bước 2: Khởi tạo nút hiện hành pCurr = pRoot
- Bước 3: Đọc một bit b từ file nén fn
- Bước 4: Nếu b=0 thì pCurr = pCurr.nRight
- Bước 5: Nếu pCurr là nút lá thì xuất ký tự tại pCurr ra file và quay
lại bước 2, ngược lại quay lại bước 3
- Bước 6: Thuật toán sẽ dừng khi hết file fn.
3.4. THÍ NGHIỆM
I. Kỹ thuật tạo mã Huffman
Bước 1: Tạo giao diện Guide trên Matlab:

6/20 Trang
Bước 2: Nhập mã nguồn cho các Pushbutton:
function varargout = GuideHuffman1(varargin)
gui_Singleton = 1;
gui_State = struct('gui_Name', mfilename, ...
'gui_Singleton', gui_Singleton, ...
'gui_OpeningFcn', @GuideHuffman1_OpeningFcn, ...
'gui_OutputFcn', @GuideHuffman1_OutputFcn, ...
'gui_LayoutFcn', [] , ...
'gui_Callback', []);
if nargin && ischar(varargin{1})
gui_State.gui_Callback = str2func(varargin{1});
end
if nargout
[varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
gui_mainfcn(gui_State, varargin{:});
end
function GuideHuffman1_OpeningFcn(hObject, eventdata, handles,
varargin)
handles.output = hObject;
guidata(hObject, handles);
function varargout = GuideHuffman1_OutputFcn(hObject, eventdata,
handles)
varargout{1} = handles.output;
function push1_Callback(hObject, eventdata, handles)
my_str =get(handles.input,'string');
auto_prob = 1;
if (auto_prob == 1)
prob_dist = double(my_str);
else
prob_dist = [10 19 30 40 50];
end
num_bits = ceil(log2(length(prob_dist)));
disp('Bang Ma ASCII cua cac ky tu:');
for i = 1:length(prob_dist)
display(strcat(my_str(i),' Ma ASCII la: ',num2str(prob_dist(i))));
end
total = sum(prob_dist);
for i = 1:length(my_str)
sorted_str{i} = my_str(i);

7/20 Trang
end
init_str = sorted_str;
init_prob = prob_dist;
sorted_prob = prob_dist;
rear = 1;
while (length(sorted_prob) > 1)
[sorted_prob,indeces] = sort(sorted_prob,'ascend');
sorted_str = sorted_str(indeces);
new_node = strcat(sorted_str(2),sorted_str(1));
new_prob = sum(sorted_prob(1:2));
sorted_str = sorted_str(3:length(sorted_str));
sorted_prob = sorted_prob(3:length(sorted_prob));
sorted_str = [sorted_str, new_node];
sorted_prob = [sorted_prob, new_prob];
newq_str(rear) = new_node;
newq_prob(rear) = new_prob;
rear = rear + 1;
end
tree = [newq_str,init_str];
tree_prob = [newq_prob, init_prob];
[sorted_tree_prob,indeces] = sort(tree_prob,'descend');
sorted_tree = tree(indeces);
parent(1) = 0;
num_children = 2;
for i = 2:length(sorted_tree)
me = sorted_tree{i};
count = 1;
parent_maybe = sorted_tree{i-count};
diff = strfind(parent_maybe,me);
while (isempty(diff))
count = count + 1;
parent_maybe = sorted_tree{i-count};
diff = strfind(parent_maybe,me);
end
parent(i) = i - count;
end
treeplot(parent);
title(strcat('So do Ma cay Huffman - "',my_str,'"'));
display(sorted_tree)
display(sorted_tree_prob)
[xs,ys,h,s] = treelayout(parent);
text(xs,ys,sorted_tree);
for i = 2:length(sorted_tree)
my_x = xs(i);
my_y = ys(i);
parent_x = xs(parent(i));
parent_y = ys(parent(i));
mid_x = (my_x + parent_x)/2;
mid_y = (my_y + parent_y)/2;
slope = (parent_y - my_y)/(parent_x - my_x);
if (slope > 0)
weight(i) = 1;
else
weight(i) = 0;
end
text(mid_x,mid_y,num2str(weight(i)));
end
for i = 1:length(sorted_tree)
code{i} = '';
index = i;
p = parent(index);

8/20 Trang
while(p ~= 0)
w = num2str(weight(index));
code{i} = strcat(w,code{i});
index = parent(index);
p = parent(index);
end
end
function input_Callback(hObject, eventdata, handles)
function input_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'),
get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function pushbutton2_Callback(hObject, eventdata, handles)
my_str =get(handles.input,'string');
auto_prob = 1;
if (auto_prob == 1)
prob_dist = double(my_str);
else
prob_dist = [10 19 30 40 50];
end
num_bits = ceil(log2(length(prob_dist)));
disp('Bang Ma ASCII cua cac ky tu:');
for i = 1:length(prob_dist)
display(strcat(my_str(i),' Ma ASCII la: ',num2str(prob_dist(i))));
end
total = sum(prob_dist);
for i = 1:length(my_str)
sorted_str{i} = my_str(i);
end
init_str = sorted_str;
init_prob = prob_dist;
sorted_prob = prob_dist;
rear = 1;
while (length(sorted_prob) > 1)
[sorted_prob,indeces] = sort(sorted_prob,'ascend');
sorted_str = sorted_str(indeces);
new_node = strcat(sorted_str(2),sorted_str(1));
new_prob = sum(sorted_prob(1:2));
sorted_str = sorted_str(3:length(sorted_str));
sorted_prob = sorted_prob(3:length(sorted_prob));
sorted_str = [sorted_str, new_node];
sorted_prob = [sorted_prob, new_prob];
newq_str(rear) = new_node;
newq_prob(rear) = new_prob;
rear = rear + 1;
end
tree = [newq_str,init_str];
tree_prob = [newq_prob, init_prob];
[sorted_tree_prob,indeces] = sort(tree_prob,'descend');
sorted_tree = tree(indeces);
parent(1) = 0;
num_children = 2;
for i = 2:length(sorted_tree)
me = sorted_tree{i};
count = 1;
parent_maybe = sorted_tree{i-count};
diff = strfind(parent_maybe,me);
while (isempty(diff))
count = count + 1;
parent_maybe = sorted_tree{i-count};

9/20 Trang
diff = strfind(parent_maybe,me);
end
parent(i) = i - count;
end
treeplot(parent);
title(strcat('So do Ma cay Huffman - "',my_str,'"'));
display(sorted_tree)
display(sorted_tree_prob)
[xs,ys,h,s] = treelayout(parent);
text(xs,ys,sorted_tree);
for i = 2:length(sorted_tree)
my_x = xs(i);
my_y = ys(i);
parent_x = xs(parent(i));
parent_y = ys(parent(i));
mid_x = (my_x + parent_x)/2;
mid_y = (my_y + parent_y)/2;
slope = (parent_y - my_y)/(parent_x - my_x);
if (slope > 0)
weight(i) = 1;
else
weight(i) = 0;
end
text(mid_x,mid_y,num2str(weight(i)));
end
for i = 1:length(sorted_tree)
code{i} = '';
index = i;
p = parent(index);
while(p ~= 0)
w = num2str(weight(index));
code{i} = strcat(w,code{i});
index = parent(index);
p = parent(index);
end
end
codeBook = [sorted_tree', code']
set(handles.text2,'string',sorted_tree);
set(handles.text3,'string',code);
function axes2_CreateFcn(hObject, eventdata, handles)
function axes3_CreateFcn(hObject, eventdata, handles)
function edit3_Callback(hObject, eventdata, handles)
function edit3_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'),
get(0,'defaultUicontrolBackgroundColor'))
set(hObject,'BackgroundColor','white');
end
function axes4_CreateFcn(hObject, eventdata, handles)
imshow('C:\Users\Public\Pictures\Sample Pictures\logo\5.jpg');
function axes5_CreateFcn(hObject, eventdata, handles)
imshow('C:\Users\Public\Pictures\Sample Pictures\logo\logokhoa.png');
function pushbutton4_Callback(hObject, eventdata, handles)
dos command;

Bước 3: Nhập số liệu và chạy chương trình tạo mã Huffman cho kết quả
như sau:

10/20 Trang
II. Phần mềm nén dữ liệu ứng dụng mã huffman
Chương trình nén file dùng mã Huffman viết bằng ngôn ngữ Visual
Studio 2010, sau khi chạy chương trình xuất ra file Huffman.exe giả sử đặt
trong ổ D\truyensolieu\mahoa\Huffman.exe, để chạy chương trình nén/giải
nén file bất kỳ từ giao diện Guide bấm vào Nén/Giải nén hoặc từ cửa sổ
lệnh của Matlab ta vào đường dẫn trên như sau:

Bước 2: chạy file Huffman.exe theo cú pháp:


Huffman.exe -e tên file cần nén (nếu file cần nén không đặt tại đây thì gõ
thêm đường dẫn)
Huffman.exe -d tên file giải nén

11/20 Trang
Sau khi nén xong xuất ra file nén dưới dạng .huf, sau khi giải nén ra file
ban đầu.
3.5. BÀI TẬP
Viết chương trình tạ o mã Shanon-Fano và mộ t số loạ i mã nguồ n khá c.
2.6. BÁO CÁO TỔNG KẾT

12/20 Trang

You might also like