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

来源:互联网 发布:我的老婆是警花知君txt 编辑:程序博客网 时间:2024/06/08 10:25

实验原理

这里写图片描述

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

DPCM是差分预测编码调制的缩写,是比较典型的预测编码系统。在DPCM系统中,需要注意的是预测器的输入是已经解码以后的样本。之所以不用原始样本来做预测,是因为在解码端无法得到原始样本,只能得到存在误差的样本。因此,在DPCM编码器中实际内嵌了一个解码器,如编码器中虚线框中所示。
在一个DPCM系统中,有两个因素需要设计:预测器和量化器。理想情况下,预测器和量化器应进行联合优化。实际中,采用一种次优的设计方法:分别进行线性预测器和量化器的优化设计。

代码分析

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++;            }        }    }}
原图像 预测误差图像 重建图像 原图像概率分布 预测误差图像概率分布

压缩性能比较:

文件名称 源文件大小(KB) huffman变换(KB) 压缩比 DPCM+huffman变换(KB) 压缩比 birds.bmp 384 304 1.26 148 2.59 lena.bmp 64 53 1.20 37 1.73 camman.bmp 64 50 1.28 34 1.88

  预测误差图像都为明显的灰色,电平集中分布在128附近,量化过程中将量化误差抬升128电平所以表明实际预测误差值集中分布在 0 左右,证明对于正常图像,相邻像素之间存在很强的关联性,利用相关性对像素量化后进行压缩压缩比会很理想。

原创粉丝点击