二維離散餘弦變換(DCT)與二維離散反餘弦變換(IDCT)C語言實現
實驗目標
對一個8x8的矩陣進行DCT和IDCT然後在觀察前者和後者的變化
實驗準備
理論基礎
二維離散餘弦變換
二維離散反餘弦變換
具體公式理解就不講了,高中知識就可以理解
實驗結果
實驗過程
/*
劍一
blog: www.leon7777.online
github:www.github.com/zpf996
emil: [email protected]
步驟:
1、向左位移127
2、編碼:DCT變換
3、除以量化矩陣
4、解碼:IDCT變換
5、向右位移127
*/
#include<stdio.h>
#include<math.h>
#define PI 3.1415926
//矩陣
int fre[8][8];
int temp[8][8];
float t[8][8];
//向左移位127
int move(int fre[8][8])
{
int i, j = 0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
temp[i][j] = fre[i][j] - 128;
}
}
pr(temp);
}
//向右移位127
int Imove(int fre[8][8])
{
int i, j = 0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
temp[i][j] = fre[i][j] + 128;
}
}
pr(temp);
}
//離散餘弦變換
float DCT(int f[8][8], int k, int l)
{
int i, j = 0;
float p1=0, p2=0;
float factor;
float sum = 0;
float data_dct;
if (k == 0)
{
if (l == 0)
{
factor = 1.0 / 8;
}
else
{
factor = sqrt(2.0) / 8;
}
}
else
{
if (l == 0)
{
factor = sqrt(2.0 )/ 8;
}
else
{
factor = 2.0 / 8;
}
}
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
p1 = cos(((2 * i + 1)*k*PI) / 16.0);
p2 = cos(((2 * j + 1)*l*PI) / 16.0);
sum = sum + f[i][j] * p1*p2;
}
}
data_dct = sum * factor;
return data_dct;
}
//四捨五入
int rounding(float a)
{
if (a >= 0)
{
return (int)(a + 0.5);
}
else
{
return (int)(a - 0.5);
}
}
//反離散餘弦變換
float IDCT(int f[8][8], int k, int l)
{
int u, v = 0;
float p1, p2;
float factor;
float sum = 0;
float data_dct;
for (u = 0; u < 8; u++)
{
for (v = 0; v < 8; v++)
{
if (u == 0)
{
if (v == 0)
{
factor = 1.0 / 8;
}
else
{
factor = sqrt(2.0) / 8;
}
}
else
{
if (v == 0)
{
factor = sqrt(2.0 )/ 8;
}
else
{
factor = 2.0 / 8;
}
}
p1 = ((2 * k + 1)*u*PI) / 16.0;
p2 = ((2 * l + 1)*v*PI) / 16.0;
sum = sum + factor *f[u][v] * cos(p1)*cos(p2);
}
}
data_dct = sum;
return data_dct;
}
//編碼
int coding(float fre[8][8])
{
int k, l = 0;
for (k = 0; k < 8; k++)
{
for (l = 0; l < 8; l++)
{
t[k][l] = DCT(fre, k, l);
printf(" %.2f", t[k][l]);
}
printf("\n");
}
}
//亮度化係數矩陣
int LQ(float f[8][8], int lq[8][8])
{
int i, j = 0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
temp[i][j] = rounding(f[i][j] / lq[i][j]);
}
}
pr(temp);
}
//亮度化恢復係數矩陣
int ILQ(int fre[8][8], int lq[8][8])
{
int i, j = 0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
temp[i][j] = fre[i][j] * lq[i][j];
}
}
pr(temp);
}
//解碼
int decoding(int f[8][8])
{
int k, l = 0;
for (k = 0; k < 8; k++)
{
for (l = 0; l < 8; l++)
{
fre[k][l] = rounding(IDCT(f, k, l));
}
}
pr(fre);
}
//輸出
int pr(int fre[8][8])
{
int i, j = 0;
for (i = 0; i < 8; i++)
{
for (j = 0; j < 8; j++)
{
printf(" %-8d", fre[i][j]);
}
printf("\n");
}
}
int main()
{
//亮度係數矩陣
int Lq[8][8] = { {16,11,10,16,24,40,51,61},
{12,12,14,19,26,58,60,55},
{14,13,16,24,40,57,69,56},
{14,17,22,29,51,87,80,62},
{18,22,37,56,68,109,103,77},
{24,35,55,64,81,104,113,92},
{49,64,78,87,103,121,120,101},
{72,92,95,98,112,100,103,99} };
//初試矩陣
int data[8][8] = { {52,55,61,66,70,61,64,73},
{63,59,55,90,109,85,69,72},
{62,59,68,113,144,104,66,73},
{63,58,71,122,154,106,70,69},
{67,61,68,104,126,88,68,70},
{79,65,60,70,77,68,58,75},
{85,71,64,59,55,61,65,83},
{87,79,69,68,65,76,78,94} };
printf("初始矩陣\n");
pr(data);
printf("減小絕對值波動,將數值向左移位127後的矩陣\n");
//減小絕對值波動,將數值向左移位128
move(data);
printf("編碼\n");
//編碼
coding(temp);
printf("除以亮度量化係數矩陣\n");
//除以亮度量化係數矩陣
LQ(t, Lq);
printf("亮度量化恢復係數矩陣\n");
//亮度量化恢復係數矩陣
ILQ(temp, Lq);
printf("解碼\n");
//解碼
decoding(temp);
printf("右移127\n");
//右移127
Imove(fre);
printf("初始矩陣\n");
pr(data);
}