结合实验二代码
文章目录
一、实验目的
掌握DPCM编解码系统的基本原理。
初步掌握实验用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。
二、实验原理
1.DPCM编解码原理
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。
在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。
因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。
2.峰值信噪比
三、实验代码
1.main.cpp:
(1)开拓空间
int main(int argc, char** argv)
{
/* variables controlable from command line */
u_int frameWidth = 352; /* --width=<uint> */
u_int frameHeight = 240; /* --height=<uint> */
unsigned int i;
/* internal variables */
char* yuvFileName = NULL;
char* reFileName = NULL;
char* qFileName = NULL;
FILE* yuvFile = NULL;
FILE* reFile = NULL;
FILE* qFile = NULL;
u_int8_t* fileBuf = NULL;
u_int8_t* yBuf = NULL;
u_int8_t* reBuf = NULL;
u_int8_t* qBuf = NULL;
u_int32_t videoFramesWritten = 0;
yuvFileName = argv[1];
qFileName = argv[2];
reFileName = argv[3];
frameWidth = atoi(argv[4]);
frameHeight = atoi(argv[5]);//atoi字符串转为数字
(2)打开输入的yuv文件
yuvFile = fopen(yuvFileName, "rb");
if (yuvFile == NULL)
{
printf("cannot find yuv file\n");
exit(1);
}
else
{
printf("The input yuv file is %s\n", yuvFileName);
}
(3)打开输出的(要写入的)重建图像和残差图像
qFile = fopen(qFileName, "wb");
reFile = fopen(reFileName, "wb");
qBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
reBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);
fileBuf = (u_int8_t*)malloc(frameWidth * frameHeight / 2);
fread(yBuf, 1, frameWidth * frameHeight, yuvFile);
DPCM(frameHeight, frameWidth, yBuf, qBuf, reBuf);
for (int i = 0; i < frameWidth * frameHeight / 2; i++)
{
fileBuf[i] = 128;
}
fwrite(qBuf, 1, frameWidth * frameHeight, qFile);
fwrite(fileBuf, 1, frameWidth * frameHeight / 2, qFile);
fwrite(reBuf, 1, frameWidth * frameHeight, reFile);
fwrite(fileBuf, 1, frameWidth * frameHeight / 2, reFile);
(4)关闭
free(yBuf);
free(qBuf);
free(reBuf);
free(fileBuf);
fclose(qFile);
fclose(reFile);
fclose(yuvFile);
2.dpcm.cpp
(1)8bit
void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
int size = width * height;
for (int i = 0; i < size; i++) {
if (i % width == 0) { //判断是否是每行第一个像素
qBuf[i] = yuvBuf[i];
reBuf[i] = yuvBuf[i];
}
else {
int dn = yuvBuf[i] - reBuf[i - 1];// dn的范围是-255 — 255
//8比特量化,为0-255
dn >>= 1;//-127 - 127
int temp = dn + 128;//0 - 255
qBuf[i] = temp;
reBuf[i] = qBuf[i] * 2 + reBuf[i - 1];
}
}
}
(2)4bit
void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
int size = width * height;
for (int i = 0; i < size; i++) {
if (i % width == 0) { //判断是否是每行第一个像素
int k = 256 / pow(2, 4);
qBuf[i] = int(yuvBuf[i] / k);
reBuf[i] = int(yuvBuf[i] / k);
}
else {
int dn = yuvBuf[i] - reBuf[i - 1];// dn的范围是-255 — 255
//4比特量化
dn >>= 5;//-7 - 7
int temp = dn + 8;//0 - 15
qBuf[i] = temp;
reBuf[i] = qBuf[i] * 32 + reBuf[i - 1];
}
}
}
(3)2bit
void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
int size = width * height;
for (int i = 0; i < size; i++) {
if (i % width == 0) { //判断是否是每行第一个像素
int k = 256 / pow(2, 6);
qBuf[i] = int(yuvBuf[i] / k);
reBuf[i] = int(yuvBuf[i] / k);
}
else {
int dn = yuvBuf[i] - reBuf[i - 1];// dn的范围是-255 — 255
//2比特量化
dn >>= 7;//-1 - 1
int temp = dn + 2;//0 - 3
qBuf[i] = temp;
reBuf[i] = qBuf[i] * 128 + reBuf[i - 1];
}
}
}
(4)1bit
void DPCM(short int height, short int width, unsigned char* yuvBuf, unsigned char* qBuf, unsigned char* reBuf)
{
int size = width * height;
for (int i = 0; i < size; i++) {
if (i % width == 0) { //判断是否是每行第一个像素
int k = 256 / pow(2, 7);
qBuf[i] = int(yuvBuf[i] / k);
reBuf[i] = int(yuvBuf[i] / k);
}
else {
int dn = yuvBuf[i] - reBuf[i - 1];// dn的范围是-255 — 255
//1比特量化
dn >>=8;
int temp = dn + 1;
qBuf[i] = temp;
reBuf[i] = qBuf[i] * 256 + reBuf[i - 1];
}
}
}
四、实验结果
原图:
1.8bit:
2.4bit:
3.2bit:
4.1bit:
五、实验分析
1.比较编码质量:
计算各自量化标准下原始图像和重建图像间的峰值信噪比:
psnr.cpp:
#include <math.h>
double psnr(unsigned char* ybuf, unsigned char* rebuf, int height, int width)
{
double mse = 0;
double div = 0;
double psnr = 0;
for (int v = 0; v < height; v++)
{
for (int u = 0; u < width; u++)
{
div = rebuf[v * width + u] - ybuf[v * width + u];
mse += div * div;
}
}
mse = mse / (width * height);
psnr = 10 * log10(255 * 255 / mse);
return psnr;
}
在main.cpp关闭文件前加入:
double ps = psnr(yBuf, reBuf, frameHeight, frameWidth);
cout << ps;
8bit:51.7761
4bit:23.1471
2bit:14.8853
1bit:10.0007
2.比较编码效率:
利用哈弗曼编码的可执行程序得到两个.huff文件
(1)将预测误差图像写入文件并将该文件输入Huffman编码器
(2)将原始图像文件输入Huffman编码器
比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)
前者:(96-32.6)/96
后者:(96-80.7)/96
总结
好难