`
ldb19890624
  • 浏览: 243704 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

算法系列之八:RLE行程长度压缩算法

 
阅读更多

RLE(Run Length Encoding)行程长度压缩算法(也称游程长度压缩算法),是最早出现、也是最简单的无损数据压缩算法。RLE算法的基本思路是把数据按照线性序列分成两种情况:一种是连续的重复数据块,另一种是连续的不重复数据块。对于第一种情况,对连续的重复数据块进行压缩,压缩方法就是用一个表示块数的属性加上一个数据块代表原来连续的若干块数据。对于第二种情况,RLE算法有两种处理方法,一种处理方法是用和第一种情况一样的方法处理连续的不重复数据块,仅仅是表示块数的属性总是1;另一种处理方法是不对数据进行任何处理,直接将原始数据作为压缩后的数据。

为了更直观的说明RLE算法,下面就用示例数据就对RLE算法进行演示。首先是第一种情况,原始数据有5个连续相同的数据块组成:

[block] [block] [block] [block] [block]

则压缩后的数据就是:

[5] [block]

接着是第二种情况,原始数据由连续的不重复数据块组成:

[block1] [block2] [block3] [block4] [block5]

按照第一种处理方法,最后的压缩数据就如以下情形:

[1][block1] [1][block2] [1][block3] [1][block4] [1][block5]

如果按照第二种处理方法,最后的数据和原始数据一样:

[block1] [block2] [block3] [block4] [block5]

数据块block的长度可以是任意长度,数据块长度越长则连续重复的概率就越低,压缩的优势就体现不出来,因此,大多数RLE算法的实现都使用一个字节作为数据块长度。

接下来本文就介绍几种RLE算法的实现,首先是最简单的一种算法实现,这种算法实现对连续的不重复字节采用和重复字节一样的处理方法,就是在每个字节前增加一个值是1的连续块数属性(一个字节)。采用这种处理方法的首先好处是压缩和解压缩算法简单,可以用相同的模式处理两种情况的压缩数据,缺点就是当原始数据重复率比较低时,压缩后的数据长度会超过原始数据的长度,起不到压缩的作用,最糟糕的情况就是所有数据块没有连续重复的情况,压缩后的数据反而膨胀一倍。压缩的过程是这样的,线性扫描原始数据,如果某一个字节后面有重复的字节,则增加重复计数,然后继续向后扫描,直到找到一个不重复的字节,然后将块数和这个字节的数据依次写入压缩数据,然后从新的开始字节继续扫描直到原书数据结束。算法中需要注意的一点就是块数属性是用一个字节存储的,因此最大值就是255,当连续的相同数据超过255个字节时,就从第255个字节处断开,将第256个字节以及256字节后面的数据当成新的数据处理。这种RLE压缩算法的C语言实现如下:

6int Rle_Encode_N(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

7{

8 unsigned char *src = inbuf;

9 int i;

10 int encSize = 0;

11

12 while(src < (inbuf + inSize))

13 {

14 if((encSize + 2) > onuBufSize) /*输出缓冲区空间不够了*/

15 {

16 return -1;

17 }

18 unsigned char value = *src++;

19 i = 1;

20 while((*src == value) && (i < 255))

21 {

22 src++;

23 i++;

24 }

25 outbuf[encSize++] = i;

26 outbuf[encSize++] = value;

27 }

28

29 return encSize;

30}

对于字符串“AAABBBBBCD”,用这种RLE算法Rle_Encode_N()函数压缩后的数据就是:0x03,0x41,0x05,0x42,0x01,0x43,0x01,0x44共8个字节,比原始长度10个字节少了2个字节,实现了数据长度的压缩。

解压缩的过程也很简单,就是定为到第一个块数属性字节位置,根据块数属性的值n,连续向解压缩缓冲区还原n个原始数据,原始数据就是块数属性后面一个字节的数据,然后偏移到下一个块数属性字节位置继续上述处理,直到压缩数据结束。解压缩算法的C语言实现如下:

32int Rle_Decode_N(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

33{

34 unsigned char *src = inbuf;

35 int i;

36 int decSize = 0;

37

38 while(src < (inbuf + inSize))

39 {

40 int count = *src++;

41 if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/

42 {

43 return -1;

44 }

45 unsigned char value = *src++;

46 for(i = 0; i < count; i++)

47 {

48 outbuf[decSize++] = value;

49 }

50 }

51

52 return decSize;

53}

这个最简单的的RLE算法存在着一个致命问题,就是对连续出现的不重复数据,会因为插入太多块数属性字节而膨胀,如果一段数据连续出现重复数据的情况很少,大多数是连续不重复的数据,则使用上面的算法会导致数据没有被压缩,反而增大了,在极端的情况下,会因为插入的块数属性字节而导致数据膨胀一倍。针对这种情况,人们对算法进行了改进,改进的关键点就是对连续出现的不重复数据,不再简单插入块数属性,而是将其直接作为压缩后的数据处理。这样会遇到一个问题,就是解码的过程中,如何判断一个数据是块数属性数据还是正常的数据?方法就是对块数属性字节设置标志位,将块数属性字节的高两位作为标志位,当这两个标志位是连续的两个1时,则判断此字节数据是块数属性字节,它的剩下的6个位就是重复块数。如果这两个标志位不是连续的1,则认为这个字节是正常数据。现在的问题是,如果用户数据中出现了与标志位冲突的数据怎么办?其实没有太好的方法,解决这个问题的方案就是插入值是1的块数属性字节。往好的方面想,这个改进对于数据不超过192(0xC2)的原始数据是非常有效的,著名的图像文件格式PCX格式,就是使用了这种改进的压缩算法,效果还是不错的。下面就来看看一个改进的压缩算法实现:

55int Rle_Encode_P(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

56{

57 unsigned char *src = inbuf;

58 int i;

59 int encSize = 0;

60

61 while(src < (inbuf + inSize))

62 {

63 unsigned char value = *src++;

64 i = 1;

65 while((*src == value) && (i < 63))

66 {

67 src++;

68 i++;

69 }

70

71 if((encSize + i + 1) > onuBufSize) /*输出缓冲区空间不够了*/

72 {

73 return -1;

74 }

75 if(i > 1)

76 {

77 outbuf[encSize++] = i | 0xC0;

78 outbuf[encSize++] = value;

79 }

80 else

81 {

82 if((value & 0xC0) == 0xC0)

83 {

84 outbuf[encSize++] = 0xC1;

85 }

86 outbuf[encSize++] = value;

87 }

88 }

89

90 return encSize;

91}

对于字符串“AAABBBBBCD”,用这种RLE算法的Rle_Encode_P()函数压缩后的数据就是:0xC3,0x41,0xC5,0x42,0x43,0x44共6个字节,比原始长度10个字节少了4个字节,对于原始数据都小于192的数据能够有效地抑制因插入块数属性过多导致的数据膨胀。

使用这种算法解压缩,需要判断当前数据是否有块属性标志,如果有则从低6位bit中去到重复数据的块数n,然后将下一个字节的数据重复复制n次。如果当前数据没有块属性标志,则直接使用当前数据,具体实现的C代码见Rle_Decode_P()函数:

93int Rle_Decode_P(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

94{

95 unsigned char *src = inbuf;

96 int i;

97 int decSize = 0;

98 int count = 0;

99

100 while(src < (inbuf + inSize))

101 {

102 unsigned char value = *src++;

103 int count = 1;

104 if((value & 0xC0) == 0xC0) /*是否有块属性标志*/

105 {

106 count = value & 0x3F; /*低位是count*/

107 value = *src++;

108 }

109 else

110 {

111 count = 1;

112 }

113 if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/

114 {

115 return -1;

116 }

117 for(i = 0; i < count; i++)

118 {

119 outbuf[decSize++] = value;

120 }

121 }

122

123 return decSize;

124}

上述优化后的RLE算法,在原始数据普遍大于192(0xC0)的情况下,其优化效果相对于优化前的算法没有明显改善。原因在于,原始的RLE算法和改进后的RLE算法对于连续出现的不重复数据的处理方式都是一个一个处理的,没有把不重复数据作为一个整体进行处理。现在考虑再对原始的RLE算法进行优化,主要优化思想就是对连续的不重复数据进行整理处理,用一个和处理连续重复数据一样的标志,标识后面的数据是长度为n的连续不重复数据。这样的标志字节就相当于是数据块的块头部分,描述后面跟的数据类型以及数据长度。由于标志是始终存在于数据块的前面,因此就不需要区分标志字节和原始数据,也就是说,第一个改进算法中用“高两位是连续的1”的方式区分标志字节和数据都是没有必要的,唯一需要区分的是后面跟的数据类型。区分的方法就是对标志字节的8个bit进行分工,用高位一个bit表示后面跟的数据类型,如果这个bit是1则表示后面跟的是连续重复的数据,如果这个bit是0则表示后面跟的是连续不重复的数据。标志字节的低7位bit存储一个数字(最大值是127),对于连续重复数据,这个数字表示需要重复的次数,对于连续不重复数据,这个数字表示连续不重复数据块的长度。需要注意的是,只有重复次数超过2的数据才被认为是连续重复数据,因为如果数据的重复次数是2,压缩后加上标志字节后总的长度没有变化,因此没有必要处理。

下面根据上述优化思想进行算法设计,首先是压缩算法。在这种情况下,压缩算法就比前两种RLE压缩算法复杂一些,就是要能识别连续的重复数据和连续的不重复数据。首先设置搜索起始位置,算法开始时这个搜索起始位置就是原始数据的第一个字节。每次搜索就是从起始位置开始向后搜索比较数据,根据搜索比较结果,一种情况就是后面数据重复且数据长度超过2,则设置连续重复数据的标志,然后继续向后查找,直到找到第一个与之不相同的数据为止,将这个位置记为下次搜索的起始位置,根据位置差计算重复次数,连重复标志和重复次数以及原始数据一起写入压缩数据;另一种情况是后面的数据都没有连续重复的,则继续向后查找,直到找到连续重复的数据,然后设置不重复数据标志,将新位置记为下次搜索的起始位置,最后将标志字节写入压缩数据并将原始数据复制到压缩数据。从新的搜索起始位置重复上面的过程,直到原始数据结束。函数Rle_Encode_O()就是上述算法的C语言实现(只有算法的主体部分):

185int Rle_Encode_O(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

186{

187 unsigned char *src = inbuf;

188 int i;

189 int encSize = 0;

190 int srcLeft = inSize;

191

192 while(srcLeft > 0)

193 {

194 int count = 0;

195 if(IsRepetitionStart(src, srcLeft)) /*是否连续三个字节数据相同?*/

196 {

197 if((encSize + 2) > onuBufSize) /*输出缓冲区空间不够了*/

198 {

199 return -1;

200 }

201 count = GetRepetitionCount(src, srcLeft);

202 outbuf[encSize++] = count | 0x80;

203 outbuf[encSize++] = *src;

204 src += count;

205 srcLeft -= count;

206 }

207 else

208 {

209 count = GetNonRepetitionCount(src, srcLeft);

210 if((encSize + count + 1) > onuBufSize) /*输出缓冲区空间不够了*/

211 {

212 return -1;

213 }

214 outbuf[encSize++] = count;

215 for(i = 0; i < count; i++) /*逐个复制这些数据*/

216 {

217 outbuf[encSize++] = *src++;;

218 }

219 srcLeft -= count;

220 }

221 }

222 return encSize;

223}

现在用数据“AAABBBBBCABCDDD”检验上述算法,得到压缩后的数据:0x83,0x41,0x85,0x42,0x04,0x43,0x41,0x42,0x43,0x83,0x44,原始数据长度是15字节,压缩后是11字节,这种改进后的算法,原始数据越长,压缩的效果就越明显。

这种改进方法的解压缩算法就比较简单了,因为两种情况下的数据的首部都有标志,只要根据标志判断如何处理就可以了。首先从压缩数据中取出一个字节的标志字节,然后判断是连续重复数据的标志还是连续不重复数据的标志,如果是连续重复数据,则将标志字节后面的数据重复复制n份,;如果是连续不重复数据,则将连续复制标志字节后面的n个数据。n的值是标志字节与0x3F做与操作后得到,因为标志字节的低7位bit就是数据块数属性。

改进的解压缩算法如下:

225int Rle_Decode_O(unsigned char *inbuf, int inSize, unsigned char *outbuf, int onuBufSize)

226{

227 unsigned char *src = inbuf;

228 int i;

229 int decSize = 0;

230 int count = 0;

231

232 while(src < (inbuf + inSize))

233 {

234 unsigned char sign = *src++;

235 int count = sign & 0x3F;

236 if((decSize + count) > onuBufSize) /*输出缓冲区空间不够了*/

237 {

238 return -1;

239 }

240 if((sign & 0x80) == 0x80) /*连续重复数据标志*/

241 {

242 for(i = 0; i < count; i++)

243 {

244 outbuf[decSize++] = *src;

245 }

246 src++;

247 }

248 else

249 {

250 for(i = 0; i < count; i++)

251 {

252 outbuf[decSize++] = *src++;

253 }

254 }

255 }

256

257 return decSize;

258}

用前面Rle_Encode_O()函数得到的压缩数据进行验证,结果正确。

当今常用的压缩软件普遍使用从LZ77压缩算法改进的LZSS压缩算法。LZSS压缩算法是一种基于字典模型的压缩算法,算法依据是在文本流中词汇或短语很可能会重复出现,同样图像流中图像模式很也可能会重复出现。因此,在处理的过程中,构造一个编码表,用较短的编码代替重复序列,就可以有效地减少数据大小。与LZSS算法相比,RLE的压缩率显然没有LZSS的高,但是RLE算法具有速度快的优势,在LZSS算法出现之前,还是得到了很广泛的应用,比如著名的图像文件格式PCX就是使用了本文提到的第二种RLE算法。
分享到:
评论

相关推荐

    RLE压缩算法C语言实现

    RLE(Run-Length Encoding,行程长度编码)是一种简单的无损数据压缩算法,它通过寻找连续重复的字符或字节,并用一对数值表示该字符或字节的重复次数和该字符本身,来达到压缩数据的目的。在C语言中实现RLE算法,...

    RLE.rar_RLE_RLE的java编码_RLE编码_rle 算法_rle压缩

    RLE(Run-Length Encoding,行程长度编码)是一种简单的无损数据压缩算法,尤其适用于处理具有大量重复连续元素的数据。在图像处理中,它被广泛应用于压缩具有相同颜色像素的长行或列。此算法的基本原理是将连续重复...

    使用RLE(Run Length Encoding)编码的例子(2KB)...

    RLE(Run Length Encoding)是一种简单的无损数据压缩算法,主要应用于处理连续重复的数据。它通过将连续出现的相同字符计数并存储为一对字符和计数值来减少数据量,从而实现压缩。在这个例子中,我们关注的是如何...

    基于C++的游程长度编码RLE

    游程长度编码(Run-Length Encoding, RLE)是一种简单的无损数据压缩算法,常用于处理具有大量重复连续值的数据。这种编码方式通过统计连续相同的数值并记录其出现次数来减小数据量,尤其适用于图像处理和文本压缩。...

    RLE行程编码

    RLE(Run-Length Encoding,行程长度编码)作为一种简单有效的无损压缩算法,在图像压缩领域占据着重要的地位。该算法的核心思想是对连续重复出现的数据进行编码,用一个计数值和一个数据值代替原有的重复序列,从而...

    RLE算法小工具

    RLE(Run-Length Encoding)算法,全称为行程长度编码,是一种简单且常见的数据压缩方法。在图像处理、文本压缩等领域有着广泛的应用。该算法的基本思想是寻找连续出现的相同字符或颜色像素,并用一个字符(通常是该...

    RLE.rar_RLE_rle算法_rle编码格式

    RLE(Run-Length Encoding,行程长度编码)是一种简单的无损数据压缩算法,广泛应用于图像处理、文本压缩等领域。它的基本思想是将连续出现的相同数据值压缩为一个数据值加上该值连续出现的次数。例如,一串连续的'0...

    bmp格式转rle

    BMP格式是一种无损的、未压缩的位图格式,通常用于存储高质量的图像,而RLE则是一种简单且有效的压缩算法,常用于减少图像文件的大小,尤其适用于具有大量重复像素的图像。 在Android系统中,由于内存和存储空间的...

    matlab图像专题:50 行程编码实现编码压缩.zip

    本专题将探讨MATLAB中行程编码(Run-Length Encoding,RLE)的实现方法,这是一种简单而有效的无损压缩算法。 行程编码的核心思想是利用图像中的连续相同像素值进行压缩。在未压缩的图像数据中,相邻的像素值可能会...

    使用游程编码的图像压缩:rle 应用到图像压缩-matlab开发

    游程编码(Run-Length Encoding, RLE)是一种简单的无损数据压缩算法,尤其适用于处理具有大量重复连续元素的数据。在图像处理领域,当图像存在大量的相同颜色或亮度区域时,RLE能有效地压缩数据。本篇文章将深入...

    yasuobi.zip_压缩图像编码_图像压缩_行程长度

    “压缩图像编码”是实现图像压缩的技术手段,包括各种编码算法,如霍夫曼编码、算术编码、游程编码和行程长度编码。这些编码方法都是通过对图像数据进行统计分析,找出数据中的规律性,然后用更少的位来表示常见的...

    图像压缩(行程编码)

    行程编码(Run-Length Encoding,RLE)是一种简单的无损数据压缩算法,尤其适用于处理含有大量重复连续数据的图像。在图像处理中,如果一个颜色连续出现多次,行程编码就能有效地捕捉这种特性并进行压缩。 行程编码...

    常见压缩算法简介与压缩文件格式特征

    常见的无损压缩算法包括行程长度编码(RLE)、字典编码(如LZ77、LZ78及其变体LZW)以及熵编码。 行程长度编码(RLE)是一种简单的变长编码技术,尤其适用于处理具有连续重复元素的数据,如图像文件中的像素。RLE...

    RLE-Encode.zip_RLE matlab _RLEencode_Stroke gray level_rle_encod

    在这种情况下,其他更复杂的压缩算法,如霍夫曼编码(Huffman Coding)、算术编码(Arithmetic Coding)或JPEG、PNG等标准图像压缩格式可能会更有效。 在压缩包中的“行程编码.ppt”文件可能是关于RLE编码的详细...

    RLE.rar_RLE_RLE图像编码_RLE编码

    RLE(Run-Length Encoding,行程长度编码)是一种简单的无损数据压缩算法,广泛应用于图像处理领域,特别是针对灰度图像的编码。RLE的核心思想是将连续出现的相同数据值用一个计数值和该数据值来表示,以此来减少...

    行程编码 C++

    行程编码(Run-Length Encoding,RLE)是一种简单的无损数据压缩算法,主要用于处理具有大量重复连续字符的数据。在本示例中,我们将讨论如何使用C++实现行程编码及其解码过程。 行程编码的基本原理是找到输入字符...

    图像无损压缩算法综述.doc

    行程编码是一种简单的无损压缩算法。该算法的基本思想是将输入数据流中的连续重复的符号用一个符号和其重复次数来代替。例如,输入数据流为 AAAABBBCCC,可以用 A4B3C3 来代替。 5. 费诺-香农编码 费诺-香农编码是...

    利用游程编码实现二值图像压缩.

    基本思想是记录相同颜色像素的连续个数(行程长度)以及该颜色,从而减少存储需求。 具体来说,游程编码分为定长和不定长两种类型。定长编码是指每个行程的长度用固定数量的位来表示,而不定长编码则根据实际需要...

    RLE.rar_visual c

    RLE(Run-Length Encoding,行程长度编码)是一种简单且高效的无损压缩方法,它适用于那些具有大量重复连续像素值的图像。"RLE.rar_visual c"的标题表明这个压缩包包含的是关于使用Visual C++进行RLE压缩的实现代码...

    图像无损压缩算法综述..pdf

    【图像无损压缩算法综述】 图像无损压缩是一种能够完全恢复原始图像数据的压缩方法,它在编码过程中不会导致图像质量的下降。随着多媒体技术和通信技术的发展,图像数据的存储和传输需求日益增长,而有限的带宽资源...

Global site tag (gtag.js) - Google Analytics