数据压缩_实验四_DCPM编码实验

Netany ·
更新时间:2024-09-21
· 676 次阅读

文章目录DPCM编码实验一、实验原理1、DPCM编解码原理二、实验步骤1、基本流程2、关键代码(1)绘制原图像Y分量概率分布图(2)取图像第一列直接赋值(3)DPCM编码(4)量化与反量化(5)计算PSNR(6)计算预测图像量化索引概率分布(7)将量化索引映射至0~255三、实验结果四、完整代码 DPCM编码实验 一、实验原理 1、DPCM编解码原理

DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,

需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是

因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实

际内嵌了一个解码器,如编码器中虚线框中所示。

截屏2020-05-03上午9.59.41

二、实验步骤 1、基本流程 test 2、关键代码 (1)绘制原图像Y分量概率分布图 // 计算原始图像Y概率分布,输出至txt void img_freq(unsigned char* y,int width,int height) { int count_Y[256] = { 0 }; double freq_Y[256] = { 0 }; for (int i = 0; i < width*height; i++) { count_Y[*(y + i)]++; } ofstream Y_sat; Y_sat.open("Y_sat.txt", ios::out, ios::trunc); if (!Y_sat) { cout << "Error opening Y_sat.txt" << endl; } else { Y_sat << "symbol\tfreq" << endl; for (int i = 0; i < 256; i++) { freq_Y[i] = count_Y[i] / (double)(width * height); Y_sat << i << "\t" << freq_Y[i] << endl; } } Y_sat.close(); }

以图像seed.yuv为例,画出概率分布图如下:

image-20200503102423291 (2)取图像第一列直接赋值

由于DPCM预测编码是取左侧像素重建值与当前像素真实值相减,第一列像素无前序重建值,故直接将第一列像素值赋给重建图像,取预测误差为0。

// 将第一列全部写入重建图像 for (int i = 0; i < Height; i++) { ybuff_recon[i * Width] = ybuff[i * Width]; ybuff_pre_d[i * Width] = 0; ybuff_pre[i * Width] = Quantify(N_bits, ybuff_pre_d[i * Width]); val_error[i * Width] = 0; } (3)DPCM编码

DPCM基本框架如下:

// DPCM for (int j = 0; j < Height; j++) { for (int i = 1; i 255 ? 255 : temp; temp = temp < 0 ? 0 : temp; ybuff_recon[j * Width + i] = (unsigned char)temp; // 求解重建值和与实际值误差 val_error[j * Width + i] = (int)ybuff_recon[j * Width + i] - (int)ybuff[j * Width + i]; } } (4)量化与反量化 依据设定的量化比特数,将-255~+255均匀划分为2N_bits个区间,取区间中值作为重构水平。 编码器将每个区间的索引发给解码器。 解码器用重构水平表示该区间内所有的值。 // 量化 unsigned char Quantify(int N_Bits,int x) { int temp = 0; switch (N_Bits) { case 1: temp = (int)((x + 255) / 255.5); break; case 2: temp = (int)((x + 255) / 127.75); break; case 4: temp = (int)((x + 255) / 31.9375); break; case 8: temp = (int)((x + 255) / 2.0); break; default: cout << "error" << endl; exit(0); break; } return (unsigned char)temp; } // 反量化 int Re_Quantify(int N_Bits, unsigned char x) { int temp = (int)x; switch (N_Bits) { case 1: temp = (int)((temp * 255.5 + 127.75) - 255 + 0.5); break; case 2: temp = (int)((temp * 127.5 + 63.75) - 255+0.5); break; case 4: temp = (int)((temp * 31.9375 + 15.96875) - 255+0.5); break; case 8: temp = (temp * 2) - 255; break; default: cout << "error" << endl; exit(0); break; } return temp; } (5)计算PSNR

峰值信噪比(PSNR), 一种评价图像的客观标准。PSNR一般是用于最大值信号和背景噪音之间的一个工程项目。通常在经过影像压缩之后,通常输 出的影像都会在某种程度与原始影像不同。为了衡量经过处理后的影像品质,我们通常会参考PSNR值来衡量某个处理程序能否令人满意。

PSNR计算公式如下:
PSNR=10log10(MAX2MSE) \text{} PSNR=10log_{10}\left( \frac{MAX^{2}}{MSE} \right) PSNR=10log10​(MSEMAX2​)

MSE=1mn∑i=1n∑j=1m∣K(i,j)−I(i,j)∣2 MSE=\frac{1}{mn} \sum^{n}_{i=1} \sum^{m}_{j=1} \left\vert K\left( i,j\right) -I\left( i,j\right) \right\vert^{2} MSE=mn1​i=1∑n​j=1∑m​∣K(i,j)−I(i,j)∣2

