【数据压缩7】Lab4 DPCM压缩系统的实现和分析
文章目录
一、实验项目名称
DPCM 压缩系统的实现和分析
二、实验目的
掌握DPCM编解码系统的基本原理。初步掌握实验用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。
三、主要设备
安装 Windows 和 Visual Studio 等编程平台的个人计算机
四、实验内容和原理
1. 量化器
**量化:**用一个很小的集合表示一个大集合。
描述:
1.
量
化
区
间
的
数
目
:
M
=
2
n
2.
量
化
区
间
的
索
引
:
i
3.
决
策
边
界
:
b
i
4.
重
构
水
平
:
y
i
=
b
i
+
b
i
−
1
2
5.
量
化
间
隔
(
步
长
)
:
Δ
=
2
∗
X
m
a
x
M
,
信
源
的
取
值
范
围
[
−
X
m
a
x
,
X
m
a
x
]
6.
量
化
失
真
的
度
量
:
e
(
x
)
=
x
−
x
′
1.量化区间的数目:M=2^n\\ 2.量化区间的索引:i\\ 3.决策边界:b_i\\ 4.重构水平:y_i=\frac {b_i+b_{i-1}} 2\\ 5.量化间隔(步长):\Delta=\frac {2*X_{max}} M ,信源的取值范围[-X_{max},X_{max}]\\ 6. 量化失真的度量:e(x)=x-x'
1.量化区间的数目:M=2n2.量化区间的索引:i3.决策边界:bi4.重构水平:yi=2bi+bi−15.量化间隔(步长):Δ=M2∗Xmax,信源的取值范围[−Xmax,Xmax]6.量化失真的度量:e(x)=x−x′
2. DPCM编解码原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
本实验中,DPCM对当前值和预测值的差值(预测误差)进行量化,预测误差值的范围为[-255,255],因此用9bit表示且需要单极性化(+255)。残差值的量化映射方法是除以量化间隔再取整,这种量化方法相当于每次取下电平。
3. DPCM编码系统的设计
本实验的目标是验证DPCM编码的编码效率。在本次实验中,我们采用:
- 固定预测器和均匀量化器;
- 预测器采用左侧、上方预测均可;
- 量化器采用8比特均匀量化。
4. 压缩质量客观评价(PSNR)
通常用来评价一幅图像压缩后和原图像相比质量的好坏,压缩后图像一定会比原图像质量差的,PSNR越高,压缩后失真越小。这里主要定义了两个值,一个是均方差MSE,另一个是峰值信噪比PSNR(dB),这里的MAX通常是图像的灰度级,一般就是255。
PSNR值 | 评价 |
---|---|
高于40dB: | 说明图像质量极好(即非常接近原始图像) |
30—40dB: | 通常表示图像质量是好的(即失真可以察觉但可以接受) |
20—30dB: | 说明图像质量差 |
五、实验步骤
- 首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求)。还可对预测误差进行1比特、2比特和4比特的量化设计(提高要求)。
- 在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。
- 将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
- 将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。
- 最后比较两种系统(1.DPCM+熵编码和 2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。
1. 主函数
- 设置文件参数
- 开辟缓冲区
- 打开文件(输入文件和输出文件)
- 左向差分预测编码,计算压缩质量
- 统计残差的概率分布(matlab画图)
- 结果写入
- 释放缓冲区,关闭文件
int main()
{
// 1. 文件参数
const int width = 256;
const int height = 256;
int bitdepth = 8;//量化比特数
// 2. 缓冲区
unsigned char* ybuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height); // 原图
unsigned char* ubuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 0.25); //4:2:0
unsigned char* vbuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height * 0.25);
unsigned char* ebuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height); // 预测误差图像
unsigned char* rebuf = (unsigned char*)malloc(sizeof(unsigned char) * width * height); // 重建图像
double* freq_y = (double*)malloc(sizeof(double) * 256);// 原图概率分布
double* freq_e= (double*)malloc(sizeof(double) * 256);// 残差图概率分布
// 3. 定义文件指针,打开文件
// input
FILE* yuv = fopen("lena.yuv", "rb");// 打开原图
fread(ybuf, sizeof(unsigned char), width * height, yuv);// 读取原始图像
fread(ubuf, sizeof(unsigned char), width * height * 0.25, yuv);
fread(vbuf, sizeof(unsigned char), width * height * 0.25, yuv);
// output
FILE* qyuv = fopen("lena_q.yuv", "wb");// 预测误差图像
FILE* reyuv = fopen("lena_re.yuv", "wb");// 重建图像
FILE* efile = fopen("e.txt", "w"); // 残差图概率分布
FILE* yfile = fopen("y.txt", "w");// 原图概率分布
// 4. 左向差分预测编码,计算压缩质量
Left_DPCM(ybuf, ebuf, rebuf, width, height, bitdepth);
PSNR(ybuf, rebuf, height, width, bitdepth);
// 5. 统计概率分布
int cout_y[256] = { 0 };
int cout_e[256] = { 0 };
for (int i = 0; i < width * height; i++){
cout_y[ybuf[i]]++;
freq_y[ybuf[i]] = double(cout_y[ybuf[i]]) / (width * height);// 原图概率分布
}
for (int i = 0; i < width * height; i++) {
cout_e[ebuf[i]]++;
freq_e[ebuf[i]] = double(cout_e[ebuf[i]]) / (width * height);// 残差图概率分布
}
// 6. 结果写入
fwrite(ebuf, sizeof(unsigned char), width * height, qyuv);// 残差图
fwrite(ubuf, sizeof(unsigned char), width * height * 0.25, qyuv);
fwrite(vbuf, sizeof(unsigned char), width * height * 0.25, qyuv);
fwrite(rebuf, sizeof(unsigned char), width * height, reyuv);// 重建图
fwrite(ubuf, sizeof(unsigned char), width * height * 0.25, reyuv);
fwrite(vbuf, sizeof(unsigned char), width * height * 0.25, reyuv);
for (int i = 0; i < 256; i++){ // 概率分布
fprintf(yfile, "%f\n",freq_y[i]);
fprintf(efile, "%f\n", freq_e[i]);
}
// 7. 释放缓冲区,关闭文件
free(ybuf); free(ubuf); free(vbuf);free(ebuf); free(rebuf);
fclose(yuv);fclose(qyuv);fclose(reyuv);fclose(efile);fclose(yfile);
}
2. DPCM左向预测函数
采用左向预测的方法,第一列像素的误差值设为128。输入原图指针,残差图指针,重建图指针,宽,高,量化比特数。
残差图:当前值 - 前一个像素的重建值
e
(
n
)
=
y
(
n
)
−
r
e
(
n
−
1
)
e
^
(
n
)
=
e
(
n
)
+
255
Δ
∗
0.5
Δ
e(n)=y(n)-re(n-1)\\ \hat e(n)=\frac {e(n)+255} \Delta *0.5\Delta
e(n)=y(n)−re(n−1)e^(n)=Δe(n)+255∗0.5Δ
重建图:预测误差值 + 前一个像素的重建值
r
e
(
n
)
=
e
^
(
n
)
+
r
e
(
n
−
1
)
re(n)=\hat e(n)+re(n-1)
re(n)=e^(n)+re(n−1)
void DPCM(unsigned char* ybuf, unsigned char* ebuf, unsigned char* rebuf, int width, int height, int bitNum)
{
int quantized_interval = 512 / pow(2, bitNum);// 量化间隔
int error; // 差值
int rebuild_value;// 重建值
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++)
{
if (j == 0) { //第一列
error = ybuf[width * i + j] - 128;
ebuf[width * i + j] = int((error + 255) / quantized_interval) * quantized_interval / 2;
rebuild_value = (ebuf[width * i + j] * 2) - 255 + 128;
}
else {
error = ybuf[width * i + j] - rebuf[width * i + j - 1];
ebuf[width * i + j] = int((error + 255) / quantized_interval) * quantized_interval / 2;
rebuild_value = (ebuf[width * i + j] * 2) - 255 + rebuf[j - 1 + width * i];
}
if (rebuild_value > 255)
rebuild_value = 255;
if (rebuild_value < 0)
rebuild_value = 0;
rebuf[width * i + j] = rebuild_value;
}
}
}
3. PSNR峰值信噪比函数
先计算量化的均方误差 MSE ,再计算PSNR。
int PSNR(unsigned char* ybuf, unsigned char* rebuf, int height, int width, int dep)
{
double max = 255;
double mse = 0;
double psnr;
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++){
mse += (ybuf[i * width + j] - rebuf[i * width + j]) * (ybuf[i * width + j] - rebuf[i * width + j]);
}
mse = mse / (double)(width * height);
psnr = 10 * log10((double)(max * max) / mse);
cout << dep << "比特量化时PSNR = " << psnr << endl;
return 0;
}
4. Huffman熵编码
准备:
transfer.bat文件内容如下:
huff_run.exe -i lena.yuv -o lena.huff -c -t lena.txt
huff_run.exe -i lena_e8.yuv -o lena_e8.huff -c -t lena_e8.txt
huff_run.exe -i lena_e4.yuv -o lena_e4.huff -c -t lena_e4.txt
huff_run.exe -i lena_e2.yuv -o lena_e2.huff -c -t lena_e2.txt
熵编码结果:
六、实验结果
1. 图像质量
原图:
熵编码是无损编码,图片质量最好;量化比特数越高,压缩后的图片质量越高。即:熵编码>8bit DPCM+熵编码>4bit DPCM+熵编码>2bit DPCM+熵编码。
2. 压缩比
压缩比=输入/输出,压缩比越高说明压缩效率越高。
熵编码是无损编码,压缩效率比较低;量化比特数越低,压缩效率越高。即:熵编码<8bit DPCM+熵编码<4bit DPCM+熵编码<2bit DPCM+熵编码。
熵编码输入图像灰度的概率分布图 | 压缩比 | |
---|---|---|
仅进行熵编码 | 1.39 | |
8bit DPCM+熵编码 | 2.09 | |
4bit DPCM+熵编码 | 4.36 | |
2bit DPCM+熵编码 | 5.33 |
3. 结论
(1)量化区间数目的对比
根据重建图像主客观评价,量化区间数目(量化比特数)越小,图像失真越明显;根据概率分布图,量化区间数目(量化比特数)越小,压缩效率越高。量化器是失真和码率的折中,需要8bit及其以上的量化器才能保证图像质量。
颗粒噪声:平坦区域的随机噪声。出现在灰度值变化慢的区域。
斜率过载:边缘模糊。出现在灰度值变化快的区域,量化比特数越小越明显。
(2)压缩系统的对比
-
对比两种压缩系统,仅有熵编码的压缩比远不如DPCM+熵编码的压缩比。
-
先预测编码再无失真编码的原因:对于无失真编码来讲(Huffman编码),根据香农第一定理(无失真变长信源编码定理),信源熵决定平均码长的下界,即输入信源熵越小,平均码长越可能小,压缩效率越高。
如果使信源熵变小,就需要概率分布不均匀。利用信号之间的相关性(差分预测编码)或者去除信号的相关性(变化编码),即可将均匀分布的信号转化为不均匀的信号。
-
和实际信号的分布相比,预测误差是关于0的高尖峰。因此,预测误差具有比原始密度更小的熵。这意味着预测的过程把样值间的大部分冗余去掉了。
综上所述,无失真编码之前进行预测编码,能够提高系统性能;而且量化误差合适的情况下,可以几乎不引起失真。