DPCM 压缩系统的实现和分析
生活随笔
收集整理的這篇文章主要介紹了
DPCM 压缩系统的实现和分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
DPCM基本原理
DPCM即查分預測編碼調制,將一個像素與上一個像素的差量化,得到預測誤差。
本實驗中采用右側減左側得到差值來預測,量化器采用8比特均勻量化。
編碼代碼
/* y_buffer:存儲y分量的指針 x_dim:圖像水平個數 y_dim:圖像垂直個數 y_new_out[k + 1]:上圖的yk' differ[k+1]:上圖的^ek */ for (int j = 0; j < y_dim; j++) {y = y_buffer + j * x_dim;y_new_out[j * x_dim] = *y;differ[j * x_dim] = 0;for (int i = 0; i < x_dim-1; i++){differ[j * x_dim + i + 1] = ((*(y + 1) - y_new_out[j * x_dim + i]) - (*(y + 1) - y_new_out[j * x_dim + i]) % 2) / 2;y_new_out[j * x_dim + i + 1] = y_new_out[j * x_dim + i] + differ[j * x_dim + i + 1];y++;}}for (int i = 0; i<size; i++)differ[i] = differ[i] + 128;圖像測試
原圖:
復原圖
差值圖:
原圖:
復原圖:
差值圖:
采用huffman編碼器進行編碼:
| Birds | 1,153KB | 1,099KB | 1.049 | 576KB | 191KB | 3.016 |
| Lena | 193KB | 184KB | 1.049 | 96KB | 48KB | 2.000 |
計算psnr判斷壓縮質量:
PSNR:峰值信噪比
MSE:均方誤差
PSNR越大,圖像失真越小,即壓縮質量越好
計算psnr的代碼:
void CountPSNR(unsigned char* oldBuf, unsigned char* newBuf, int n) {double mse;double psnr;double sum = 0;for (int i = 0; i < n; i++){sum = sum + (oldBuf[i] - newBuf[i]) * (oldBuf[i] - newBuf[i]);}mse = sum / n;psnr = 10 * log10(255 * 255 / mse);printf("psnr=%lf", psnr); }經過計算,Birds的psnr=33.500681
Lena的psnr=27.042175
由數據可知,圖像在經過DPCM前使用huffman編碼壓縮效果很差幾乎無法壓縮,經過DPCM編碼后數據更容易被壓縮,壓縮效率大幅提高;經過DPCM后恢復出的圖片壓縮質量較好。
for (int i = 0; i < x_dim-1; i++){differ[j * x_dim + i + 1] = ((*(y + 1) - y_new_out[j * x_dim + i]) - (*(y + 1) - y_new_out[j * x_dim + i]) % 4) / 4;//修改此處“% 2) / 2”中的兩個2y_new_out[j * x_dim + i + 1] = y_new_out[j * x_dim + i] + differ[j * x_dim + i + 1];y++;}通過修改上述代碼編碼代碼中的2為32、128、256可將8比特量化改為4、2、1比特量化。(將2改為(2^n)即為9-n比特量化)
完整代碼
rgb2yuv.h:
int RGB2YUV(int x_dim, int y_dim, void* bmp, void* y_out, void* u_out, void* v_out, int flip,unsigned char*y_new_out,unsigned char*differ_out);void InitLookupTable();#pragma oncergb2yuv.cpp:
#include "stdlib.h" #include "rgb2yuv.h" #include <math.h> #include <stdio.h> static float RGBYUV02990[256], RGBYUV05870[256], RGBYUV01140[256]; static float RGBYUV01684[256], RGBYUV03316[256]; static float RGBYUV04187[256], RGBYUV00813[256];int RGB2YUV(int x_dim, int y_dim, void* bmp, void* y_out, void* u_out, void* v_out, int flip,unsigned char* y_new_out,unsigned char* differ) {static int init_done = 0;long i, j, size;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;}// check to see if x_dim and y_dim are divisible by 2if ((x_dim % 2) || (y_dim % 2)) return 1;size = x_dim * y_dim;// allocate memoryy_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;// convert RGB to YUVif (!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;*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);*u = (unsigned char)128;*v = (unsigned char)128;b += 3;y++;u++;v++;}}}else {for (j = 0; j < y_dim; j++){for (i = 0; i < x_dim; i++){g = b + 1;r = b + 2;*y = (unsigned char)(RGBYUV02990[*r] + RGBYUV05870[*g] + RGBYUV01140[*b]);*u = (unsigned char)128;*v = (unsigned char)128; b += 3;y++;u++;v++;}}}for (int j = 0; j < y_dim; j++) {y = y_buffer + j * x_dim;y_new_out[j * x_dim] = *y;differ[j * x_dim] = 0;for (int i = 0; i < x_dim-1; i++){differ[j * x_dim + i + 1] = ((*(y + 1) - y_new_out[j * x_dim + i]) - (*(y + 1) - y_new_out[j * x_dim + i]) % 2) / 2;y_new_out[j * x_dim + i + 1] = y_new_out[j * x_dim + i] + differ[j * x_dim + i + 1];y++;}}for (int i = 0; i<size; i++)differ[i] = differ[i] + 128;// subsample UVfor (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; }main.cpp:
#include <stdio.h> #include <stdlib.h> #include <malloc.h> #include <windows.h> #include "rgb2yuv.h" #include"math.h" BITMAPFILEHEADER File_header; BITMAPINFOHEADER Info_header; #pragma warning(disable:4996) #define u_int8_t unsigned __int8 #define u_int unsigned __int32 #define u_int32_t unsigned __int32 #define FALSE false #define TRUE true/** rgb2yuv* required arg1 should be the input RAW RGB24 file* required arg2 should be the output RAW YUV12 file*/ int main() {/* variables controlable from command line */u_int frameWidth; /* --width=<uint> */u_int frameHeight; /* --height=<uint> */bool flip = FALSE; /* --flip */unsigned int i;void Write(const char* bmpflie, const char* yuvfile, u_int8_t * rgbBuf, u_int8_t * yBuf, u_int8_t * uBuf, u_int8_t * vBuf, u_int frameWidth, u_int frameHeight);void CountPSNR(unsigned char* oldBuf, unsigned char* newBuf, int n);/* internal variables */const char* bmpFileName = NULL;const char* yuvFileName1 = NULL;const char* yuvFileName2 = NULL;FILE* bmpFile = NULL;FILE* yuvFile1 = NULL;FILE* yuvFile2 = NULL;u_int8_t* rgbBuf = NULL;u_int8_t* yBuf = NULL;u_int8_t* yNewBuf = NULL;u_int8_t* differBuf = NULL;u_int8_t* uBuf = NULL;u_int8_t* vBuf = NULL;u_int32_t videoFramesWritten = 0;/* begin process command line *//* point to the specified file names */bmpFileName = "Birds.bmp";yuvFileName1 = "Birds_out.yuv";yuvFileName2 = "Birds_out_re.yuv";//yuvFileName = "Birds_outwhole.yuv";/* open the RGB file */bmpFile = fopen(bmpFileName, "rb");if (bmpFile == NULL){printf("cannot find bmp file\n");exit(1);}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);}if (fread(&Info_header, sizeof(BITMAPINFOHEADER), 1, bmpFile) != 1){printf("read info header error!");exit(0);}printf("The input bmp file is %s\n", bmpFileName);frameWidth = Info_header.biWidth;frameHeight = Info_header.biHeight;printf("width: %d , height: %d\n ", frameWidth, frameHeight);/* open the RAW file */yuvFile1 = fopen(yuvFileName1, "wb");yuvFile2 = fopen(yuvFileName2, "wb");if (yuvFile1 == NULL|| yuvFile2 == NULL){printf("cannot find yuv file\n");exit(1);}else{printf("The output yuv file is %s and %s\n", yuvFileName1, yuvFileName2);}/* get an input buffer for a frame */rgbBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3);/* get the output buffers for a frame */yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);yNewBuf = (u_int8_t*)malloc(frameWidth * frameHeight);differBuf = (u_int8_t*)malloc(frameWidth * frameHeight);uBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);vBuf = (u_int8_t*)malloc((frameWidth * frameHeight) / 4);if (rgbBuf == NULL || yBuf == NULL || uBuf == NULL || vBuf == NULL){printf("no enought memory\n");exit(1);}while (fread(rgbBuf, 1, frameWidth * frameHeight * 3, bmpFile)){if (RGB2YUV(frameWidth, frameHeight, rgbBuf, yBuf, uBuf, vBuf, flip,yNewBuf,differBuf)){printf("error");return 0;}fwrite(differBuf, 1, frameWidth * frameHeight, yuvFile1);fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile1);fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile1);fwrite(yNewBuf, 1, frameWidth * frameHeight, yuvFile2);fwrite(uBuf, 1, (frameWidth * frameHeight) / 4, yuvFile2);fwrite(vBuf, 1, (frameWidth * frameHeight) / 4, yuvFile2);}CountPSNR(yBuf, yNewBuf, frameWidth * frameHeight);/* cleanup */free(rgbBuf);free(yBuf);free(uBuf);free(vBuf);fclose(bmpFile);fclose(yuvFile1);fclose(yuvFile2);return(0); } void CountPSNR(unsigned char* oldBuf, unsigned char* newBuf, int n) {double mse;double psnr;double sum = 0;for (int i = 0; i < n; i++){sum = sum + (oldBuf[i] - newBuf[i]) * (oldBuf[i] - newBuf[i]);}mse = sum / n;psnr = 10 * log10(255 * 255 / mse);printf("psnr=%lf", psnr); }總結
以上是生活随笔為你收集整理的DPCM 压缩系统的实现和分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 编写彩色空间转换程序:YUVtoRGB
- 下一篇: JPEG原理分析及JPEG解码器的调试