DPCM实验

DPCM原理

  1. DPCM系统框图

 

  1. DPCM难点分析

    DPCM设计的总体目标为在给定的码率下,使失真尽量小。由DPCM的系统框图可以知道,设计过程中需要主要关注量化器的设计以及预测器的设计,但由于编码器本身的反馈机制,使得量化器和预测器的输出互为对方的输入,难以进一步分析设计,也成为DPCM算法设计的一大难点。

  2. 量化器与预测器的分离

    当量化器采用高码率的均匀量化时,量化误差小,而样本的重建值与样本的真值之间的差值小。因此,在高码率均匀量化的前提下,可以将上一个样本的真值作为当前样本的预测值,此时预测器的输入不再依赖于量化器的输出,量化器的输入也不再依赖于预测器的输出,从而实现量化器与预测器的分离。

    分离量化器与预测器之后,只需要将其设计为各自最优状态即可实现DPCM编码系统的整体最优。

DPCM代码实现

本次实验中选择的规则如下:

量化:均匀量化

预测:左向预测,并将上一个样本的重建值作为当前样本的预测值

重建:将当前样本反量化后的预测误差与当前样本预测值之和作为当前样本的重建值

DPCM具体实现

void DPCM(unsigned char* y_buffer, unsigned char* y_Pred, unsigned char* y_Re, int N, int w, int h)
{
    //预测误差
    char* pred_error;
    pred_error = (char*)malloc(sizeof(char) * (w * h));
    //量化区间数
    double Q_num = pow(2, N);
    //量化间隔,此处采用均匀量化
    double step = pow(2, (double)(9 - N));
​
    //预测与量化过程;
    //预测机制:采用左向预测,当前样本的预测值为上一个样本的重建值
    //重构:样本的重构值等于反量化后预测误差与样本预测值之和
    for (int i = 0; i < h; i++) {
        for (int j = 0; j < w; j++) {
            if (j == 0)
            {
                //第一列的预测特殊处理,以128作为预测值进行预测
                pred_error[i * w + j] = (char)(y_buffer[i * w + j] - 128); //需要做类型转换以免溢出
                y_Pred[i * w + j] = (unsigned char)((pred_error[i * w + j] + 255) / step);
​
                if (y_Pred[i * w + j] > Q_num - 1)
                    y_Pred[i * w + j] = (unsigned char)(Q_num - 1);
                else if (y_Pred[i * w + j] < 0)
                    y_Pred[i * w + j] = 0;
​
                y_Re[i * w + j] = (y_Pred[i * w + j] * step - 255) +128;
            }
            else 
            {
                //非第一列
                pred_error[i * w + j] = (char)(y_buffer[i * w + j] - y_Re[i * w + j - 1]);
                y_Pred[i * w + j] = (unsigned char)((pred_error[i * w + j] + 255) / step);
​
                if (y_Pred[i * w + j] > Q_num - 1)
                    y_Pred[i * w + j] = (unsigned char)(Q_num - 1);
                else if (y_Pred[i * w + j] < 0) 
                    y_Pred[i * w + j] = 0;
​
                y_Re[i * w + j] = (y_Pred[i * w + j] * step - 255) + y_Re[i * w + j - 1];
                
                if (y_Re[i * w + j] > 255) 
                    y_Re[i * w + j] = 255;
                else if (y_Re[i * w + j] < 0) 
                    y_Re[i * w + j] = 0;
​
            }
        }
    }
}

main