// 计算PSNR double Count_PSNR(int N_bits, int width,int height,int* delta) { double psnr = 0; double mse = 0; for (int i = 0; i < width*height; i++) { mse += pow(*(delta + i), 2); } mse = mse / (width * height); psnr = 10 * log10(pow((pow(2, N_bits) - 1), 2) / mse); return psnr; } (6)计算预测图像量化索引概率分布 // 计算预测图像Y概率分布,输出至txt void predict_freq(int N_bits, int width, int height, unsigned char* ybuff) { double* freq = new double[pow(2, N_bits)]; for (int i = 0; i < pow(2, N_bits); i++) { *(freq + i) = 0; } for (int i = 0; i < width*height; i++) { int temp = (int)*(ybuff + i); *(freq + temp) = *(freq + temp) + 1; } // 写入txt ofstream Predict_sat; Predict_sat.open("Predict_sat.txt", ios::out, ios::trunc); if (!Predict_sat) { cout << "Error opening Predict_sat.txt" << endl; } else { Predict_sat << "symbol\tfreq" << endl; for (int i = 0; i < pow(2, N_bits); i++) { *(freq + i) = *(freq + i) / (double)(width * height); Predict_sat << i << "\t" << *(freq + i) << endl; } } Predict_sat.close(); if (freq!=NULL) { delete[]freq; } } (7)将量化索引映射至0~255

将1bit、2bit、4bit量化后的量化区间索引映射至0~255,便于直接在图像中观察量化误差。

// 映射至8bit void Map_To_8(int N_bits, int width,int height,unsigned char* ybuff) { double N = pow(2, N_bits); for (int i = 0; i < width* height; i++) { *(ybuff + i) =(unsigned char) (*(ybuff + i) * (255.0 / N) + (255 / (2 * N)+0.5)); } } 三、实验结果

原始图像

截屏2020-05-03下午1.02.54
截屏2020-05-03下午1.03.50 截屏2020-05-03下午1.04.04
截屏2020-05-03下午1.04.52 截屏2020-05-03下午1.05.04
截屏2020-05-03下午1.05.38 截屏2020-05-03下午1.05.50
截屏2020-05-03下午1.06.22 截屏2020-05-03下午1.06.35
image-20200503125917917 image-20200503125838429
image-20200503125555322 image-20200503125738685

将原始图像文件输入Huffman编码器后,压缩比为33.83%

量化比特数 PSNR 压缩比
1bit 51.1587 16.78%
2bit 29.291 18.83%
4bit 16.9087 19.37%
8bit 10.9245 27.97%

由表可知,8bit量化的图像质量最好但压缩效率最低。1bit量化的图像质量最差但压缩效率最高。
当量化比特数过低时,图像出现颗粒杂波、边缘忙乱和伪轮廓失真。

