数据压缩原理 实验四 DPCM压缩系统的实现和分析

来源:互联网 发布:网络市场的主要功能有 编辑:程序博客网 时间:2024/06/08 10:25

实验原理

实验原理

DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器虚线框中所示。

在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。

在本次实验中,我们采用固定预测器和均匀量化器。预测器采用左侧、上方预测均可。量化器采用8bit均匀量化。本实验的目标是验证DPCM编码的编码效率。首先读取一个256级的灰度图像,采用自己设定的预测方法计算预测误差,并对预测误差进行8比特均匀量化(基本要求)。还可以对预测误差进行1比特、2比特和4比特的量化设计。

本实验我采用的是左侧预测,8比特均匀量化。

实验流程

先将BMP文件转换为YUV文件,提取Y数据,再对Y数据进行预测计算误差,然后对预测误差进行8bit均匀量化,再对量化后的预测误差进行反量化,求重建值。将误差图像和原图像传入上次实验的Huffman编码工程得到编码数据。

代码分析

main.cpp

#include<stdio.h>#include<stdlib.h>#include<malloc.h>#include<Windows.h>#include<math.h>#include"DPCM.h"#define u_int8_t    unsigned __int8#define u_int       unsigned __int32#define u_int32_t   unsigned __int32BITMAPFILEHEADER File_header;BITMAPINFOHEADER Info_header;int main(int argc, char** argv){       bool flip = FALSE;                  //BMP图像倒序存储数据 需要翻转    char* bmpFileName = NULL;           //输入    char* yuvFileName = NULL;           //输出    char* deviationFileName = NULL;     //误差    char* rebuildFileName = NULL;       //重建    FILE* bmpFile = NULL;    FILE* yuvFile = NULL;    FILE* deviationFile = NULL;    FILE* rebuildFile = NULL;    u_int8_t* rgbBuf = NULL;    u_int8_t* yBuf = NULL;    u_int8_t* uBuf = NULL;    u_int8_t* vBuf = NULL;    u_int8_t* deviationBuf = NULL;    u_int8_t* rebuildBuf = NULL;    u_int frameWidth, frameHeight;      //宽高    int i = 0, j = 0;    bmpFileName = argv[1];              //输入    yuvFileName = argv[2];              //输出    deviationFileName = argv[3];        //误差    rebuildFileName = argv[4];          //重建    /////read files/////    bmpFile = fopen(bmpFileName, "rb");    if (bmpFile == NULL)    {        printf("cannot find bmp file\n");        exit(1);    }    else    {        printf("The input bmp file is %s\n", bmpFileName);    }    yuvFile = fopen(yuvFileName, "wb");    if (yuvFile == NULL)    {        printf("cannot find yuv file\n");        exit(1);    }    else    {        printf("The output yuv file is %s\n", yuvFileName);    }    deviationFile = fopen(deviationFileName, "wb");    if (deviationFile == NULL)    {        printf("cannot find deviation file\n");        exit(1);    }    else    {        printf("The output deviation file is %s\n", deviationFileName);    }    rebuildFile = fopen(rebuildFileName, "wb");    if (rebuildFile == NULL)    {        printf("cannot find rebuild file\n");        exit(1);    }    else    {        printf("The output rebuild file is %s\n", rebuildFileName);    }    printf("\n");    /////read BMP fileheader & infoheader/////    if (fread(&File_header, sizeof(BITMAPFILEHEADER), 1, bmpFile) != 1)    {        printf("read file header error!");        exit(0);    }    if (File_header.bfType != 0x4D42)    {        printf("Not bmp file!");        exit(0);    }    else    {        printf("this is a bmp file.\n");    }    if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1)    {        printf("read info header error!");        exit(0);    }    printf("bitcount==%d\n", (unsigned char)Info_header.biBitCount);    /////end read header/////    frameWidth = Info_header.biWidth;               //宽高赋值    frameHeight = Info_header.biHeight;    /////开缓存区/////    rgbBuf = (u_int8_t *)malloc(sizeof(u_int8_t)*frameHeight*frameWidth * 3);    memset(rgbBuf, 0, frameHeight*frameWidth * 3);    yBuf = (u_int8_t*)malloc(sizeof(u_int8_t)*frameHeight*frameWidth);    uBuf = (u_int8_t*)malloc(sizeof(u_int8_t)*frameHeight*frameWidth / 4);    vBuf = (u_int8_t*)malloc(sizeof(u_int8_t)*frameHeight*frameWidth / 4);    deviationBuf = (u_int8_t*)malloc(sizeof(u_int8_t)*frameHeight*frameWidth);    rebuildBuf = (u_int8_t*)malloc(sizeof(u_int8_t)*frameHeight*frameWidth);    ReadRGB(rgbBuf, bmpFile, File_header, Info_header);    if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip))    {        printf("Color transferring failed");        return 0;    }    printf("framewidth==%d,frameheight==%d.\n", frameWidth, frameHeight);       //输出图像宽高    DO_DPCM(yBuf, deviationBuf, rebuildBuf,frameWidth,frameHeight);                 //进行DPCM编码    fwrite(yBuf, 1, frameWidth * frameHeight, yuvFile);                         //写输出文件    fwrite(deviationBuf, 1, frameHeight*frameWidth, deviationFile);    fwrite(rebuildBuf, 1, frameHeight*frameWidth, rebuildFile);    /////关缓存/////    if (rgbBuf != NULL)         free(rgbBuf);    if (yBuf != NULL)         free(yBuf);    if (uBuf != NULL)         free(uBuf);    if (vBuf != NULL)         free(vBuf);    if (deviationBuf != NULL)         free(deviationBuf);    if (rebuildBuf != NULL)         free(rebuildBuf);    /////关文件/////    if (bmpFile != NULL)         fclose(bmpFile);    if (yuvFile != NULL)         fclose(yuvFile);    if(deviationFile != NULL)         fclose(deviationFile);    if(rebuildFile != NULL)         fclose(rebuildFile);    system("pause");    return 0;}

