DPCM编码

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)压缩比概率分布图
原文件731100%
1bit91.412.50%
2bit10914.91%
4bit11215.32%
8bit14920.38%
原文件仅Huffman编码21829.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;
}
​
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值