C++二维DCT的简单代码实现

       学习视频编码理论知识的进度太慢,目前才看到变换编码这一块,对DCT的内容进行了简单的了解,根据我的理解,DCT在视频编码中的作用应该是:对预测后的残差进行DCT变换,使得空间域相对分散的能量在变换域变的相对集中,来进一步减少空间冗余。 我就按照H.265/HEVC原理标准与实现(万帅、杨付正)这本书中的第145页的公式来写一段代码帮助自己加深理解,截图如下:

        一开始我使用指针的方法去实现,出现了一个错误,在调试的时候发现无法在调试窗口观察到多级指针内部的值,于是改用vector容器的方法来实现,最终检查到了错误,使用容器的有点就是:减少代码量,方便调试,减少了内存泄漏的问题,增加了可读性。下面我把两种实现的方法都放上来,欢迎指正。

        两个程序的作用完全一样,都是将一个二维数组经过DCT变换并输出。并且代码很简单,耐心看下去即可。

1.用vector容器来实现:

#include<stdlib.h>
#include<iostream>
#include<math.h>
#include<vector>
#define PI acos(-1)//定义圆周率
using namespace std;

void DCT(vector<vector<float>>& ori, vector<vector<float>>& dct, float N);

int main(void)
{
	const int N = 4;//二维数组的阶数
	float start[N][N] = { 12,27,3,4,55,6,7,28,9,10,11,12,123,14,65,16 };//二维数组的初始值,可以自己任意设置
	vector<vector<float>> oriMatrix;//原始的二维数组,用容器的方法来定义,方便调试
	vector<vector<float>> dctMatrix;//用来存储经过DCT变换后的二维数组
	vector<float> temp;//temp仅仅是为了用来填充oriMatrix
	//填充oriMatrix
	for (int i = 0; i < N; i++)
	{
		temp.push_back(0);
	}
	for (int i = 0; i < N; i++)
	{
		oriMatrix.push_back(temp);
	}
	dctMatrix = oriMatrix;//初始化dctMatrix
	//初始化oriMatrix
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			oriMatrix[i][j] = start[i][j];
		}
	}
	//输出oriMatrix
	cout << "原始二维数组矩阵:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%-10.4f", oriMatrix[i][j]);//每个输出占10个字符,左对齐,保留4位小数
		}
		cout << endl;
	}
	cout << endl;
	DCT(oriMatrix, dctMatrix, N);//调用自己定义的函数
	//输出dctMatrix
	cout << "经过DCT变换后的二维数组矩阵:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%-10.4f", dctMatrix[i][j]);
		}
		cout << endl;
	}
	
	return 0;
}
//注意下面这个自定义的函数的第三个参数必须要是float型,否则会出错(自己换成int型试一下就知道了)
void DCT(vector<vector<float>>& ori, vector<vector<float>>& dct, float N)//第一个形参是原始二维数组的引用,第二个形参矩阵是经过DCT变换的二维数组的引用,第三个形参是阶数
{
	//计算dct[0][0]的值
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			dct[0][0] += (1 / N) * ori[m][n];
		}
	}
	//计算dct[0][1]
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			dct[0][1] += (sqrt(2) / N) * (ori[m][n]) * cos((2 * n + 1) * PI / (2 * N));
		}
	}
	//计算dct[1][0]
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			dct[1][0] += (sqrt(2) / N) * (ori[m][n]) * cos((2 * m + 1) * PI / (2 * N));
		}
	}
	//从dct[1][1]一直计算到dct[N-1][N-1],根据公式来看,需要四个for循环
	for (int k = 1; k < N; k++)
	{
		for (int l = 1; l < N; l++)//注意区分字母L和数字1
		{
			for (int m = 0; m < N; m++)
			{
				for (int n = 0; n < N; n++)
				{
					dct[k][l] += (2 / N) * (ori[m][n]) * (cos((2 * m + 1) * k * PI / (2 * N))) * (cos((2 * n + 1) * l * PI / (2 * N)));
				}
			}
		}
	}
}

2.用指针的方法实现:

