《C》C语言实现DCT算法

一、DCT的概念
1. DCT算法

DCT变换的全称是离散余弦变换 Discrete Cosine transform),离散余弦变换相当于一个长度大概是它两倍的离散傅里叶变换,这个离散傅里叶变换是对一个实偶函数进行的通过数字信号处理的学习我们知道实函数的傅立叶变换获得的频谱大多是复数,而偶函数的傅立叶变换结果是实函数。以此为基础,使信号函数成为偶函数,去掉频谱数的虚部,是余弦变换的特点之一。

2. DCT变换的形式:一维和二维

一维DCT变换是二维DCT变换的基础,一维DCT变换分为8种,其中第二种由于运算简单、适用范围广,所以经常使用第二种,公式如下:
F ( u ) = c ( u ) i = 0 N 1 f ( i ) c o s [ ( i + 0.5 ) π N u ] F(u)=c(u) \sum \limits_{i=0}^{N-1}f(i)cos[\frac{(i+0.5)π}{N}u]
c ( u ) = { 1 N , u=0 2 N , u!=0 c(u)=\begin{cases}\sqrt\frac{1}{N},& \text{u=0}\\\sqrt\frac{2}{N},& \text{u!=0} \end{cases}

二维DCT变换就是在一维的基础上再进行一次DCT变换,公式如下:
F ( u v ) = c ( u ) c ( v ) i = 0 N 1 j = 0 N 1 f ( i , j ) c o s [ ( i + 0.5 ) π N u ] c o s [ ( j + 0.5 ) π N v ] F(u,v)=c(u)c(v) \sum \limits_{i=0}^{N-1} \sum \limits_{j=0}^{N-1}f(i,j)cos[\frac{(i+0.5)π}{N}u]cos[\frac{(j+0.5)π}{N}v]
c ( u ) = { 1 N , u=0 2 N , u!=0 c(u)=\begin{cases}\sqrt\frac{1}{N},& \text{u=0}\\\sqrt\frac{2}{N},& \text{u!=0} \end{cases}​

二、C语言实现DCT

在使用DCT变换时,数据要能构成方阵,在实际应用中对不是方阵的数据都是先补齐再进行变换。

1. 参数及函数语句说明
参数、函数类型 参数意义
int DCT_SIZE 规定输入阵的维数
void TransMat() 求变换矩阵
void DCT() 设A为变换矩阵,I为输入矩阵,即完成AIA’的过程
2. 源程序【DCT.c】
#include "stdio.h"
#include<math.h>
#include <stdlib.h>

#define PI 3.1415926535
 
int MAT_SIZE;
 
float DCT_Mat[100][100]; //定于变换矩阵
float DctMap[100][100];  //输入矩阵,计算结束后为输出矩阵
float DctMapTmp[100][100];  //矩阵运算时用的中间矩阵

void TransMat()
{
    int i,j;
	float a;
	
    for(i=0;i<MAT_SIZE;i++)
    {
        for(j=0;j<MAT_SIZE;j++)
        {
			a = 0;
			if(i==0)
			{
				a=sqrt((float)1/MAT_SIZE);
			}
			else
			{
				a=sqrt((float)2/MAT_SIZE);
			}
			DCT_Mat[i][j]= a*cos((j+0.5)*PI*i/MAT_SIZE); //变换矩阵
        }
    }
}
 
void DCT()
{
    float t=0;
    int i,j,k;
    for(i=0;i<MAT_SIZE;i++)  //相当于A*I
	{
        for(j=0;j<MAT_SIZE;j++)
		{
            t=0;
            for(k=0;k<MAT_SIZE;k++)
			{
                t+=DCT_Mat[i][k]*DctMap[k][j]; //矩阵的乘法,DCT_Mat的第i行乘DctMap的第j列
			}
            DctMapTmp[i][j]=t;
        }
    }
    for(i=0;i<MAT_SIZE;i++)  //相当于(A*I)后再*A‘
	{
        for(j=0;j<MAT_SIZE;j++)
		{
            t=0;
            for(k=0;k<MAT_SIZE;k++)
			{
                t+=DctMapTmp[i][k]*DCT_Mat[j][k];
			}
            DctMap[i][j]=t;
        }
    }
}
 
int main(int argc, char *argv[])
{
	MAT_SIZE = atoi(argv[1]); //定义矩阵维度
	float k = 1;
	int count = 1;
	for(int i=0;i<MAT_SIZE;i++)   //产生输入数据
	{
		for(int j=0;j<MAT_SIZE;j++)
		{
			DctMap[i][j]=k + 50*cos(k*2*PI/40);
			k++;
		}
	}
    InitDctMat();
    DCT();
    for(int i=0;i<MAT_SIZE;i++)
    {
        for(int j=0;j<MAT_SIZE;j++)
        {
            printf("%d\t%f\n",count,DctMap[i][j]); //输出DCT变换结果
			count++;
        }
    }
}

输入信号: k + 50 × c o s ( k × 2 × π / 40 ) k+50 \times cos(k \times 2 \times π/40) ,其中 k [ 1 , M A T _ S I Z E 2 ] k \in [1,MAT\_SIZE^2]

  • 运行结果:
    1
3. 将DCT变换的结果,用gnuplot作图

作图指令:

set xlabel "N"
set ylabel "DCT"
plot [0:16] [-150:250] "<DCT 8" u 1:2 w l title "DCT 8X8"
  • 运行结果:
    2
五、计算结果验证
1. matlab实现DCT。源程序【DCT.mat】

输入信号: k + 50 × c o s ( k × 2 × π / 40 ) k+50 \times cos(k \times 2 \times π/40) ,其中 k [ 1 , M A T _ S I Z E 2 ] k \in [1,MAT\_SIZE^2]

I=zeros(8)   %定义I为4x4矩阵
k = 0;
for i=1:8
	for j=1:8
		k = k+1;
		I(i,j)=k + 50*cos(k*2*pi/40);   %产生数据序列
	end
end
D=dct2(I)   %对I进行DCT变换
D=D'    %D进行转置
D=D(:)  %将D转成1x16的矩阵
plot(1:64,D)  %作图
title('DCT 8X8')
xlabel('N')
ylabel('DCT')
  • 运行结果:
    3
2. 波形图对比
  • c语言画图结果:
    1
  • matlab画图结果:
    在这里插入图片描述
    对比两图结果一致。

猜你喜欢

转载自blog.csdn.net/yga_airspace/article/details/86688327