某些类型数据的压缩性能

时间:2011-09-19 00:47:13

标签: performance compression

我正在测试我的新图像文件格式,其中没有涉及不必要的细节,包括通过zlib的压缩流发送的每像素格式的PPM RGB格式,以及附加到前面的8字节标头。

当我编写测试来评估实现这个的相应代码的性能时,我有一个测试用例产生了非常可怕的结果。

unsigned char *image = new unsigned char[3000*3000*3];
for(int i=0;i<3000*3000;++i) {
    image[i*3] = i%255;
    image[i*3+1] = (i/2)%255;
    image[i*3+2] = (i*i*i)%255;
}

现在我正在做的是创建一个3000x3000完全打包的每像素3字节图像,其中红色和绿色条纹稳定增加,但蓝色组件将会变化很多。

当我使用zlib流为我的.ppmz格式压缩它时,它能够将大小从27,000,049字节缩小(因为它不是一个2700万,即标题中的49字节)到25,545,520字节。此压缩文件的原始大小为94.6%。

这让我起初感到非常慌张,因为我认为即使蓝色组件如此混乱也无法帮助太多,至少红色和绿色组件重复了很多。足够聪明的压缩机应该能够缩小到大约1/3的尺寸......

为了测试它,我采用了最初的27MB未压缩文件并对其进行了RAR,结果为8,535,878字节。这是相当不错的,为31.6%,甚至超过三分之一!

然后我意识到我在定义测试图像时犯了一个错误。当我应该钳位到255时,我使用mod 255,这是mod 256:

unsigned char *image = new unsigned char[3000*3000*3];
for(int i=0;i<3000*3000;++i) {
    image[i*3] = i%256;
    image[i*3+1] = (i/2)%256;
    image[i*3+2] = (i*i*i)%256;
}

问题是,我的像素现在只有一个值,我之前正在跳过这个值。但是当我再次运行我的代码时,ppmz变成了一个可怜的145797字节文件。 WinRAR将其压缩到62K。

为什么这个微小的变化会导致这种巨大差异?即使是强大的WinRAR也无法获得8MB以下的原始文件。什么是每256个步骤重复值,每255个步骤完全改变?我用%255得到它,它使前两个颜色组件的模式稍微不同相,但行为几乎不是随机的。然后就是疯狂的模块化算法被转储到最后一个通道中。但我不知道它如何能够解释如此巨大的性能差距。

我想知道这是一个数学问题而不是编程问题,但我真的不知道原始数据如何包含比我新修改的数据更多的熵。我认为2依赖的力量表明与算法有关。

更新:我已经完成了另一项测试:我将第三行切换回(i*i*i)%255,但将其他行保留为%256ppmz压缩率略微上升至94.65%,RAR的比率为30.9%。所以看起来他们可以很好地处理线性增加的序列,即使它们不同步,但是有一些非常奇怪的事情,算术mod 2 ^ 8对于我们的压缩算法来说比对我们的压缩算法更友好。其他价值观。

2 个答案:

答案 0 :(得分:4)

嗯,首先,计算机就像两个人的力量。 :)

大多数此类压缩算法使用通常与2的大功率对齐的压缩块。当您的循环与这些块完美对齐时,只有一个“唯一序列”可以压缩。如果您的数据未对齐,您的序列将在每个块上移动一点,并且算法可能无法将其识别为一个“序列”。

编辑:(从评论中更新)

第二个原因是i*i*i上存在整数溢出。结果是双模数:一个超过2^32,然后一个超过255。这种双模数大大增加了循环的长度,使其接近随机,并且压缩算法难以找到“模式”。

答案 1 :(得分:2)

Mystical有很大一部分答案,但是看看数据本身的数学属性也是值得的,尤其是蓝色通道。

(i * i * i) % 255以255的周期重复,同时经常采用255个不同的值。一个天真的编码器(忽略不同像素之间或R和B像素之间的模式)需要7.99位/像素来编码蓝色通道。

每当(i * i * i) % 256是8的倍数时,

i为0(8立方为512,当然是0 mod 256);
每当i比4的倍数多4时,它就是64; 只要i小于8的倍数(一起覆盖所有4的倍数),它就是192;
它是16个不同值中的一个,i是4的偶数非倍数,取决于i的残差mod 64.
只要i为奇数,它就会占用128个不同值中的一个。

这使得蓝色像素只有147种不同的可能性,其中一些比其他像素更常见,而蓝色通道的初始熵为6.375位/像素。