int main(int argc, char* argv[]) 
{
    int w = 256; //图像宽
    int h = 256; //图像高
    int N = 8; //量化比特数
    //文件读入
    FILE* FileOpen = fopen("文件路径", "rb");
    if (FileOpen == NULL) {
        printf("open file fail!");
    }
    //打开预测输出文件
    FILE* PredictedFile = fopen("文件路径", "wb");
    if (PredictedFile  == NULL)
    {
        printf("open PredictedFile fail!");
    }
​
    //打开重建输出文件
    FILE* RebuildFile = fopen("文件路径", "wb");
    if (RebuildFile  == NULL)
    {
        printf("open RebuildFile fail!");
    }
​
    //建立缓冲区
    unsigned char* y_buffer, * u_buffer, * v_buffer, * y_Pred, * y_Re;
    y_buffer = (unsigned char*)malloc(sizeof(char) * (w * h));
    y_Pred = (unsigned char*)malloc(sizeof(char) * (w * h));
    y_Re = (unsigned char*)malloc(sizeof(char) * (w * h));
    u_buffer = (unsigned char*)malloc(sizeof(char) * (w * h) / 4);
    v_buffer = (unsigned char*)malloc(sizeof(char) * (w * h) / 4);
​
    //读取yuv数据到缓冲区中
    fread(y_buffer, 1, w * h, FileOpen);
    fread(u_buffer, 1, w * h / 4, FileOpen);
    fread(v_buffer, 1, w * h / 4, FileOpen);
​
    //DPCM
    DPCM(y_buffer, y_Pred, y_Re, N, w, h);
​
    //计算PSNR
    int max = 255;
    double mse = 0;
    for (int i = 0; i < h; i++)
        for (int j = 0; j < w; j++)
        {
            mse += (y_buffer[i * w + j] - y_Re[i * w + j]) * (y_buffer[i * w + j] - y_Re[i * w + j]);
        }
    mse = (double)mse / (double)(w * h);
    double psnr = 10 * log10((double)(max * max) / mse);
    printf("PSNR = %f\n", psnr);
​
    //写入预测误差图像
    fwrite(y_Pred, 1, w * h, PredictedFile);
    fwrite(u_buffer, 1, w * h / 4, PredictedFile);
    fwrite(v_buffer, 1, w * h / 4, PredictedFile);
​
​
    //写入重建图像
    fwrite(y_Re, 1, w * h, RebuildFile);
    fwrite(u_buffer, 1, w * h / 4, RebuildFile);
    fwrite(v_buffer, 1, w * h / 4, RebuildFile);
​
    fclose(FileOpen);
    fclose(PredictedFile);
    fclose(RebuildFile);
    free(y_buffer);
    free(u_buffer);
    free(v_buffer);
    free(y_Pred);
    free(y_Re);
    return 0;
}

实验结果

量化比特数原图像预测误差图像重建图像PSNR(dB)
8bit51.133820
4bit14.81887
2bit7.649990

 

熵编码 vs DPCM+熵编码

计算概率分布并写入文件

   void Frequence(FILE* file, unsigned char* buffer, int w, int h) {
	double fre[256] = { 0 };
	for (int i = 0; i < 256; i++)
	{
		for (int j = 0; j < w * h; j++)
		{
			if (buffer[j] == i)
				fre[i]++;
		}
		fre[i] = fre[i] / (w * h);
		fprintf(file, "%lf\n", fre[i]);
	}
} 

    FILE* y_Freq = fopen("文件路径", "wb");
	if (y_Freq == NULL) {
		printf("file open fail!\n");
	}
    Frequence(y_Freq, y_buffer, w, h);
	FILE* y_Pre_Freq = fopen("文件路径", "wb");
	if (y_Pre_Freq == NULL) {
		printf("file open fail!\n");
	}
	
	Frequence(y_Pre_Freq, y_Pred, w, h);

使用Visual Studio对huffman.bat进行编辑

huff_run.exe -i Lena256B.yuv -o lena.huff -c -t lena.txt
huff_run.exe -i PredictedFile.yuv -o PredictedFile.huff -c -t PredictedFile.txt

结果对比

原始图像8bit量化后的预测误差图像
编码前文件大小96KB96KB
编码后文件大小69KB45KB
压缩比139.13%213.33%
重建图像PSNR~51.133820
分布概率图

         可以看到,与直接对未经处理的图像进行熵编码相比,对8bit量化后的预测误差图像进行熵编码的压缩比更大,可以得出结论,从压缩数据角度而言,DPCM+熵编码的系统更优。

        在选用8bit量化时,重建图像的PSNR在50以上,就人眼观察而言与原图相差并不大,在选用足够比特的量化情况下,DPCM+熵编码可以实现对于人眼而言“无失真”的,压缩比更高的数据压缩。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值