实验目的:掌握DPCM编解码系统的基本原理。初步掌握实验用C/C++/Python等语言编程实现DPCM编码器,并分析其压缩效率。
DPCM编码原理:
在一个DPCM系统中,需要设计预测器和量化器两部分,在本次实验中,采用固定预测器和均匀量化器
代码部分:
#include
#include
#include
using namespace std;
int main(int argc, char** argv)
{
char* orifilename = NULL;
char* prefilename = NULL;
char* recfilename = NULL;
orifilename = argv[1];
prefilename = argv[2];
recfilename = argv[3];
FILE* fp1 = fopen(orifilename, "rb");
FILE* fp2 = fopen(prefilename, "wb");
FILE* fp3 = fopen(recfilename, "wb");
if (fp1 == NULL)
cout << "cannot find oriyuv" << endl;
if (fp2 == NULL)
cout << "cannot find preyuv" << endl;
if (fp3 == NULL)
cout << "cannot find recyubv" << endl;
unsigned char* oribuffer;
unsigned char* prebuffer;
unsigned char* recbuffer;
unsigned char* u_buffer;
unsigned char* v_buffer;
int width = atoi(argv[4]);
int height = atoi(argv[5]);
oribuffer = (unsigned char*)malloc(width * height * 1.5);
prebuffer = (unsigned char*)malloc(width * height * 1.5);
recbuffer = (unsigned char*)malloc(width * height);
u_buffer = (unsigned char*)malloc(width * height * 1 / 4);
v_buffer = (unsigned char*)malloc(width * height * 1 / 4);
fread(oribuffer, sizeof(unsigned char), width * height, fp1);
int p1;
int p2;
unsigned char p3;
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
if (j == 0)
{
*(recbuffer + i * width + j) = 128;
*(prebuffer + i * width + j) = *(oribuffer + i * width + j) - 128;
}
else
{
p1 = *(oribuffer + i * width + j) - *(oribuffer + i * width + j - 1);//误差
if (p1 % 2 == 0)
p2 = p1 / 2 + 128;//8bit量化
else
p2 = (p1 - 1) / 2 + 128;//8bit量化
*(prebuffer + i * width + j) = unsigned char(p2);
p3 = unsigned char(p2 * 2);//反量化
*(recbuffer + i * width + j) = *(oribuffer + i * width + j - 1) + p3;
}
}
}
for (int i = 0; i < height / 2; i++)
{
for (int j = 0; j < width / 2; j++)
{
*(u_buffer + i * width / 2 + j) = 128;
*(v_buffer + i * width / 2 + j) = 128;
}
}
fwrite(recbuffer, 1, width * height, fp3);
fwrite(u_buffer, 1, width * height / 4, fp3);
fwrite(v_buffer, 1, width * height / 4, fp3);
fwrite(prebuffer, 1, width * height, fp2);
fwrite(u_buffer, 1, width * height / 4, fp2);
fwrite(v_buffer, 1, width * height / 4, fp2);
int max = 255;
double mse = 0;
for (int i = 0; i < width * height; i++)
{
mse += (double(oribuffer[i]) - double(recbuffer[i])) * (double(oribuffer[i]) - double(recbuffer[i])); //分子
}
mse = (double)mse / (double)(width * height);
double psnr = 10 * log10((double)(max * max) / mse);
cout << "PSNR = " << psnr;
return 0;
}
dpcm编码
for(int i=0;i < frameWidth*frameHeight;i++)
{
if(i % frameWidth==0)
{
prebuf[i]=(yBuf[i]-128)/2+128;
resconbuf[i]=(prebuf[i]-128)*2+ 128;//重现信号为预测信号反量化后的值+0
}
else{
prebuf[i]=(yBuf[i]- resconbuf[i-1])/2+128;// 预测信号为当前输入的y信号与上一个重现信号的差值做量化
resconbuf[i]=((prebuf[i]-128)*2+resconbuf[i-1]);//重现信号为当前预测信号反量化后的值与上个重现信号的和的值
}}
psnr代码
double MSE = 0;
double sub = 0;
double sum = 0;
for (int j = 0; j < 256; j++)
{
for (int i = 0; i <256; i++)
{
sub = yBuf[i] - resconbuf[i];
sum = sum + pow(sub, 2);
}
}
MSE = (sum) / (256 * 256);
double psnr = 10 * log10 ((255 * 255) / MSE);
cout<<"PSNR="<
实验结果及分析:
8bit:
4bit :
2bit:
1、从预测误差图像概率分布与原始图像的概率分布对比可以看出,预测误差图像的概率分布更集中,大部分像素都集中在灰度值为100-150之间,像素之间的关联性更高分布的很集中,很适合用霍夫曼编码进行熵编码,压缩的时候更加容易,而原始图像的概率分布则更均匀,在进行霍夫曼编码时压缩的效率就没有那么高。
2、PSNR越大,图像质量越好,8bit量化的重现图像的PSNR=51.1411dB,比4/2/1bit要好