二維離散餘弦變換(DCT)與二維離散反餘弦變換(IDCT)C語言實現

二維離散餘弦變換(DCT)與二維離散反餘弦變換(IDCT)C語言實現

實驗目標

對一個8x8的矩陣進行DCT和IDCT然後在觀察前者和後者的變化

實驗準備

理論基礎

二維離散餘弦變換

F(u,v)=c(u)c(v)i=0N1i=0N1f(i,j)cos[(i+0.5)πNu]cos[(i+0.5)πNv]F(u,v)=c(u)c(v)\sum_{i=0}^{N-1}\sum_{i=0}^{N-1}f(i,j)\cos{[\frac{(i+0.5)\pi}{N}u]}\cos{[\frac{(i+0.5)\pi}{N}v]}
c(u)={1N,u=02N,u0c(u)=\begin{cases}\sqrt{\frac{1}{N}}, & u=0 \\ \sqrt{\frac{2}{N}}, & u\neq0\end{cases}
二維離散反餘弦變換
f(i,j)=u=0N1v=0N1c(u)c(v)F(u,v)cos[(i+0.5)πNu]cos[(j+0.5)πNv]f(i,j)=\sum_{u=0}^{N-1}\sum_{v=0}^{N-1}c(u)c(v)F(u,v)\cos[\frac{(i+0.5)\pi}{N}u]\cos[\frac{(j+0.5)\pi}{N}v]
c(u)={1N,u=02N,u0c(u)=\begin{cases}\sqrt{\frac{1}{N}}, & u=0 \\ \sqrt{\frac{2}{N}}, & u\neq0\end{cases}

具體公式理解就不講了,高中知識就可以理解

實驗結果

YWN7m4.png
YWNH0J.png

實驗過程

/*
劍一
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);

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章