DPCM编码进行图像压缩
程序员文章站
2022-07-14 19:06:12
...
DPCM的编解码原理如下:
编码思路:
主程序代码:main.cpp
#include "pch.h"
#include <iostream>
#include<math.h>
#include<malloc.h>
using namespace std;
const int w = 500;
const int h = 500;
const int depth = 5;
const int N = w * h;
int main(int argc, char *argv[])
{
FILE* yuvFile = NULL;
FILE* reFile = NULL;
FILE* peFile = NULL;
errno_t err;
err = fopen_s(&yuvFile, "seed.yuv", "rb");
if (err != 0)
{
printf("cannot open yuv file\n");
}
errno_t err1;
err1 = fopen_s(&reFile, "re.yuv", "wb");
if (err1 != 0)
{
printf("cannot open refile\n");
}
errno_t err2;
err2 = fopen_s(&peFile, "pe.yuv", "wb");
if (err2 != 0)
{
printf("cannot open prediction error file\n");
}
unsigned char* yBuf = (unsigned char*)malloc(sizeof(unsigned char) * N);
unsigned char* uBuf = (unsigned char*)malloc(sizeof(unsigned char) * N );
unsigned char* vBuf = (unsigned char*)malloc(sizeof(unsigned char) * N );
unsigned char* reBuf = (unsigned char*)malloc(sizeof(unsigned char) * N);//重建图像
unsigned char* peBuf = (unsigned char*)malloc(sizeof(unsigned char) * N);//预测误差 prediction error
fread(yBuf, sizeof(unsigned char), N, yuvFile);
fread(uBuf, sizeof(unsigned char), N , yuvFile);
fread(vBuf, sizeof(unsigned char), N , yuvFile);
dpcm(h, w, yBuf, depth, reBuf, peBuf);
fwrite(reBuf, sizeof(unsigned char), N, reFile);
fwrite(uBuf, sizeof(unsigned char), N , reFile);
fwrite(vBuf, sizeof(unsigned char), N , reFile);
fwrite(peBuf, sizeof(unsigned char), N, peFile);
fwrite(uBuf, sizeof(unsigned char), N, peFile);
fwrite(vBuf, sizeof(unsigned char), N, peFile);
fclose(yuvFile);
fclose(reFile);
free(yBuf);
free(vBuf);
free(uBuf);
free(reBuf);
free(peBuf);
}
DPCM编码代码:DPCM.cpp
void dpcm(int h,int w,unsigned char *Y_Buf,int depth,unsigned char *reBuf,unsigned char *preErr)
{
int prediction,err,inerr;//预测值和差值
int extend;
for (int i = 0; i < h; i++){
for (int j = 0; j < w; j++){
if (j == 0) {
prediction = 128;
err = Y_Buf[i*w] - prediction;
extend = (err + 128) / pow(2, 8 - depth);
preErr[i*w + j] = extend;
if (preErr[i*w + j] < 0) {
preErr[i*w + j] = 0;
}
else if (preErr[i*w + j] > pow(2, depth) - 1) {
preErr[i*w + j] = pow(2, depth) - 1;
}
inerr = preErr[i*w] * pow(2, 8 - depth);
reBuf[i*w + j] = inerr;
if (reBuf[i*w + j] < 0) {
reBuf[i*w + j] = 0;
}
else if (reBuf[i*w + j] > 255) {
reBuf[i*w + j] = 255;
}
}
else {
prediction = reBuf[i*w + j - 1];
err = Y_Buf[i*w + j] - prediction;
extend = (err + 255) / pow(2, 9 - depth);//拓展为8bit量化
preErr[i*w + j] = extend;
if (preErr[i*w + j] < 0) {
preErr[i*w+j] = 0;
}
else if (preErr[i*w + j] > pow(2, depth) - 1) {
preErr[i*w+j] = pow(2, depth) - 1;
}
inerr = preErr[i*w + j] * pow(2, 9 - depth) - 255 + prediction;
reBuf[i*w + j] = inerr;
if (reBuf[i*w + j] < 0) {
reBuf[i*w+j] = 0;
}
else if (reBuf[i*w + j] > 255) {
reBuf[i*w+j] = 255;
}
}
}
}
}
计算PSNR
void psnr(int w,int h,unsigned char *Y_Buf,unsigned char *reBuf,int depth) //计算图像的压缩质量
{
FILE* psnrtxt;
fopen_s(&psnrtxt, "psnr.txt", "ab");
double psnr = 0;
double mse = 0;
for (int i = 0; i < w*h; i++) {
mse += pow((Y_Buf[i] - reBuf[i]), 2);
}
mse = mse / (w * h);
psnr = 10 * log10(255 * 255 / mse);
fprintf(psnrtxt,"Bit=%d,psnr=%lf\n", depth,psnr);//写入文件
}
本次选用了两张图来看结果。
一张为56*256的4:2:0的yuv文件
由此可见,量化系数越大,图像质量越佳。
量化系数 | PSNR |
---|---|
8bit | 30.035363 |
7bit | 30.201576 |
6bit | 29.375232 |
5bit | 26.893395 |
4bit | 19.217079 |
3bit | 11.516803 |
2bit | 8.467440 |
1bit | 9.448466 |
在1bit时psnr会突然上涨。
下面的是436*538的4:4:4的yuv文件,下面是1-8bit量化的结果
同样可以从图中看出量化系数越大,图片质量越好。
量化系数 | PSNR |
---|---|
8bit | 5.478266 |
7bit | 3.519651 |
6bit | 2.757276 |
5bit | 2.505715 |
4bit | 2.575068 |
3bit | 2.973797 |
2bit | 4.045500 |
1bit | 7.024183 |
由于使用的图黑色占了大部分占比,所以最后1bit量化时出现了明显误差。