数据压缩代码(matlab)

本文深入探讨数据压缩原理,包括熵的计算、算术编码、LZW编码等核心算法的实现与应用,通过代码实例讲解如何高效压缩数据。

数据压缩课程中的代码(有点多先放一点以后有空再说)

熵的计算

熵的定义在这里不加赘述直接上代码

% 计算信源的熵
% 输入:p 概率集合
% 输出:H 其对应的熵
function H=entropy(p)
if nargin==0
    disp('输入的概率集合不能为空,请重新输入!!')
    return
end
p=p(:); % 将p变成一维向量
% 检测p的合法性
for i=1:length(p)
    if p(i)<0 | p(i)>1
        disp('概率必须在0到1之间');
        return
    end
    
end
% 实际中概率之和不可能精确等于1
tol=1e-4; % 设定允许的精度
if abs(sum(p)-1)>tol
    disp('概率之和必须为“1”且在允许的精度范围内');
    return
end
% 计算熵
disp('信源的熵为:');
p(find(p==0))=[]; % 删除p中的0值,否则会出现NaN
H=0;
for i=1:length(p)
    H=H-p(i)*log2(p(i));
end

算术编码和解码

简单介绍

    根据信源可能发现的不同符号序列的概率,把[0,1]区间划分为互不重叠的子区间,子区间的宽度恰好是各符号序列的概率。这样信源发出的不同符号序列将与各子区间一一对应,因此每个子区间内的任意一个实数都可以用来表示对应的符号序列,这个数就是该符号序列所对应的码字。显然,一串符号序列发生的概率越大,对应的子区间就越宽,要表达它所用的比特数就减少,因而相应的码字就越短。

初始状态下 , 。在已知所有信源符号的概率的情况下对数据序列中的每一个符号按顺序进行以下操作:

在这里插入图片描述在这里插入图片描述在这里插入图片描述
其中 startB表示前一个的开始值, 表示本字符开始值, 表示本字符结束值, 表示本字符概率区间左端, 表示概率区间右端。
    解码过程:开始的时候拿编码比较概率区间,得到第一个解析的信源码,接下来的编码采用如下处理:

(4)
        每次处理完后比较概率区间,知道解析出所有的信源编码。

算术编码实现

clc;
clear;
  %设定固定的概率
c = [8000,1600,3000,4400,12000,2500,1700,6400,8000,400,800,4000,3000,8000,8000,1700,500,6200,8000,9000,3400,1200,2000,400,2000,200];
c = c/sum(c);
 
str = input('请输入待编码的字符串 ','s');
start = 0;
L = 1;
k = 0;
%得出概率区间
matr = zeros(length(c),2);
for i = 1:length(c)
    matr(i,1) = k;
    k = k+c(i);
    matr(i,2) = k; 
end
 %进行迭代计算
for i = 1: length(str)
    midst = start;
    start = midst + L*matr(str(i)-'a'+1,1);
    endn = midst + L*matr(str(i)-'a'+1,2);
    L = endn - start;
    disp(sprintf ('%c\t%.30f\t%.30f\t%.30f',str(i),start,endn,L));   
end
  %输出编码
disp(sprintf ('输出的编码为:%.30f',start));

测试结果:
在这里插入图片描述
注意输出格式,否则有可能看到都为0的结果

disp(sprintf ('%c\t%.30f\t%.30f\t%.30f',str(i),start,endn,L));   

解码实现

clc;
clear;
%%输入概率
c = [8000,1600,3000,4400,12000,2500,1700,6400,8000,400,800,4000,3000,8000,8000,1700,500,6200,8000,9000,3400,1200,2000,400,2000,200];
c = c/sum(c);
%%输入编码和字符数
code = input('请输入编码:');
num = input('请输入字符数');
 
%%得出区间
matr = zeros(length(c),2);
k = 0;
for i = 1:length(c)
    matr(i,1) = k;
    k = k+c(i);
    matr(i,2) = k; 
end
 
for i = 1:num
    for i = 1:26
      if code>=matr(i,1)-0.001&&code<=matr(i,2)-0.001 
         disp(char('a'+i-1)) ; 
         code = (code-matr(i,1))/c(i);
         break
      end
    end
end

测试结果:
在这里插入图片描述    算术编码的解码需要输入解码后的字符数,否则会无限解码下去。当然也可以加容忍误差到达范围内停止解码。

LZW编码

原理

    LZW编码的核心思想其实比较简单,就是把出现过的字符串映射到记号上,这样就可能用较短的编码来表示长的字符串,实现压缩。
     LZW压缩算法的基本概念:LZW压缩有三个重要的对象:数据流、编码流和编译表。在编码时,数据流是输入对象(文本文件的据序列),编码流就是输出对象(经过压缩运算的编码数据);在解码时,编码流则是输入对象,数据流是输出对象;而编译表是在编码和解码时都须要用借助的对象。
     LZW编码的算法步骤:
     初始化:将所有单个字符按字母顺序初始化输入到字典中 读入第一个字符到S1
       Step1:读入下一个字符存放到S2中
         if S2 为空(表示读入到字符串尾了)
                输出S1的index 结束
         If S1+S2已经在字典中
                S1+S2->S1
                Repeat Step1
         else (三步)
                输出S1的index
                S1+S2顺序添加到字典末尾
                S2->S1
                 Repeat Step
     LZW解码的算法步骤:
        Step 读入编码到K中
        if K不为空
                 查找字典中K对应的字符串
                 Repeat step

LZW实现

%%先输入单个字符集
%%再输入字符集组成的字符串
%%输出的是编码
%%然后输出根据编码和字典所得到的原来的信息
 
clc;
clear;
 
od = input('输入编码中的字符集合','s');
num = size(od,2);
for i = 1:num
    lib(i) = struct('code',od(i),'num',dec2hex(i-1)); %index从0开始所以需要减1
end
 
str = input('输入待编码的字符串','s');
s1 = str(1);
cod = [];  %存放码
num = num -1; 
for i = 2:size(str,2)
    s2 = str(i);
    s = strcmp({lib.code},[s1,s2]);
    ind = find(s==1);
    if  ~isempty(ind)         %s1+s2在字典中
        s1 = [s1,s2];
        continue
    else
        s = strcmp({lib.code},s1);    % 输出index s1 s1+s2顺序添加到末尾 s1=s2
        ind = find(s==1);
        cod = [cod,lib(ind).num];
        
        num = num+1;
        lib(num+1) = struct('code',[s1,s2],'num',dec2hex(num));
        s1 = s2;
    end
end
 
s = strcmp({lib.code},s1);
ind = find(s==1);
cod = [cod,lib(ind).num];
 
disp('输出的编码为');
disp(cod);

 %%解码部分

decode = [];
for i = 1:size(cod,2)
     s = strcmp({lib.num},cod(i));    
     ind = find(s==1);
     decode = [decode,lib(ind).code];
end
 
disp('解码输出原来的信息为:');
disp(decode);

测试结果:
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值