#include<stdlib.h>
#include<iostream>
#include<math.h>
#define PI acos(-1)//定义圆周率
using namespace std;

void DCT(float*** ori, float*** dct, float N);

int main(void)
{
	const int N = 4;//矩阵的阶数
	float start[N][N] = { 13,2,3,4,20,6,7,8,9,10,11,12,35,14,15,16 };//二维数组的初始值,可以自己任意设置
	//为多级指针申请内存时遵循这条原则:申请的时候从外层往里层,逐层申请;释放的时候从里层往外层,逐层释放
	float** oriMatrix = NULL;//用指针的形式定义二维数组,方便作为函数参数来传递
	float** dctMatrix = NULL;//用来接收经过dct函数变换后的二维数组
	//为oriMatrix申请内存
	oriMatrix = (float**)malloc(sizeof(float*) * N);
	if (oriMatrix == NULL)
	{
		cout << "func malloc() err." << endl;
		exit(-1);
	}
	for (int s = 0; s < N; s++)
	{
		oriMatrix[s] = (float*)malloc(sizeof(float) * N);
		if (oriMatrix[s] == NULL)
		{
			cout << "func malloc() err." << endl;
			exit(-1);
		}
	}
	//为dctMatrix申请内存
	dctMatrix = (float**)malloc(sizeof(float*) * N);
	if (dctMatrix == NULL)
	{
		cout << "func malloc() err." << endl;
		exit(-1);
	}
	for (int s = 0; s < N; s++)
	{
		dctMatrix[s] = (float*)malloc(sizeof(float) * N);
		if (dctMatrix[s] == NULL)
		{
			cout << "func malloc() err." << endl;
			exit(-1);
		}
	}
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			oriMatrix[i][j] = start[i][j];
		}
	}
	//初始化dctMatrix
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			dctMatrix[i][j] = 0;
		}
	}
	//输出oriMatrix
	cout << "原始二维数组矩阵:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%-10.4f", oriMatrix[i][j]);//每个输出占10个字符,左对齐,保留4位小数
		}
		cout << endl;
	}
	DCT(&oriMatrix, &dctMatrix, N);//调用自己定义的函数
	cout << endl;
	cout << "经过DCT变换后的二维数组矩阵:" << endl;
	for (int i = 0; i < N; i++)
	{
		for (int j = 0; j < N; j++)
		{
			printf("%-10.4f", dctMatrix[i][j]);
		}
		cout << endl;
	}
	
	//为oriMatrix释放内存
	for (int s = 0; s < N; s++)
	{
		free(oriMatrix[s]);
	}
	free(oriMatrix);
	//为dctMatrix释放内存
	for (int s = 0; s < N; s++)
	{
		free(dctMatrix[s]);
	}
	free(dctMatrix);

	return 0;
}

void DCT(float*** ori, float*** dct, float N)//第一个形参是原始二维数组的地址,第二个形参矩阵是经过DCT变换的二维数组的地址,第三个形参是阶数
{
	//计算dct[0][0]的值
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			(*dct)[0][0] += (1 / N) * (*ori)[m][n];
		}
	}
	//计算dct[0][1]
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			(*dct)[0][1] += (sqrt(2) / N) * ((*ori)[m][n]) * cos((2 * n + 1) * PI / (2 * N));
		}
	}
	//计算dct[1][0]
	for (int m = 0; m < N; m++)
	{
		for (int n = 0; n < N; n++)
		{
			(*dct)[1][0] += (sqrt(2) / N) * ((*ori)[m][n]) * cos((2 * m + 1) * PI / (2 * N));
		}
	}
	//从dct[1][1]一直计算到dct[N-1][N-1],根据公式来看,需要四个for循环
	for (int k = 1; k < N; k++)
	{
		for (int l = 1; l < N; l++)//注意区分字母L和数字1
		{
			for (int m = 0; m < N; m++)
			{
				for (int n = 0; n < N; n++)
				{
					(*dct)[k][l] += (2 / N) * ((*ori)[m][n]) * (cos((2 * m + 1) * k * PI / (2 * N))) * (cos((2 * n + 1) * l * PI / (2 * N)));
				}
			}
		}
	}
}

 

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值