数据压缩之Huffman编码
实验介绍
通过已有的HuffmanCodes项目,
1.对sena.img、omaha.img、sensin.img、Bookshelf1.img等raw图像文件进行Huffman编码;
2.自行编写一段程序,对sena.img、omaha.img、sensin.img三者进行相邻像素差值计算,并输出差值图像。然后分别对输出的差值图像进行Huffman编码;
3.使用对sensin.img图像进行Huffman编码时生成的码本(编码树),对Bookshelf1.img和sena.img图像进行Huffman编码,与自身计算得到的码本的压缩效果进行对比。
实验环境介绍和项目使用方法
本次实验使用的软件为Visual Studio 2019(版本最好在2013以上);
具体安装方式参考链接:VS2019安装教程
安装好VS2019后,打开HuffmanCodec项目文件,
即打开HuffmanCodec.sln文件。
带参数调试VS项目的方法:
对具体需要使用的项目右键,设置为启动项目;
下面以打开HuffmanEnc项目为例
如图设置为启动项目后,启动项目会高亮显示;
然后同样对使用的项目右键,点击最下面的属性,选择配置属性下的调试
在命令参数部分写入需要设置的命令即可。
以HuffEnc项目为例,从huff_enc.doc或huff_enc.c中的usage()函数中的内容可以得知,本项目输入参数包含四种:
-i 代表输入文件,本次输入的为.img格式的raw图像文件;
-o 代表输出文件,本程序的输出为.huff或.huffenc后缀的Huffman编码文件;
-c 代表编码使用的码本文件,依然以.huff或.huffenc为后缀,如果不设置,默认在编码前计算出对应图像的码本;
-s 代表码本的存储位置,以.huff或.huffenc为后缀,如果-c没有被设置,则输出由图像自身计算出的码本,如果-c被设置,则输出和-c同样的码本;如果不设置,则默认写入-o对应的输出文件的头部;
所以,输入参数的格式为:
-i 输入文件路径 -o 输出.huff文件路径 -c 输入码本路径 -s 输出码本路径
其中每一部分需要用空格间隔开。
(需要注意的是,这样的输入格式是因为项目中代码使用了相应的函数进行设置,并非所有项目的输入都有同样的参数设置格式,这里不再对这种函数进行介绍)
1.对.img图像文件进行Huffman编码
本次实验所用的图片大小皆为64KB,如图所示:
编码后结果如图所示:
其中.huffenc为图像编码后结果
_code.huffenc为对应的码本文件
可以看到编码后文件大小整体被压缩了大概5~9KB
2.编写diff程序得到差值图像,并进行Huffman编码
代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char** argv)
{
FILE* ifp, * ofp;
unsigned char* file, * tmp, * tmp_diff;
int size;
char infile[80], outfile[80];
strcpy(infile, argv[1]);
strcpy(outfile, argv[2]);
fopen_s(&ifp, infile, "rb");
if (ifp == NULL) {
printf("infile open error!");
return 0;
}
fseek(ifp, 0, 2); /* 指针从文件末尾开始 */
size = ftell(ifp); /* 获取指针所在的位置,(这里就相当于获取到了文件数据的个数) */
++size;
fseek(ifp, 0, 0); /* 指针从文件开头开始 */
file = (unsigned char*)malloc(size * sizeof(unsigned char) * 4); /* 开辟空间 */
tmp = (unsigned char*)malloc(size * sizeof(unsigned char) * 4);
tmp_diff = (unsigned char*)malloc(size * sizeof(unsigned char) * 4);
if (file == NULL) {
printf("Unable to allocate memory for file.\n");
exit(1);
}
/* 获取文件内容 */
fread(file, sizeof(unsigned char), size, ifp);
fclose(ifp);
fopen_s(&ofp, outfile, "wb");
if (ofp == NULL) {
printf("outfile open error!");
return 0;
}
int i,j;
for (i = 0;i < size;++i) {
*(tmp + i) = *(file + i);
}
for (i = 0;i < 256;++i) {
for (j = 0;j < 256;++j) {
if (j == 0)
{
*(tmp_diff + i * 256 + j) = (*(tmp + i * 256 + j) - 128);
}
else
{
*(tmp_diff + i * 256 + j) = (*(tmp + i * 256 + j) - *(file + i * 256 + j - 1));
}
}
}
fwrite(tmp_diff, sizeof(unsigned char), size, ofp);
fclose(ofp);
return 0;
}
(#define _CRT_SECURE_NO_WARNINGS为忽视老版本函数警告,
可根据具体情况进行删减;
本项目在之前的大项目下会有传参问题,
故需要在新的文件夹下另建一个项目;
本项目使用main函数进行传参,
第一个参数为 输入.img原图像的路径
第二个参数为 输出.img差值图像的路径
输出的路径同样需要先创建好文件夹)
本项目的差值压缩方法:
通常情况下,当前位置与其左侧位置的互信息最大,
即二者的相关性高,顾使用其与左侧的差值代替当前位置;
使用当前像素值减去左侧像素值得到当前位置的差值;
最左侧像素则减去128得到最左侧位置对应的差值。
使用本程序对sena.img、omaha.img、sensin.img三个图像分别进行处理,
得到输出的差值图像;
之后再对输出的差值图像进行Huffman编码;
结果如图所示:
其中_diff.img为差值图像文件;
_diff.huff对Huffman编码后的文件;
_diffcode.huff为计算出的码本文件;
可以看到,差值图像普遍比原图像增加了1KB,
是因为差值处理引入了负数导致整体大小变大了一点;
也可以看到
对差值图像编码后文件大小比原图像的编码后文件压缩比更高;
其中sena.img和sensin.img压缩提升多,但omaha.img压缩提升不明显。
3.使用其他图像码本对图像进行Huffman编码
首先使用对sensin.img图像的码本
即sensin_code.huffenc文件
对Bookshelf1.img和sena.img图像进行Huffman编码。
结果如下图所示:
可以看到使用sensin码本编码的bookshelf1.img,
编码后文件大小比使用自身码本得到的文件更大,
甚至比原图像文件更大;
而sena.img使用sensin码本编码后压缩效果也不如使用原码本。