DCT算法的原理和优化

https://blog.csdn.net/qq_20613513/article/details/78744101


离散余弦变换(DCT for Discrete Cosine Transform)是与傅里叶变换相关的一种变换,它与离散傅里叶变换类似,但是只使用实数。

这种变化经常被信号处理和图像处理使用,用于对信号和图像(包括静止图像和运动图像)进行有损压缩。在压缩算法中,现将输入图像划分为8*8或16*16的图像块,对每个图像块作DCT变换;然后舍弃高频的系数,并对余下的系数进行量化以进一步减少数据量;最后使用无失真编码来完成压缩任务。解压缩时首先对每个图像块作DCT反变换,然后将图像拼接成一副完整的图像。

大多数自然信号(包括声音和图像)的能量都集中在余弦变换后的低频部分。由于人眼对于细节信息不是很敏感,因此信息含量更少的高频部分可以直接去掉,从而在后续的压缩操作中获得较高的压缩比。

  • 1. 一维DCT变换
  • 2. 二维DCT变换
  • 3. DCT反变换
  • 4. 怎样提高二维DCT变换的速度

1. 一维DCT变换

一维DCT变换共有8种,最实用的一种公式如下: 
这里写图片描述

其中N是一维数据的元素总数,c(u)系数使得DCT变换矩阵成为正交矩阵,正交特性在二维DCT变换中更能体现其优势。一维DCT变换的复杂度是O(n^2)。

2. 二维DCT变换

二维DCT变换公式如下:

这里写图片描述

我们将公式变换一下: 
这里写图片描述

可以发现,二维DCT变换其实是在一维DCT变换的基础上,再做一次一维DCT变换。二维DCT也可以写成矩阵相乘的形式:

这里写图片描述

矩阵A和f必须为长宽均为N的方阵,f不是方阵的情况可以补零再对其做DCT变换。生成矩阵A的matlab代码如下:

A=zeros(N);
 for i=0:N
    for j=0:N
        if i==0
            a=sqrt(1/N);
        else
            a=sqrt(2/N);
        end            
        A(i+1,j+1)=a*cos(pi*(2*j+1)*i/(2*N));
    end
end
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

二维DCT变换的复杂度达到O(n^4),所以进行DCT变换的矩阵不宜过大。在实际处理图片的过程中,需要先把矩阵分块,一般分为8*8或16*16大小,这样DCT变换不至于耗费过多的时间。

3. DCT反变换

DCT变换是无损并可逆的,反变换的公式如下:

这里写图片描述

同样,DCT反变换也可以写成矩阵相乘的形式:

这里写图片描述

DCT反变换的时间复杂度与DCT变换相同。

4. 怎样提高DCT变换的速度

由于DCT变换的高效,这种变换方法已经广泛应用于信号处理和图像处理,成为许多图像编码国际标准的核心。但随着信息时代的来临和信息量的飞速增长,人们对图像处理的速度要求越来越高,虽然离散余弦变换已经比较高效了,但是能否在DCT变换的基础上,继续提升其速度呢?

我们考虑用并行计算的方法提升速度。并行计算指的是同时使用多种计算资源解决计算问题的一种高效的计算手段。图形处理器(Graphics Processing Unit,缩写GPU)非常擅长大规模并发计算,所以我考虑在GPU上实现并行的二维DCT变换,看能否有效提升二维DCT变换的速度。

我们观察二维DCT变换的公式,不难发现每一个DCT系数的计算,不依赖于任何一个DCT系数,也就是说,任意多个DCT系数的计算,都可以独立进行。所以我考虑对整个矩阵分线程块计算,线程块内再以每一个系数为单位分为线程,每一个DCT系数由一个线程来完成。记矩阵的大小为length*length,块大小为block_len* block_len。

DCT算法的CUDA代码如下,环境为ubuntu 14.04,CUDA版本8.0:

int tidy = blockIdx.x * blockDim.x + threadIdx.x;
    int tidx = blockIdx.y * blockDim.y + threadIdx.y;
    int index = tidx * length + tidy;
    int i;
    float tmp;
    float beta, alfa;
    if (tidx == 0)
        beta = sqrt(1.0 / length);
    else
        beta = sqrt(2.0 / length);
    if (tidy == 0)
        alfa = sqrt(1.0 / length);
    else
        alfa = sqrt(2.0 / length);
    if (tidx < length && tidy < length) {
        for (i = 0; i < length * length; i++) {
            int x = i / length;
            int y = i % length;
            tmp += ((double) f[i])
                    * cos((2 * x + 1) * tidx * PI / (2.0 * length))
                    * cos((2 * y + 1) * tidy * PI / (2.0 * length));
        }
        F[index] = (double) alfa * beta * tmp;
    }
    __syncthreads();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

由于GPU的控制单元可以把多个访问合并成少的访问,同时,计算每个系数需要访问的数据都完全相同,导致同一个块内的线程对于原矩阵的访问可以达到非常高的效率,所以我直接将块数设置为1,让所有计算系数的线程处于一个块内。

通过实验发现,基于CPU实现的DCT算法随着矩阵的增大,处理时间急剧的上升,而基于GPU实现的并行二维DCT变换算法,耗时非常短,计算速度惊人。

这里写图片描述

Matrix LengthDCT Based on GPU(ms)DCT Based on CPU(ms)speedup
82.1110.1110.053
165.5030.3360.061
3235.12962.8440.081
641.10516.33814.785
1282.312218.51294.291
2562.1511534.86213.556
3201.9613034.051547.195

