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;
}