1.DPCM编解码原理
如图所示,xn为预测误差值,pn为重建值
DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中, 需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是 因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实 际内嵌了一个解码器,如编码器中虚线框中所示。
如图所示,xn为预测误差值,pn为重建值
2.PSNR公式:
I、K表示求均方误差的两个图像
MAX(I)表示图像点颜色的最大数值
3.huffman编码
使用huffcode.exe
txt文件用于存放结果:
压缩比=.huff文件大小/原.yuv文件大小
实验结果:
原图:
量化数 | 预测误差图像 | 重建图像 | PSNR |
---|---|---|---|
8bit | ![]() | ![]() | ![]() |
4bit | ![]() | ![]() | ![]() |
2bit | ![]() | ![]() | ![]() |
1bit | ![]() | ![]() | ![]() |
文件 | 大小(kb) | 压缩比 | 概率分布图 |
---|---|---|---|
原文件 | 731 | 100% | ![]() |
1bit | 91.4 | 12.50% | ![]() |
2bit | 109 | 14.91% | ![]() |
4bit | 112 | 15.32% | ![]() |
8bit | 149 | 20.38% | ![]() |
原文件仅Huffman编码 | 218 | 29.82% | ![]() |
完整代码:
#pragma once void DPCM(unsigned char* ybuff, unsigned char* buff1, unsigned char* buff2, int height, int width,int bits); int DPCME(int temp, int bits); int DPCMD(int temp, int bits); double PSNR(unsigned char* ybuff, unsigned char* buff2, int height, int width);
#include<stdio.h> #include<iostream> #include<fstream> #include<cstdio> #include "Encode.h" using namespace std; #define width 464 #define height 538 //4:4:4格式 int main(char argc,char* argv[]) { ifstream yuvfile(argv[1],ios::binary); ofstream efile(argv[2], ios::binary); ofstream rfile(argv[3], ios::binary); ofstream y_sat(argv[4], ios::trunc); if (!yuvfile) cout << "yuvfile open failed!" << endl; if (!efile) cout << "efile open failed!" << endl; if (!rfile) cout << "rfile open failed!" << endl; if (!y_sat) cout << "y_sat open failed!" << endl; unsigned char* ybuff = NULL; unsigned char* uvbuff = NULL; unsigned char* buff1 = NULL; unsigned char* buff2 = NULL; ybuff = (unsigned char*)malloc(height * width); uvbuff = (unsigned char*)malloc(height * width * 2); buff1 = (unsigned char*)malloc(height * width); buff2 = (unsigned char*)malloc(height * width); //读取原始图像Y分量及uv分量 yuvfile.read((char*)ybuff, height * width); for (int i = 0; i < width * height * 2; i++) { *(uvbuff + i) = 128; } //计算概率分布 double pro[256] = { 0 }; unsigned char y[width * height] = { 0 }; for (int i = 0; i < width * height; i++) { y[i] = *(ybuff + i); pro[y[i]] = pro[y[i]] + 1; } for (int i = 0; i < 256; i++) pro[i] = pro[i] / double(width * height); y_sat << "symbol\tfreq" << endl; for (int i = 0; i < 256; i++) { y_sat << i << "\t" << pro[i] << endl; } int bits = 8;//进行几比特量化 DPCM(ybuff,buff1,buff2,height,width,bits); //获得预测误差图像 efile.write((char*)buff1, width * height); efile.write((char*)uvbuff, width * height * 2); //获得重建图像 rfile.write((char*)buff2, width * height); rfile.write((char*)uvbuff, width * height * 2); double psnr = PSNR(ybuff, buff2, height, width); cout << psnr << endl; yuvfile.close(); efile.close(); rfile.close(); y_sat.close(); free(ybuff); free(uvbuff); free(buff1); free(buff2); return 0; }
#include<iostream> #include<fstream> #include "Encode.h" int DPCME(int temp, int bits) { temp = (temp + 255) / 2;//确保误差范围在0-255之间有利于进行量化 temp = floor(temp / pow(2, 8 - bits)); temp = temp * pow(2, 8 - bits); if (temp > 255) temp = 255; if (temp < 0) temp = 0; return temp; } int DPCMD(int temp, int bits) { temp = temp * 2 - 255; return temp; } void DPCM(unsigned char* ybuff, unsigned char* buff1, unsigned char* buff2, int height, int width,int bits) { for (int i = 0; i < height; i++) for (int j = 0; j < width; j++) { if (j == 0) { double temp = *(ybuff + i * width + j); temp = DPCME(temp, bits);//进行量化 *(buff1 + i * width + j) = temp; temp = DPCMD(temp, bits);//进行反量化 if (temp > 255) temp = 255; if (temp < 0) temp = 0; *(buff2 + i * width + j) = temp;//获得重建值 } else { int temp = *(ybuff + i * width + j) - *(buff2 + i * width + j - 1); temp = DPCME(temp, bits); *(buff1 + i * width + j) = temp; temp = DPCMD(temp, bits); temp = temp + *(buff2 + i * width + j - 1); if (temp > 255) temp = 255; if (temp < 0) temp = 0; *(buff2 + i * width + j) = temp; } } } double PSNR(unsigned char* ybuff, unsigned char* buff2, int height, int width) { int max = pow(2, 8) - 1; int size = width * height; double MSE = 0.0; for (int i= 0; i < height * width; i++) { double e = *(ybuff + i) - *(buff2 + i); MSE += e * e; } MSE = MSE / (double)(size); double psnr1 = 10 * log10((double)pow(max,2) / MSE); return psnr1; }