从上表中我们发现,当矩阵比较小的时候,GPU并行计算没有带来优势,反而让DCT变换时间更长了。通过CUDA提供的程序性能分析工具,观察到GPU并行程序的大部分时间不是花在了计算上面,而是CUDA任务的创建上。当矩阵增大之后,CUDA程序的运行时间不再主要取决于Event的创建。而基于CPU的DCT变换的时间基本来自于计算,所以随着矩阵的增大,时间基本呈指数增长。

这里写图片描述

通过以上内容,我完整的了解了一维和二维DCT变换的详细过程,并且通过GPU并行计算为二维DCT变换加速,实验结果显示,对于比较大的矩阵,基于GPU的二维DCT变换速度得到了巨大的提升,但是在矩阵比较小的应用场景下,CPU更有优势。


  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
推荐,Matlab精选学习资料+练习源码大全+算法课件大合集。 一、Matlab示例源码 经典-matlab经典算法的程序 Matlab时间序列-AR 基于仿射变换的数字图象置乱技术 MATLAB源程序代码 拉格朗日插值 MATLAB源程序代码 蒙特卡洛法求椭圆面积的MATLAB源程序代码 牛顿Newton插值 MATLAB源程序代码 MATLAB DCT水印源程序代码 MATLAB GUI实现动态画图曲线的源程序代码 MATLAB光通过三稜镜色散动画 MATLAB绘制 维维安尼Viviani曲线 源代码程序 MATLAB霍夫曼Huffman编码译码GUI界面设计 源程序代码 MATLAB计算粒子速度分布 源程序代码 MATLAB建模 人口增长模型 源程序代码 MATLAB求解非线性方程组 fsolve源程序代码 MATLAB设计的简单滤波器程序源代码 MATLAB生成Gif图片程序源代码 MATLAB实现不同插值方法的GUI界面设计 源程序代码 MATLAB实现灰度预测模型的源代码 MATLAB实现偏微分方程的差分计算 源程序代码 MATLAB实现图像去噪 滤波 锐化 边缘检测 MATLAB实现线性拟合和相关系数 源程序代码 MATLAB实现学生成绩查询系统 源代码程序 MATLAB使用欧拉Euler法求解微分方程组 源程序代码 MATLAB图像处理实现螺纹识别 源程序代码 MATLAB图像处理实现直线识别(拟合角平分线) MATLAB文字连通域源程序代码 MATLAB寻找素数的源程序代码 MATLAB夜间车牌识别程序 MATLAB中的基本语法和语句示例代码 MATLAB中colorbar的设置 源程序代码 二、Matlab精选学习资料 Matlab常用源码 MATLAB基础教程资料合集 MATLAB控制仿真资料合集 MATLAB神经网络资料合集 MATLAB数值计算资料合集 MATLAB图像处理资料合集 MATLAB小波分析资料合集 MATLAB信号分析资料合集 MATLAB遗传算法资料合集 Simulink仿真技术资料合集 三、Matlab常用算法 十大算法合集 106人工变量法 遗传算法及其MATLAB程序 遗传算法matlab代码 遗传算法matlab实现源程序 蚁群算法最短路径matlab程序 第03章 非线性规划 第04章 动态规划 第05章 图与网络 第06章 排队论 第07章 对策论 第08章 层次分析法 第09章 插值与拟合 第10章 数据的统计描述和分析 第11章 方差分析 第12章 回归分析 第13章 微分方程建模 第14章 稳定状态模型 第15章 常微分方程的解法 第16章 差分方程模型 第17章 马氏链模型 第18章 变分法模型 第19章 神经网络模型 第20章 偏微分方程的数值解 第21章 目标规划 第22章 模糊数学模型 第23章 现代优化算法 第24章 时间序列模型 第25章 存贮论 第26章 经济与金融中的优化问题 第27章 生产与服务运作管理中的优化问题 第28章 灰色系统理论及其应用 第29章 多元分析 第30章 偏最小二乘回归 附录二 Matlab在线性代数中的应用 附录四 判别分析 附录一 Matlab入门 蒙特卡罗算法案例 算法数论 图论算法及其MATLAB实现++完成 先进算法讲义 遗传算法及其matlab实现 最优化计算机原理算法程序设计 模拟退火算法 常用算法PPT
Verilog DCT(离散余弦变换)是一种数字信号处理算法,广泛应用于音频和图像压缩领域。DCT算法通过将时域信号转换为频域信号来实现压缩效果。 在Verilog中,DCT算法的实现可以通过以下步骤完成: 1. 输入信号采样:首先,将输入的音频或图像信号进行采样,将连续的模拟信号转换为离散的数字信号。 2. 分块:将采样后的信号分成大小相等的块。每个块的大小取决于应用的要求和计算资源。 3. 窗函数:对每个块应用窗函数,以减小信号的边际效应。常用的窗函数有汉宁窗、汉明窗等。 4. 离散余弦变换:对每个块应用离散余弦变换算法,将时域信号转为频域信号。DCT算法是通过计算每个频域系数来完成的,这些系数表示信号在不同频率上的能量分布。 5. 量化:为了实现信号的压缩,需要对DCT系数进行量化。通过将系数更改为更少的位数或使用特定的量化表来实现。 6. 逆向DCT变换:对量化后的DCT系数应用逆向DCT变换,将其转换回时域信号。逆向DCT变换将频域系数重构为原始信号。 7. 输出和压缩:通过将逆向DCT得到的信号进行输出,可以得到压缩后的音频或图像信号。压缩比取决于量化的程度。 总之,Verilog DCT算法通过将输入信号从时域转换为频域,并对频域信号进行量化和逆变换,实现了对音频和图像信号的压缩。这为数字信号处理领域的压缩应用提供了一种有效的实现方式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值