矢量量化——LBG算法
我的运行环境为win7 vs2013,刚打开源代码时出现错误:#include <unistd.h>无法打开源代码,原因是头文件unistd.h是Linux/Unix的系统调用,所以必须把这个头文件加入到vs2013的头文件库里面,我的电脑是在 C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include 添加一个unistd.h文件即可,其内容如下[1]:
#ifndef _UNISTD_H
#define _UNISTD_H
#include <io.h>
#include <process.h>
#endif /* _UNISTD_H */
本程序调试分三个部分:
1. trvqsp_img—获得图像矢量量化的码书(码数以分裂法初始化)
其命令参数为 ts_img codefile [-b cb_size] [-t block_height] [-w block_width] [-x row_size] [-y col_size]
ts_img:是训练图像,也即待量化压缩的图像
Codefile:以二进制格式存放码书的文件,有一个包含12个字节的文件头记录:向量的维度,以及码书的大小
-b cb_size:码书的大小
-t block_height:块的高度(以像素为单位)
-w block_width:块的宽度(以像素为单位)
-x row_size:输入图像的宽
-y col_size:输入图像的高
单步运行代码,命令参数为 earth.img earth_codefile_8_2x2 -b 8 -t 2 -w 2 -x 256 -y 256
tfp 指向输入待压缩图像文件,icb 指向存放码书的文件,( sscanf 与scanf 类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。)
经过while循环,final_codebook_size = 8,
blockr = 2,blockc = 2,row_size = 2,col_size = 2,为数据缓冲区 trimg 开辟图像大小的空间(char型),readimage(
)函数将图像数据填入缓冲区,向量维数为 2*2 = 4,训练集个数 ts_size 为 256*256/4 = 16384,经过 for 语句循环,training_set (int型)和 trimg 的对应关系如图1(把trimg中一个像素即一个char型的数据转为int型赋给training_set):
图1. training_set 和 trimg的对应关系
扰动eps固定为10,分裂法实现如下:
假定只有一个类:codebook_size = 1,先将所有训练集视为一个类,计算类中心(均值)作为测试矢量和输出水平,然后用 codebook_size 与 final_codebook_size 比大小,若假定的类的个数小于参数码书大小,则将一个类分裂成两个子类,即 codebook_size = 2*codebook_size,子类中心分别为原父中心的均值加一个扰动及原父中心的均值,vqencode( )函数返回失真较小的码书指针,count用来统计遍历训练集后,哪个码字失真更小的次数,再将每次迭代后的统计次数赋值给store,第一次迭代的失真指标是每次失真码字较小的失真总和除以训练集个数的平均值,从第二次迭代开始,每次都把上一次迭代的失真赋值给total_distortion_old,失真指标变成这一次失真相对于上一次失真减少的百分比,然后重新计算类中心(用new_codebook除以统计次数),再计算失真,循环下去,直到失真指标小于给定的阈值或迭代次数超过100次结束, 再用 codebook_size 与 final_codebook_size 比大小,循环下去,直到codebook_size 大于等于 final_codebook_size结束循环,再向码书文件中记录一些数据:块大小(宽、高),码书大小以及具体码字(大于255的一律记为255)
图2.trvqsp_img输出结果
2. vqimg_enc—根据码书对图像进行矢量量化
其命令参数为 [-i imagein] [-o cmpfile] [-c codebook] [-x row_size] [-ycol_size]
-i imagein:输入的待编码的图像文件名
-o cmpfile:输出的量化压缩后的文件名
-c cmpfile:码书文件
-x row_size:输入图像的宽
-y col_size:输入图像的高
单步运行代码,命令参数为 -i earth.img -o earth_cmp_8_2x2 -c earth_codefile_8_2x2 -x 256 -y 256
ifp 指向输入的待编码的图像文件,ofp 指向输出的量化压缩后的文件,经过一系列赋值之后,将codebook文件名的长度以及文件名、原图像的高和宽写入输出文件,从码书文件中读出块的宽和高以及码书大小分别赋值给各参数,计算每个块需要多少比特来表示,numbits
= 3bits,为码书开辟空间,从码书文件中读取码字,然后通过 vqencode( )函数来衡量每个图像块距离最近的码字索引index,stuffit( )函数将一个整字节(8比特)的编码赋值给save,再写入输出文件,filled用来表示一个字节中有几比特码字已经填好,move表示移位的位数,直到16384个训练集都遍历完毕, end_flag = 1,编码完毕,跳出for循环,最后计算平均失真,如图3。
图3. vqimg_enc输出结果
3. vqimg_dec—根据码书文件和压缩后的文件重构原始图像
其命令参数为 [-i cmpfile] [-o imageout]
-i cmpfile:压缩文件名
-o imageout:重建图像文件名
单步运行代码,命令参数为 -i earth_cmp_8_2x2 -o earth_8_2x2.img
从压缩文件中读取码书文件名的长度,为存储文件名开辟空间,再从压缩文件中读取码书文件名赋值给cbfile,然后打开码书文件,再从压缩文件中读取原图像的宽和高,为数据缓冲区outimg开辟存储重建图像数据的空间,从码书文件中读取块的宽和高以及码书大小,计算每个码字需要的比特数,为码书开辟空间,从码书文件中逐字节的读取码字填入刚刚开辟的码书数据缓冲区,unstuff( )函数将压缩文件中的码字索引读入buffer中,然后重建图像,每个图像块先从buffer中读出码书索引,然后将对应的码字赋给该图像块。
图4. vqimg_dec输出结果
原图像与重建图像的对比图如下:
原图 earth.img 重建图像earth_8_2x2.img
参考文献
[1] 在vs2013下如何使用头文件unistd.h和去除vs2013编译警告—http://blog.csdn.net/earbao/article/details/51757334
上一篇: TS码流分析