四、完整代码 // Lab_4_DPCM.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "DPCM.h" int main(int argc, char* argv[]) { int N_bits=8; int Width = 500; int Height = 500; unsigned char* ybuff = NULL, * ubuff = NULL, * vbuff = NULL; // 原始图像buffer ybuff = new unsigned char[Width * Height]; ubuff = new unsigned char[Width * Height]; vbuff = new unsigned char[Width * Height]; // 预测误差buffer unsigned char* ybuff_pre = NULL; int* ybuff_pre_d = NULL; ybuff_pre = new unsigned char[Width * Height]; ybuff_pre_d = new int[Width * Height]; // 重建图像buffer unsigned char* ybuff_recon = NULL; ybuff_recon = new unsigned char[Width * Height]; // 重建值和与实际值误差buffer int *val_error = NULL; val_error = new int[Width * Height]; ifstream ImageFile; ImageFile.open("seed.yuv", ios::in | ios::binary); if (!ImageFile.is_open()) { cout << "ImageFile open failed." << endl; } ImageFile.read((char*)ybuff, Width * Height); ImageFile.read((char*)ubuff, Width * Height); ImageFile.read((char*)vbuff, Width * Height); // 计算原始图像Y概率分布,输出至txt img_freq(ybuff, Width, Height); // 将第一列全部写入重建图像 for (int i = 0; i < Height; i++) { ybuff_recon[i * Width] = ybuff[i * Width]; ybuff_pre_d[i * Width] = 0; ybuff_pre[i * Width] = Quantify(N_bits, ybuff_pre_d[i * Width]); val_error[i * Width] = 0; } // DPCM for (int j = 0; j < Height; j++) { for (int i = 1; i 255 ? 255 : temp; temp = temp < 0 ? 0 : temp; ybuff_recon[j * Width + i] = (unsigned char)temp; // 求解重建值和与实际值误差 val_error[j * Width + i] = (int)ybuff_recon[j * Width + i] - (int)ybuff[j * Width + i]; } } cout << "量化比特数:" << N_bits << endl; cout <<"PSNR = "<< Count_PSNR(8,Width,Height,val_error) << endl; // 计算预测图像Y概率分布, 输出至txt predict_freq(N_bits, Width, Height, ybuff_pre); // 将输出文件映射至8bit if (N_bits != 8) { Map_To_8(N_bits, Width, Height, ybuff_pre); } WriteYUV("Predict_img.yuv",Height, Width, ybuff_pre, ubuff, vbuff); WriteYUV("Recon_img.yuv",Height, Width, ybuff_recon, ubuff, vbuff); ImageFile.close(); if (ybuff != NULL) { delete[]ybuff; } if (ubuff != NULL) { delete[]ubuff; } if (vbuff != NULL) { delete[]vbuff; } if (ybuff_pre != NULL) { delete[]ybuff_pre; } if (ybuff_pre_d != NULL) { delete[]ybuff_pre_d; } if (ybuff_recon != NULL) { delete[]ybuff_recon; } if (val_error != NULL) { delete[]val_error; } } #pragma once #ifndef DPCM_H_ #include #include #include #include #include using namespace std; void WriteYUV(const char* File_name, int Height, int Width, unsigned char* Y, unsigned char* U, unsigned char* V); unsigned char Quantify(int N_Bits, int x); int Re_Quantify(int N_Bits, unsigned char x); double Count_PSNR(int N_bits, int width, int height, int* delta); void img_freq(unsigned char* y, int width, int height); void Map_To_8(int N_bits, int width, int height, unsigned char* ybuff); void predict_freq(int N_bits, int width, int height, unsigned char* ybuff); #endif // !DPCM_H_ #include "DPCM.h" // 写入YUV文件444格式 void WriteYUV(const char* File_name,int Height, int Width, unsigned char* Y, unsigned char* U, unsigned char* V) { ofstream File_out; File_out.open(File_name, ios::binary, ios::trunc); if (!File_out) { cout << "Failed to open NewImage.yuv" << endl; } else { File_out.write((char*)Y, Height * Width); File_out.write((char*)U, Height * Width); File_out.write((char*)V, Height * Width); File_out.close(); } } // 量化 unsigned char Quantify(int N_Bits,int x) { int temp = 0; switch (N_Bits) { case 1: temp = (int)((x + 255) / 255.5); break; case 2: temp = (int)((x + 255) / 127.75); break; case 4: temp = (int)((x + 255) / 31.9375); break; case 8: temp = (int)((x + 255) / 2.0); break; default: cout << "error" << endl; exit(0); break; } return (unsigned char)temp; } // 反量化 int Re_Quantify(int N_Bits, unsigned char x) { int temp = (int)x; switch (N_Bits) { case 1: temp = (int)((temp * 255.5 + 127.75) - 255 + 0.5); break; case 2: temp = (int)((temp * 127.5 + 63.75) - 255+0.5); break; case 4: temp = (int)((temp * 31.9375 + 15.96875) - 255+0.5); break; case 8: temp = (temp * 2) - 255; break; default: cout << "error" << endl; exit(0); break; } return temp; } // 计算PSNR double Count_PSNR(int N_bits, int width,int height,int* delta) { double psnr = 0; double mse = 0; for (int i = 0; i < width*height; i++) { mse += pow(*(delta + i), 2); } mse = mse / (width * height); psnr = 10 * log10(pow((pow(2, N_bits) - 1), 2) / mse); return psnr; } // 计算原始图像Y概率分布,输出至txt void img_freq(unsigned char* y,int width,int height) { int count_Y[256] = { 0 }; double freq_Y[256] = { 0 }; for (int i = 0; i < width*height; i++) { count_Y[*(y + i)]++; } ofstream Y_sat; Y_sat.open("Y_sat.txt", ios::out, ios::trunc); if (!Y_sat) { cout << "Error opening Y_sat.txt" << endl; } else { Y_sat << "symbol\tfreq" << endl; for (int i = 0; i < 256; i++) { freq_Y[i] = count_Y[i] / (double)(width * height); Y_sat << i << "\t" << freq_Y[i] << endl; } } Y_sat.close(); } // 计算预测图像Y概率分布,输出至txt void predict_freq(int N_bits, int width, int height, unsigned char* ybuff) { double* freq = new double[pow(2, N_bits)]; for (int i = 0; i < pow(2, N_bits); i++) { *(freq + i) = 0; } for (int i = 0; i < width*height; i++) { int temp = (int)*(ybuff + i); *(freq + temp) = *(freq + temp) + 1; } // 写入txt ofstream Predict_sat; Predict_sat.open("Predict_sat.txt", ios::out, ios::trunc); if (!Predict_sat) { cout << "Error opening Predict_sat.txt" << endl; } else { Predict_sat << "symbol\tfreq" << endl; for (int i = 0; i < pow(2, N_bits); i++) { *(freq + i) = *(freq + i) / (double)(width * height); Predict_sat << i << "\t" << *(freq + i) << endl; } } Predict_sat.close(); if (freq!=NULL) { delete[]freq; } } // 映射至8bit void Map_To_8(int N_bits, int width,int height,unsigned char* ybuff) { double N = pow(2, N_bits); for (int i = 0; i < width* height; i++) { *(ybuff + i) =(unsigned char) (*(ybuff + i) * (255.0 / N) + (255 / (2 * N)+0.5)); } } 柠檬树上柠檬果 原创文章 9获赞 1访问量 581 关注 私信 展开阅读全文
作者:柠檬树上柠檬果



压缩 数据 数据压缩

需要 登录 后方可回复, 如果你还没有账号请 注册新账号