LZW编码—图像压缩

本文系转载+改编:http://blog.csdn.net/krossford/article/details/49157531

LZW全称Lempel–Ziv–Welch

LZW的工作思路,考虑一段数据,abcabcabc,对于这样的一段数据,如果不做任何处理和压缩,假设每个字符用一个字节来表示,直接存储的空间应该是9字节。详细说明下:
下表是我们dictionary,也就是码表,字符与编码的对应。

character   decimal    binary
   a           1      0000 0001
   b           2      0000 0010
   c           3      0000 0011

上面的字符串,abc是重复的,如果abc能用一个字节来表示的话,那么,只需要3字节存储就足够了。

character   decimal binary
abc           1    0000 0001

Encoding

基本思想

编码的基本思想是这样的,首先我们有一个码表或者称为dictionary,里面只定义单个字符和编码,比如0-9a-zA-Z这些,其实ASCII码中的所有全部都放进去都可以。

也就是说通常用十进制数0-255来表示单一字符(single character)。

然后我们开始读取字符串,很显然对于任何常规字符串,每个single character都可以得到一个码字,但是如果我们不做处理的话,那么n个字符encode后,就是n个码字了完全没有压缩。

所以,再边读取的时候,一边开始对dictionary进行扩增,不断的将single character拼接成dictionary中不存在的符号(symbol),扩充dictionary,这样下次再次遇到这样的组合,就可以使用有一个码字表示了。

流程

说实话,用纯文字描述还真的不是很好描述,于是我画了一个流程图来描述这样一个过程。
这里写图片描述
就是上面这个图了,代码只要照着这个写就能搞定问题。但出于尊重,还是要讲解下比较好。
首先我们需要两个暂存器,P和C,为啥叫这个名字呢。(当时上学那会,老师给的是p和s,完全不知道意义)

P -> Previous -> 表示之前的字符
C -> Current -> 表示当前读取的字符
1
2
然后我们考虑字符串abcbcabcabcd

来,按步骤演算一下:

首先我们需要一个dictionary,简单考虑,只考虑a-d,4个英文小写字母吧。

symbol  decimal
   a       1
   b       2
   c       3
   d       4

下面是演算过程:

这里写图片描述

经过上面的演算过程,我们的dictionary也扩展为:

symbol decimal
a 1
b 2
c 3
d 4
ab 5
bc 6
cb 7
bca 8
abc 9
ca 10
代码实现

最后贴下自己实现的代码:

 public static List<Integer> encode(String data) {
        List<Integer> result = new ArrayList<>();

        //初始化dictionary
        int idleCode = 256;
        HashMap<String, Integer> dic = new HashMap<>();
        for (int i = 0; i < 256; i++) {
            dic.put((char)i + "", i);
        }

        String previous = "";
        String pc = "";
        for (char c : data.toCharArray()) {
            pc = previous + c;
            if (dic.containsKey(pc)) {
                previous = pc;
            } else {
                dic.put(pc, idleCode++);
                result.add(dic.get(previous));
                previous = "" + c;
            }
        }

        //最后一次输出
        if (!previous.equals("")) {
            result.add(dic.get(previous));
        }

        return result;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Output

//abcbcabcabcd
[97, 98, 99, 257, 256, 99, 260, 100]
1
2
3

Decoding

主要思想

解码的主要思想是,一个编码序列,我们也是事先知道一个固定的码表,我一边读取码字,一边输出解码后的字符,同时一边扩充码表。这个我也觉得好难用用文字表达清楚,上流程图。

流程

这里写图片描述
同样的,这里给出一个编码序列

[97, 98, 99, 257, 256, 99, 260, 100]
1
首先我们需要一个默认的dictionary。

decimal symbol
97 a
98 b
99 c
100 d
接下来是演算过程:

这里写图片描述
代码实现

public static String decode(List<Integer> arr) {

    StringBuilder result = new StringBuilder();
    int idleCode = 256;
    HashMap<Integer, String> dic = new HashMap<>();
    for (int i = 0; i < 256; i++) {
        dic.put(i, (char)i + "");
    }

    String p = "";
    String c = "";

    for (int code : arr) {
        if (dic.containsKey(code)) {
            c = dic.get(code);
        } else if (code == idleCode) {  //这里唯一的情况是 aaaaaaa
            c = c + c.charAt(0);
        } else {
            System.out.println("bad encode");
        }

        if (!p.equals("")) {
            dic.put(idleCode++, p + c.charAt(0));
        }
        result.append(c);
        p = c;
    }

    return result.toString();
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
Summary

References

Lempel–Ziv–Welch from Wikipedia.
LZW的各种语言的实现
http://rosettacode.org/wiki/LZW_compression
https://zh.wikipedia.org/wiki/ASCII

  • 0
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
LZW(Lempel-Ziv-Welch)压缩算法是一种无损压缩算法,能够对数据流进行有效压缩。在图像压缩方面,LZW算法可以将原始图像数据流进行压缩,并且不会损失原始图像的任何信息。下面是一个基于 MATLAB 的 LZW 图像压缩编码实现: ```matlab function [compressedImage, dict] = lzw_compress(image) % 将图像转换为一维数据流 data = reshape(image, 1, []); % 初始化编码字典 dict = cell(256, 1); for i = 1:256 dict{i} = uint8(i-1); end % 初始化编码参数 code = 257; p = uint8([]); compressedImage = []; % LZW 编码 for i = 1:numel(data) c = data(i); pc = [p c]; if ismember(pc, dict) p = pc; else compressedImage = [compressedImage uint16(find(ismember(dict, p)))]; dict{code} = pc; code = code + 1; p = c; end end % 将编码后的数据流转换为字节流 compressedImage = typecast(compressedImage, 'uint8'); end ``` 这个函数将输入的图像 `image` 转换为一维数据流 `data`,并且初始化编码字典。接下来,我们对数据流进行 LZW 编码,将编码后的数据转换为字节流并返回。此外,函数还返回了编码字典 `dict`,方便解码时使用。 以下是一个基于 MATLAB 的 LZW 图像解压缩编码实现: ```matlab function image = lzw_decompress(compressedImage, dict) % 将字节流转换为编码数据流 compressedImage = typecast(compressedImage, 'uint16'); % 初始化解码参数 code = 257; p = uint8([]); data = []; % LZW 解码 for i = 1:numel(compressedImage) k = compressedImage(i); if k <= 256 c = dict{k}; else c = [p dict{k}(1)]; end data = [data c]; if ~isempty(p) dict{code} = [p c(1)]; code = code + 1; end p = c; end % 将一维数据流转换为图像 image = reshape(data, size(image)); end ``` 这个函数将输入的压缩后的字节流 `compressedImage` 转换为编码数据流,然后初始化解码参数。接下来,我们对编码数据流进行 LZW 解码,将解码后的数据转换为图像并返回。函数中的解码过程编码过程不同,因为我们需要在解码过程中构建编码字典。因此,我们使用了一个变量 `code` 来追踪下一个字典条目的编码值。 这是一个简单的 LZW 图像压缩编码实现,可以用于对图像进行无损压缩。需要注意的是,该实现仅支持 8 位灰度图像。如果要支持彩色图像,需要对每个颜色通道分别进行压缩编码

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值