使用C++实现DPCM编码(左向预测8bit、4bit、2bit、1bit和上向预测8bit)(更新过)
使用C++實現DPCM編碼(左向預測8bit、4bit、2bit、1bit和上向預測8bit)
- 一、DPCM是什么?
- 二、使用C++實現DPCM編碼(左向預測8bit、4bit、2bit、1bit和上向預測8bit)
- 1、實驗數據描述
- 2、左向預測8bit、4bit、2bit、1bit
- 1)左向預測8bit
- 2)左向預測4bit
- 3)左向預測2bit
- 4)左向預測1bit
- 5)左向預測8bit、4bit、2bit、1bit整體代碼
- 3、上向預測8bit
- 4、整體代碼
- 5、實驗結果分析
- 1)左向預測8bit、4bit、2bit、1bit結果對比
- 1)上向預測8bit與左向預測8bit對比
- 三、歸納總結
一、DPCM是什么?
DPCM–差分脈沖編碼調制(Differential Pulse code modulation,DPCM),是一種對模擬信號的編碼模式,與PCM不同每個抽樣值不是獨立的編碼,而是先根據前一個抽樣值計算出一個預測值,再取當前抽樣值和預測值之差作編碼用。此差值稱為預測誤差.抽樣值和預測值非常接近(因為相關性強),預測誤差的可能取值范圍比抽樣值變化范圍小。所以可用少幾位編碼比特來對預測誤差編碼,從而降低其比特率.這是利用減小冗余度的辦法,降低了編碼比特率。
? 根據某一模型利用以往的樣本值對新樣本進行預測,然后將樣本的實際值與其預測值相減得到一個誤差值,最后對這一誤差值進行編碼。
? 如果模型足夠好,且樣本序列在時間上相關性較強,則誤差信號的幅度將遠遠小于原始信號,從而得到較大的數據壓縮。
在DPCM系統中,需要注意的是預測器的輸入是已經解碼以后的樣本。之所以不用原始樣本來做預測,是因為在解碼端無法得到原始樣本,只能得到存在誤差的樣本。因此,在DPCM編碼器中實際內嵌了一個解碼器,如編碼器中虛線框中所示。
二、使用C++實現DPCM編碼(左向預測8bit、4bit、2bit、1bit和上向預測8bit)
1、實驗數據描述
此次用的是Lena.yuv,YUV灰度圖像,如下圖
因為所用圖片為灰度圖像,所以需要先把文件中所有值賦為128,以便將UV分量填滿。
//給Buf128全賦值為128for (int i = 0; i < frameWidth * frameHeight / 2; i++){Buf128[i] = 128;}2、左向預測8bit、4bit、2bit、1bit
1)左向預測8bit
因為是左向預測,所以圖片中每一行的第一個值無法預測,所以直接將預測值設為本身的值,插值設為0。
if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}若不是每一行的第一個值,那就需要先先計算插值a,將這個像素值減去左側像素的預測值。但是因為圖像是8bit(灰度值為0-255),所以如果相減值就會變為-255——+255因此如果想進行8bit量化,需要將插值a/2+127(更新插值d=a/2+127)(量化插值b=a/2)。之后需要進行反量化值c,將量化插值b乘2(c=b*2)。之后再將反量化值c與左側像素預測值相加得到本像素預測值
else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 2;//進行量化c = b * 2;//進行反量化d = b + 128;//進行+128yChazhiBuf[j + i * frameWidth] = d;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}2)左向預測4bit
4bit量化與8bit量化的區別在于需要將插值a(-255–+255)轉變為4bit插值d,所以需要將插值a/32+7(更新插值d=a/32+7)(量化插值b=a/32),。之后需要進行反量化值c,將插值a乘16(c=b*16)。之后再將反量化值c與左側像素預測值相加得到本像素預測值
if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 32;//進行量化c = b * 32;//進行反量化d = b + 7;//進行+7yChazhiBuf[j + i * frameWidth] = d*16;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}3)左向預測2bit
2bit量化與8bit量化的區別在于需要將插值a(-255–+255)轉變為2bit插值d,所以需要將插值a/128+2(更新插值d=a/128+2)(量化插值b=a/128),。之后需要進行反量化值c,將插值a乘128(c=b*128)。之后再將反量化值c與左側像素預測值相加得到本像素預測值
if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 128;//進行量化c = b * 128;//進行反量化d = b + 2;//進行+2yChazhiBuf[j + i * frameWidth] = d*64;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}4)左向預測1bit
1bit量化與8bit量化的區別在于需要將插值a(-255–+255)轉變為1bit插值d,所以需要將插值a/256+1(更新插值d=a/256+1)(量化插值b=a/256)。之后需要進行反量化值c,將插值a乘256(c=b*256)。之后再將反量化值c與左側像素預測值相加得到本像素預測值
if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 256;//進行量化c = b * 256;//進行反量化d = b + 1;//進行+1yChazhiBuf[j + i * frameWidth] = d*256;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}5)左向預測8bit、4bit、2bit、1bit整體代碼
//左向預測8bit、4bit、2bit、1bit-計算差值與預測值for (int i = 0; i < frameHeight; i++){for (int j = 0; j < frameWidth; j++){if (x == 8){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 2;//進行量化c = b * 2;//進行反量化d = b + 128;//進行+128yChazhiBuf[j + i * frameWidth] = d;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 4){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 16;//進行量化c = b * 16;//進行反量化d = b + 16;//進行+64yChazhiBuf[j + i * frameWidth] = d*8;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 2){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 64;//進行量化c = b * 64;//進行反量化d = b + 4;//進行+4yChazhiBuf[j + i * frameWidth] = d*32;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 1){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 128;//進行量化c = b * 128;//進行反量化d = b + 2;//進行+2yChazhiBuf[j + i * frameWidth] = d*64;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}}}3、上向預測8bit
因為是上向預測,所以圖片中每一列的第一個值無法預測,所以直接將預測值設為本身的值,插值設為0。
若不是每一列的第一個值,那就需要先先計算插值a,將這個像素值減去上側像素的預測值。但是因為圖像是8bit(灰度值為0-255),所以如果相減值就會變為-255——+255因此如果想進行8bit量化,需要將插值a/2+127(更新插值d=a/2+127)(量化插值b=a/2),。之后需要進行反量化值c,將量化插值b乘2(c=b*2)。之后再將反量化值c與上側像素預測值相加得到本像素預測值
4、整體代碼
#include "iostream" #include"stdio.h" #include <stdio.h> #include <stdlib.h> #include <malloc.h> #include"math.h" #pragma warning (disable:4996) using namespace std; #define u_int8_t unsigned __int8 #define u_int unsigned __int32int main(int argc, char** argv) {char* yuvFileName = NULL;char* yuceFileName = NULL;char* chazhiFileName = NULL;u_int8_t* yBuf = NULL;u_int8_t* yuvBuf = NULL;u_int8_t* yYuceBuf = NULL;u_int8_t* yChazhiBuf = NULL;u_int8_t* Buf128 = NULL;FILE* yuvFile = NULL;FILE* chazhiFile = NULL;FILE* yuceFile = NULL;u_int frameWidth = 0;u_int frameHeight = 0;int a = 0;//量化前插值int b = 0;//量化后值int c = 0;//反量化后值int d = 0;//+128之后值int x = 0;//選擇4bit,8bit量化//讀取數據yuv文件數據yuvFileName = argv[1];yuceFileName = argv[2];chazhiFileName = argv[3];frameWidth = atoi(argv[4]);frameHeight = atoi(argv[5]);yuvFile = fopen(yuvFileName, "rb");yuvBuf = (u_int8_t*)malloc(frameWidth * frameHeight * 3 / 2);yBuf = (u_int8_t*)malloc(frameWidth * frameHeight);yYuceBuf = (u_int8_t*)malloc(frameWidth * frameHeight);yChazhiBuf = (u_int8_t*)malloc(frameWidth * frameHeight);Buf128 = (u_int8_t*)malloc(frameWidth * frameHeight / 2);fread(yuvBuf, 1, frameWidth * frameHeight * 3 / 2, yuvFile);yuceFile = fopen(yuceFileName, "wb");chazhiFile = fopen(chazhiFileName, "wb");//給Buf128全賦值為128for (int i = 0; i < frameWidth * frameHeight / 2; i++){Buf128[i] = 128;}//讀取y數據for (int i = 0; i < frameWidth * frameHeight; i++){yBuf[i] = yuvBuf[i];}//選擇4bit,8bit量化,2bit量化,1bit量化while ((x != 4) && (x != 8) && (x != 2) && (x != 1) && (x != 99)){cout << "如想左向預測:選擇8bit量化或者4bit量化或者2bit量化或者1bit量化,請輸入“8”或“4”或“2”或“1”" << endl<< "如想上向預測請輸入“99”(8bit)" << endl;cin >> x;if (x == 8){cout << "您選擇了左向預測8bit量化";}else if (x == 4){cout << "您選擇了左向預測4bit量化";}else if (x == 2){cout << "您選擇了左向預測2bit量化";}else if (x == 1){cout << "您選擇了左向預測1bit量化";}if (x == 99){cout << "您選擇了上向預測";}else{cout << "您輸入有誤請重新輸入";}}//左向預測8bit、4bit、2bit、1bit-計算差值與預測值for (int i = 0; i < frameHeight; i++){for (int j = 0; j < frameWidth; j++){if (x == 8){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 2;//進行量化c = b * 2;//進行反量化d = b + 128;//進行+128yChazhiBuf[j + i * frameWidth] = d;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 4){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 16;//進行量化c = b * 16;//進行反量化d = b + 16;//進行+64yChazhiBuf[j + i * frameWidth] = d*8;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 2){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 64;//進行量化c = b * 64;//進行反量化d = b + 4;//進行+4yChazhiBuf[j + i * frameWidth] = d*32;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}if (x == 1){if (j == 0){yYuceBuf[j + i * frameWidth] = yBuf[j + i * frameWidth];yChazhiBuf[j + i * frameWidth] = 0;}else{a = yBuf[j + i * frameWidth] - yYuceBuf[j + i * frameWidth - 1];//計算插值b = a / 128;//進行量化c = b * 128;//進行反量化d = b + 2;//進行+2yChazhiBuf[j + i * frameWidth] = d*64;yYuceBuf[j + i * frameWidth] = yYuceBuf[j + i * frameWidth - 1] + c;}}}}//上預測for (int i = 0; i < frameWidth; i++){for (int j = 0; j < frameHeight; j++){if (x == 99){if (j == 0){yYuceBuf[i] = yBuf[i];yChazhiBuf[i] = 0;}else{a = yBuf[i + j * frameWidth] - yYuceBuf[i + (j - 1) * frameWidth];//計算插值b = a / 2;//進行量化c = b * 2;//進行反量化d = b + 128;//進行+128yChazhiBuf[i + j * frameWidth] = d;yYuceBuf[i + j * frameWidth] = yYuceBuf[i + (j - 1) * frameWidth] + c;}}}}fwrite(yYuceBuf, frameWidth * frameHeight, 1, yuceFile);fwrite(yChazhiBuf, frameWidth * frameHeight, 1, chazhiFile);fwrite(Buf128, frameWidth * frameHeight / 2, 1, chazhiFile);fwrite(Buf128, frameWidth * frameHeight / 2, 1, yuceFile);fclose(chazhiFile);fclose(yuceFile);fclose(yuvFile);free(yBuf);free(yuvBuf);free(yYuceBuf);free(yChazhiBuf);free(Buf128);return 0; }5、實驗結果分析
1)左向預測8bit、4bit、2bit、1bit結果對比
由圖像可知,量化bit數的減少會導致插值邊緣越來越不明顯,并且得到的恢復圖像與原始圖像的差距也越來越大,與預期相符
1)上向預測8bit與左向預測8bit對比
由圖可知,圈出的地方,上向預測是白,左向預測是黑,因為通過原圖可看出,在這個部分,下側像素比上側像素要白,也就是下側灰度值(down)大于上冊灰度值(up),所以up-down為正值因此為白;而這個部分的右側像素比左側像素黑,也就是右側像素值(right)小于左側像素值(left),所以right-left為負值因此為黑。這樣也就能分辨出上向預測與左向預測。
三、歸納總結
通過此次實驗進一步了解DPCM編碼,并完成了DPCM左向8bit、4bit、2bit、1bit以及上向8bit的代碼實現。同時,經過詳細分析左向預測8bit、4bit、2bit、1bit和上向預測8bit的實驗結果,明白了其之間的差異,并會通過結果區分左向預測與上向預測。并且熟悉鞏固了C++語言的使用,為后續進一步學習數據壓縮打下了基礎。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的使用C++实现DPCM编码(左向预测8bit、4bit、2bit、1bit和上向预测8bit)(更新过)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: u盘自己新建文件夹加密-(u盘自己新建文
- 下一篇: 实验5_JPEG解码