一、实验要求
本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差(本次实验报告使用左向预测),并对预测误差进行8比特均匀量化(基本要求)。还可对预测误差进行1比特、2比特和4比特的量化设计(提高要求)。
在DPCM编码器实现的过程中可同时输出预测误差图像和重建图像。将预测误差图像写入文件并将该文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。将原始图像文件输入Huffman编码器,得到输出码流、给出概率分布图并计算压缩比。最后比较两种系统(1.DPCM+熵编码和2.仅进行熵编码)之间的编码效率(压缩比和图像质量)。压缩质量以PSNR进行计算。
二、实验原理
三、关键代码
void DpcmEn(unsigned char* yBuff, unsigned char* preerr, unsigned char* level, int h, int w, int q){
int prediction;
int err;
int i;
int j;
int a;
int b;
for (i = 0; i < h; i++){
prediction = 128;
err = yBuff[i*w] - prediction;
a = (err + 128)/pow(2, 8 - q);
if(a > pow(2, q) - 1){
a = pow(2, q) - 1;
}
if(a < 0){
a = 0;
}
preerr[i*w] = a;
b = preerr[i*w]*pow(2, 8 - q) - 128 + prediction;
if(b > 255){
b = 255;
}
if(b < 0){
b = 0;
}
level[i*w] = b;
for (j = 1; j < w; j++){
prediction = level[i*w + j - 1];
err = yBuff[i*w + j] - prediction;
a = (err + 255)/pow(2, 9 - q);
if(a > pow(2, q) - 1){
a = pow(2, q) - 1;
}
if(a < 0){
a = 0;
}
preerr[i*w + j] = a;
b = preerr[i*w + j]*pow(2, 9 - q) - 255 + prediction;
if(b > 255){
b = 255;
}
if(b < 0){
b = 0;
}
level[i*w + j] = b;
}
}
}
计算PSNR
void PrintPSNR(unsigned char* ybuffer, unsigned char* levelbuffer, int w, int h) {
double mse;
double psnr;
double sum = 0;
double temp;
int i;
for (i = 0; i < w*h; i++) {
temp = pow((ybuffer[i] - levelbuffer[i]), 2);
sum += temp;
}
mse = sum/(w * h);
psnr = 10*log10((pow(2,8)-1)*(pow(2,8)-1)/mse);
cout<<"the psnr is: "<<psnr<<endl;
}
8bit量化原始图片、输出出来的重建图片以及预测差值图片
调用了Huffman编码进行压缩的图像文件:
原图大小为96kb,运用了Huffman编码后压缩后图像大小为72.2KB,再将转化过的图像文件用Huffman码编码,压缩后文件大小如下:
四、完整代码
main函数
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
#include"DCPM.h"
using namespace std;
int main(int argc, char* argv[]){
char* yuvaddr = argv[1];
char* yuv2addr = argv[2];
int W = atoi(argv[3]);
int H = atoi(argv[4]);
char* yuverraddr = argv[5];
int imgsize = W*H*3/2;
int q = atoi(argv[6]);
unsigned char* yuvbuffer = new unsigned char[imgsize];
unsigned char* ybuffer = new unsigned char[imgsize*2/3];
unsigned char* ubuffer = new unsigned char[imgsize/6];
unsigned char* vbuffer = new unsigned char[imgsize/6];
unsigned char* preerrbuffer = new unsigned char[imgsize*2/3];
unsigned char* levelbuffer = new unsigned char[imgsize*2/3];
FILE* imgopen = fopen(yuvaddr,"rb");
if(imgopen == NULL){
cout<<"打开yuv文件失败"<<endl;
}
FILE* yuvsave = fopen(yuv2addr,"w");
if(yuvsave == NULL){
cout<<"创建yuv空白文件失败"<<endl;
}
FILE* yuvsave2 = fopen(yuverraddr,"w");
if(yuvsave2 == NULL){
cout<<"创建yuv空白文件失败"<<endl;
}
fread(yuvbuffer, sizeof(unsigned char), imgsize, imgopen);
int i;
for(i = 0; i < imgsize*2/3; i++){
ybuffer[i] = yuvbuffer[i];
}
for(i = 0; i < imgsize/6; i++){
ubuffer[i] = yuvbuffer[i+imgsize*2/3];
}
for(i = 0; i < imgsize/6; i++){
vbuffer[i] = yuvbuffer[i+imgsize*2/3+imgsize/6];
}
DpcmEn(ybuffer, preerrbuffer, levelbuffer, H, W, q);
fwrite(levelbuffer, sizeof(unsigned char), W*H, yuvsave);
fwrite(ubuffer, sizeof(unsigned char), W*H/4, yuvsave);
fwrite(vbuffer, sizeof(unsigned char), W*H/4, yuvsave);
for(i = 0; i < imgsize/6; i++){
ubuffer[i] = 128;
}
for(i = 0; i < imgsize/6; i++){
ubuffer[i] = 128;
}
fwrite(preerrbuffer, sizeof(unsigned char), W*H, yuvsave2);
fwrite(ubuffer, sizeof(unsigned char), W*H/4, yuvsave2);
fwrite(vbuffer, sizeof(unsigned char), W*H/4, yuvsave2);
PrintPSNR(ybuffer, levelbuffer, W, H);
}
DPCM.h
#ifndef DCPM_H_INCLUDED
#define DCPM_H_INCLUDED
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
using namespace std;
void DpcmEn(unsigned char* yBuff, unsigned char* preerr, unsigned char* level, int h, int w, int q){
int prediction;
int err;
int i;
int j;
int a;
int b;
for (i = 0; i < h; i++){
prediction = 128;
err = yBuff[i*w] - prediction;
a = (err + 128)/pow(2, 8 - q);
if(a > pow(2, q) - 1){
a = pow(2, q) - 1;
}
if(a < 0){
a = 0;
}
preerr[i*w] = a;
b = preerr[i*w]*pow(2, 8 - q) - 128 + prediction;
if(b > 255){
b = 255;
}
if(b < 0){
b = 0;
}
level[i*w] = b;
for (j = 1; j < w; j++){
prediction = level[i*w + j - 1];
err = yBuff[i*w + j] - prediction;
a = (err + 255)/pow(2, 9 - q);
if(a > pow(2, q) - 1){
a = pow(2, q) - 1;
}
if(a < 0){
a = 0;
}
preerr[i*w + j] = a;
b = preerr[i*w + j]*pow(2, 9 - q) - 255 + prediction;
if(b > 255){
b = 255;
}
if(b < 0){
b = 0;
}
level[i*w + j] = b;
}
}
}
void PrintPSNR(unsigned char* ybuffer, unsigned char* levelbuffer, int w, int h) {
double mse;
double psnr;
double sum = 0;
double temp;
int i;
for (i = 0; i < w*h; i++) {
temp = pow((ybuffer[i] - levelbuffer[i]), 2);
sum += temp;
}
mse = sum/(w * h);
psnr = 10*log10((pow(2,8)-1)*(pow(2,8)-1)/mse);
cout<<"the psnr is: "<<psnr<<endl;
}