实验目的:掌握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要好



