天天看點

DPCM編碼進行圖像壓縮

一、實驗要求

本實驗的目标是驗證DPCM編碼的編碼效率。首先讀取一個256級的灰階圖像,采用自己設定的預測方法計算預測誤差(本次實驗報告使用左向預測),并對預測誤差進行8比特均勻量化(基本要求)。還可對預測誤差進行1比特、2比特和4比特的量化設計(提高要求)。

在DPCM編碼器實作的過程中可同時輸出預測誤差圖像和重建圖像。将預測誤差圖像寫入檔案并将該檔案輸入Huffman編碼器,得到輸出碼流、給出機率分布圖并計算壓縮比。将原始圖像檔案輸入Huffman編碼器,得到輸出碼流、給出機率分布圖并計算壓縮比。最後比較兩種系統(1.DPCM+熵編碼和2.僅進行熵編碼)之間的編碼效率(壓縮比和圖像品質)。壓縮品質以PSNR進行計算。

二、實驗原理

DPCM編碼進行圖像壓縮

三、關鍵代碼

void DpcmEn(unsigned char* yBuff, unsigned char* preerr, unsigned char* level, int h, int w, int q){
    int prediction;
    int err;
    int i;
    int j;
    int a;
    int b;
    for (i = 0; i < h; i++){
        prediction = 128;
        err = yBuff[i*w] - prediction;
        a = (err + 128)/pow(2, 8 - q);
        if(a > pow(2, q) - 1){
            a = pow(2, q) - 1;
        }
        if(a < 0){
            a = 0;
        }
        preerr[i*w] = a;
        b = preerr[i*w]*pow(2, 8 - q) - 128 + prediction;
        if(b > 255){
            b = 255;
        }
        if(b < 0){
            b = 0;
        }
        level[i*w] = b;
        for (j = 1; j < w; j++){
            prediction = level[i*w + j - 1];
            err = yBuff[i*w + j] - prediction;
            a = (err + 255)/pow(2, 9 - q);
            if(a > pow(2, q) - 1){
                a = pow(2, q) - 1;
            }
            if(a < 0){
                a = 0;
            }
            preerr[i*w + j] = a;
            b = preerr[i*w + j]*pow(2, 9 - q) - 255 + prediction;
            if(b > 255){
                b = 255;
            }
            if(b < 0){
                b = 0;
            }
            level[i*w + j] = b;
        }
    }
}
           

計算PSNR

void PrintPSNR(unsigned char* ybuffer, unsigned char* levelbuffer, int w, int h) {
 double mse;
 double psnr;
    double sum = 0;
 double temp;
 int i;
 for (i = 0; i < w*h; i++) {
  temp = pow((ybuffer[i] - levelbuffer[i]), 2);
  sum += temp;
 }
 mse = sum/(w * h);
 psnr = 10*log10((pow(2,8)-1)*(pow(2,8)-1)/mse);
 cout<<"the psnr is: "<<psnr<<endl;
}
           

8bit量化原始圖檔、輸出出來的重建圖檔以及預測內插補點圖檔

DPCM編碼進行圖像壓縮

調用了Huffman編碼進行壓縮的圖像檔案:

DPCM編碼進行圖像壓縮

原圖大小為96kb,運用了Huffman編碼後壓縮後圖像大小為72.2KB,再将轉化過的圖像檔案用Huffman碼編碼,壓縮後檔案大小如下:

DPCM編碼進行圖像壓縮

四、完整代碼

main函數