DPCM.cpp

#include<Windows.h>#include<stdio.h>#include<math.h>#include"DPCM.h"static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256];static float RGBYUV01684[256], RGBYUV03316[256];static float RGBYUV04187[256], RGBYUV00813[256];bool MakePalette(FILE * pFile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h, RGBQUAD *pRGB_out){    /*若图像开始位置与INFOHEADER结束处位置,还有pow(2, info_h.biBitCount)个    结构体RGBQUAQ的空间(颜色数为2的biBitCount次方,调色板为数组),则说明    该bmp图像有调色板。*/    if ((file_h.bfOffBits - sizeof(BITMAPFILEHEADER) - info_h.biSize) == sizeof(RGBQUAD)*pow(2.0, info_h.biBitCount))    {        fseek(pFile, sizeof(BITMAPFILEHEADER) + info_h.biSize, 0);        fread(pRGB_out, sizeof(RGBQUAD), (unsigned int)pow(2.0, info_h.biBitCount), pFile);        return true;    }    else        return false;}void ReadRGB(unsigned char * rgbbuf, FILE *bmpfile, BITMAPFILEHEADER &file_h, BITMAPINFOHEADER & info_h){    u_int Width = 0, Height = 0;    long Loop = 0;    unsigned char *bmpbuf = NULL;    unsigned char *rgb = NULL;    unsigned char mask = 0;    int deltaw = 0;    rgb = rgbbuf;    if (((info_h.biWidth  * info_h.biBitCount / 8) % 4) == 0)        Width = info_h.biWidth*info_h.biBitCount / 8;    else        Width = (info_h.biWidth  * info_h.biBitCount + 31) / 32 * 4;    if ((info_h.biHeight % 2) == 0)        Height = info_h.biHeight;    else        Height = info_h.biHeight + 1;    deltaw = Width - info_h.biWidth * info_h.biBitCount / 8;    bmpbuf = (unsigned char *)malloc(sizeof(unsigned char)*Height*Width);    printf("word_width :%d , word_height: %d \n", Width, Height);    RGBQUAD *pRGB = (RGBQUAD *)malloc(sizeof(RGBQUAD) * (unsigned int)pow(2.0, (double)info_h.biBitCount));    if (!MakePalette(bmpfile, file_h, info_h, pRGB))    {        printf("No palette!\n");                        //没有调色板    }    fread(bmpbuf, 1, Height*Width, bmpfile);    if (info_h.biBitCount == 24)                        //24位bmp    {        for (Loop = 0; Loop<Height*Width; Loop++)        {            if (deltaw != 0)            {                if (deltaw == 1)                {                    if ((Loop + 1) % Width == 0)                        continue;                }                else if (deltaw == 2)                {                    if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0)                        continue;                }                else                {                    if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)                        continue;                }            }            *rgb = *(bmpbuf + Loop);            rgb++;        }    }    else if (info_h.biBitCount == 16)                   //16位bmp    {        for (Loop = 0; Loop < Height * Width; Loop += 2)        {            *rgb = (bmpbuf[Loop] & 0x1F) << 3;            *(rgb + 1) = ((bmpbuf[Loop] & 0xE0) >> 2) + ((bmpbuf[Loop + 1] & 0x03) << 6);            *(rgb + 2) = (bmpbuf[Loop + 1] & 0x7C) << 1;            rgb += 3;        }    }    else if (info_h.biBitCount == 32)                   //32位bmp    {        for (Loop = 0; Loop < info_h.biWidth*info_h.biHeight; Loop++)        {            *(rgb + 3 * Loop) = *(bmpbuf + 4 * Loop);            *(rgb + 3 * Loop + 1) = *(bmpbuf + 4 * Loop + 1);            *(rgb + 3 * Loop + 2) = *(bmpbuf + 4 * Loop + 2);        }    }    else                                                //其他位bmp    {        for (Loop = 0; Loop < Height*Width; Loop++)        {            if (deltaw != 0)            {                if (deltaw == 1)                {                    if ((Loop + 1) % Width == 0)                        continue;                }                else if (deltaw == 2)                {                    if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0)                        continue;                }                else                {                    if ((Loop + 1) % Width == 0 || (Loop + 2) % Width == 0 || (Loop + 3) % Width == 0)                        continue;                }            }            switch (info_h.biBitCount)                  //蒙版            {            case 1:                mask = 0x80;                            //10000000                break;            case 2:                mask = 0xC0;                            //11000000                break;            case 4:                mask = 0xF0;                            //11110000                break;            case 8:                mask = 0xFF;                            //11111111                break;            }            int shiftCnt = 1;            while (mask)            {                /*根据从数据中提取出的索引号index,以index为调色板数组下标去查询                数据中每info_h.biBitCount位所代表的颜色。                while 循环的次数:                1bit 图像 每字节循环8次                2bit 图像 每字节循环4次                4bit 图像 每字节循环2次                8bit 图像 每字节循环1次。                */                unsigned char index =                    mask == 0xFF ? bmpbuf[Loop] : ((bmpbuf[Loop] & mask) >> (8 - shiftCnt *info_h.biBitCount));                *rgb = pRGB[index].rgbBlue;                *(rgb + 1) = pRGB[index].rgbGreen;                *(rgb + 2) = pRGB[index].rgbRed;                if (info_h.biBitCount == 8) mask = 0;                else    mask >>= info_h.biBitCount;                rgb += 3;                shiftCnt++;            }        }    }    if (pRGB != NULL)         free(pRGB);    if (bmpbuf != NULL)        free(bmpbuf);}int RGB2YUV(int x_dim, int y_dim, void *bmp, void *y_out, void *u_out, void *v_out, int flip){    static int init_done = 0;    long i, j, size;    float yf, uf, vf;    unsigned char *r, *g, *b;    unsigned char *y, *u, *v;    unsigned char *pu1, *pu2, *pv1, *pv2, *psu, *psv;    unsigned char *y_buffer, *u_buffer, *v_buffer;    unsigned char *sub_u_buf, *sub_v_buf;    if (init_done == 0)    {        InitLookupTable();        init_done = 1;    }    if ((x_dim % 2) || (y_dim % 2)) return 1;    size = x_dim * y_dim;    y_buffer = (unsigned char *)y_out;    sub_u_buf = (unsigned char *)u_out;    sub_v_buf = (unsigned char *)v_out;    u_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));    v_buffer = (unsigned char *)malloc(size * sizeof(unsigned char));    if (!(u_buffer && v_buffer))    {        if (u_buffer) free(u_buffer);        if (v_buffer) free(v_buffer);        return 2;    }    b = (unsigned char *)bmp;    y = y_buffer;    u = u_buffer;    v = v_buffer;    /////RGB to YUV/////    if (!flip)     {        for (j = 0; j < y_dim; j++)        {            y = y_buffer + (y_dim - j - 1) * x_dim;            u = u_buffer + (y_dim - j - 1) * x_dim;            v = v_buffer + (y_dim - j - 1) * x_dim;            for (i = 0; i < x_dim; i++) {                g = b + 1;                r = b + 2;                yf = (RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);                uf = (-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);                vf = ((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);                *y = (unsigned char)(yf>16 ? (yf>235 ? 235 : (unsigned char)yf) : 16);                *u = (unsigned char)(uf>16 ? (uf>240 ? 240 : (unsigned char)uf) : 16);                *v = (unsigned char)(vf>16 ? (vf>240 ? 240 : (unsigned char)vf) : 16);                b += 3;                y++;                u++;                v++;            }        }    }    else     {        for (i = 0; i < size; i++)        {            g = b + 1;            r = b + 2;            *y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);            *u = (unsigned char)(-RGBYUV01684[*r] - RGBYUV03316[*g] + (*b) / 2 + 128);            *v = (unsigned char)((*r) / 2 - RGBYUV04187[*g] - RGBYUV00813[*b] + 128);            b += 3;            y++;            u++;            v++;        }    }    for (j = 0; j < y_dim / 2; j++)    {        psu = sub_u_buf + j * x_dim / 2;        psv = sub_v_buf + j * x_dim / 2;        pu1 = u_buffer + 2 * j * x_dim;        pu2 = u_buffer + (2 * j + 1) * x_dim;        pv1 = v_buffer + 2 * j * x_dim;        pv2 = v_buffer + (2 * j + 1) * x_dim;        for (i = 0; i < x_dim / 2; i++)        {            *psu = (*pu1 + *(pu1 + 1) + *pu2 + *(pu2 + 1)) / 4;            *psv = (*pv1 + *(pv1 + 1) + *pv2 + *(pv2 + 1)) / 4;            psu++;            psv++;            pu1 += 2;            pu2 += 2;            pv1 += 2;            pv2 += 2;        }    }    free(u_buffer);    free(v_buffer);    return 0;}void InitLookupTable(){    int i;    for (i = 0; i < 256; i++) RGBYUV02990[i] = (float)0.2990 * i;    for (i = 0; i < 256; i++) RGBYUV05870[i] = (float)0.5870 * i;    for (i = 0; i < 256; i++) RGBYUV01140[i] = (float)0.1140 * i;    for (i = 0; i < 256; i++) RGBYUV01684[i] = (float)0.1684 * i;    for (i = 0; i < 256; i++) RGBYUV03316[i] = (float)0.3316 * i;    for (i = 0; i < 256; i++) RGBYUV04187[i] = (float)0.4187 * i;    for (i = 0; i < 256; i++) RGBYUV00813[i] = (float)0.0813 * i;}void DO_DPCM(void * yBuf, void * deviationBuf, void *rebuildBuf, unsigned int width, unsigned int height){    unsigned char *ybuffer = NULL;    unsigned char *deviationbuffer = NULL;    unsigned char *rebuildbuffer = NULL;    int deviation = 0;    int i = 0, j = 0;    ybuffer = (unsigned char *)yBuf;                    //原始图像缓冲区    deviationbuffer = (unsigned char *)deviationBuf;    //误差图像缓冲区    rebuildbuffer = (unsigned char *)rebuildBuf;        //重建图像缓冲区    for (i = 0; i < height; i++)    {        for (j = 0; j < width; j++)        {            /*256级的灰度图像,预测值范围为[-255,255],            8bit量化则除以2,将预测值范围变为[-127,127],            再加128后可转到正常灰度显示            */            if (j == 0)                 //对第一个像素进行误差预测            {                deviation = (*ybuffer - 128)/2+128;                             //量化后的预测误差                *deviationbuffer = (unsigned char)deviation;                deviation = (*deviationbuffer - 128)*2+128;                     //反量化后的预测误差                *rebuildbuffer = (unsigned char)deviation;                ybuffer++;                deviationbuffer++;                rebuildbuffer++;            }            else                        //对其余像素进行误差预测            {                deviation = (*ybuffer - *(rebuildbuffer-1))/2+128;              //量化后的预测误差                *deviationbuffer = (unsigned char)deviation;                deviation = (*deviationbuffer - 128)*2 + *(rebuildbuffer - 1);  //反量化后的预测误差                *rebuildbuffer = (unsigned char)deviation;                ybuffer++;                deviationbuffer++;                rebuildbuffer++;            }        }    }}

实验结果与总结

实验图片进行预测误差和重建结果如下:

birds
birds误差
birds重建
birds图表
birds误差图表

相机男
相机男误差
相机男重建
相机男图表
相机男误差图表

小丑
小丑误差
小丑重建
小丑图表
小丑误差图表

水果
水果误差
水果重建
水果图表
水果误差图表

lena
lena误差
lena重建
lena图表
lena误差图表

噪声
噪声误差
噪声重建
噪声图表
噪声误差图表

欧弟
欧弟误差
欧弟重建
欧弟图表
欧弟误差图表

圆圈
圆圈误差
圆圈重建
圆圈图表
圆圈误差图表

由于量化误差是由[-127,127]上移128得到的,所以所得的误差数据会集中分布在128处。

将实验图片直接进行Huffman编码和进行DPCM后做Huffman编码的文件进行比较,结果如下:
数据分析

阅读全文
0 0
原创粉丝点击