#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
#include"DCPM.h"
using namespace std;
int main(int argc, char* argv[]){
    char* yuvaddr = argv[1];
    char* yuv2addr = argv[2];
    int W = atoi(argv[3]);
    int H = atoi(argv[4]);
    char* yuverraddr = argv[5];
    int imgsize = W*H*3/2;
    int q = atoi(argv[6]);
    unsigned char* yuvbuffer = new unsigned char[imgsize];
    unsigned char* ybuffer = new unsigned char[imgsize*2/3];
    unsigned char* ubuffer = new unsigned char[imgsize/6];
    unsigned char* vbuffer = new unsigned char[imgsize/6];
    unsigned char* preerrbuffer = new unsigned char[imgsize*2/3];
    unsigned char* levelbuffer = new unsigned char[imgsize*2/3];
    FILE* imgopen = fopen(yuvaddr,"rb");
    if(imgopen == NULL){
        cout<<"打開yuv檔案失敗"<<endl;
    }
    FILE* yuvsave = fopen(yuv2addr,"w");
    if(yuvsave == NULL){
        cout<<"建立yuv空白檔案失敗"<<endl;
    }
    FILE* yuvsave2 = fopen(yuverraddr,"w");
    if(yuvsave2 == NULL){
        cout<<"建立yuv空白檔案失敗"<<endl;
    }
    fread(yuvbuffer, sizeof(unsigned char), imgsize, imgopen);
    int i;
    for(i = 0; i < imgsize*2/3; i++){
        ybuffer[i] = yuvbuffer[i];
    }
    for(i = 0; i < imgsize/6; i++){
        ubuffer[i] = yuvbuffer[i+imgsize*2/3];
    }
    for(i = 0; i < imgsize/6; i++){
        vbuffer[i] = yuvbuffer[i+imgsize*2/3+imgsize/6];
    }
    DpcmEn(ybuffer, preerrbuffer, levelbuffer, H, W, q);
    fwrite(levelbuffer, sizeof(unsigned char), W*H, yuvsave);
    fwrite(ubuffer, sizeof(unsigned char), W*H/4, yuvsave);
    fwrite(vbuffer, sizeof(unsigned char), W*H/4, yuvsave);
    for(i = 0; i < imgsize/6; i++){
        ubuffer[i] = 128;
    }
    for(i = 0; i < imgsize/6; i++){
        ubuffer[i] = 128;
    }
    fwrite(preerrbuffer, sizeof(unsigned char), W*H, yuvsave2);
    fwrite(ubuffer, sizeof(unsigned char), W*H/4, yuvsave2);
    fwrite(vbuffer, sizeof(unsigned char), W*H/4, yuvsave2);
    PrintPSNR(ybuffer, levelbuffer, W, H);
}
           

DPCM.h

#ifndef DCPM_H_INCLUDED
#define DCPM_H_INCLUDED
#include"iostream"
#include"math.h"
#include"stdio.h"
#include"malloc.h"
using namespace std;
void DpcmEn(unsigned char* yBuff, unsigned char* preerr, unsigned char* level, int h, int w, int q){
    int prediction;
    int err;
    int i;
    int j;
    int a;
    int b;
    for (i = 0; i < h; i++){
        prediction = 128;
        err = yBuff[i*w] - prediction;
        a = (err + 128)/pow(2, 8 - q);
        if(a > pow(2, q) - 1){
            a = pow(2, q) - 1;
        }
        if(a < 0){
            a = 0;
        }
        preerr[i*w] = a;
        b = preerr[i*w]*pow(2, 8 - q) - 128 + prediction;
        if(b > 255){
            b = 255;
        }
        if(b < 0){
            b = 0;
        }
        level[i*w] = b;
        for (j = 1; j < w; j++){
            prediction = level[i*w + j - 1];
            err = yBuff[i*w + j] - prediction;
            a = (err + 255)/pow(2, 9 - q);
            if(a > pow(2, q) - 1){
                a = pow(2, q) - 1;
            }
            if(a < 0){
                a = 0;
            }
            preerr[i*w + j] = a;
            b = preerr[i*w + j]*pow(2, 9 - q) - 255 + prediction;
            if(b > 255){
                b = 255;
            }
            if(b < 0){
                b = 0;
            }
            level[i*w + j] = b;
        }
    }
}
void PrintPSNR(unsigned char* ybuffer, unsigned char* levelbuffer, int w, int h) {
 double mse;
 double psnr;
    double sum = 0;
 double temp;
 int i;
 for (i = 0; i < w*h; i++) {
  temp = pow((ybuffer[i] - levelbuffer[i]), 2);
  sum += temp;
 }
 mse = sum/(w * h);
 psnr = 10*log10((pow(2,8)-1)*(pow(2,8)-1)/mse);
 cout<<"the psnr is: "<<psnr<<endl;
}
           

繼續閱讀