C++实现离散余弦变换

写在前面

到目前为止已经阅读了相当一部分的网格水印等方面的论文了,但是论文的实现进度还没有更上,这个月准备挑选一些较为经典的论文,将其中的算法实现。在实现论文的过程中,发现论文中有用到一些空域转频率域的算法。因此也就想到了实现一下离散余弦变换。虽然本文的代码和网上很多已有的代码很类似,思路都没有太多的差别,但是本文有一个比较重要的改进。具体的说,网上现有DCT算法输入的是一个固定的二维数组。当二维数组作为函数参数进行传递时,至少需要给出第二个维度的大小,否则编译器会报错。但是在图形图像处理中,当我们希望使用DCT变换把某个图形或者图像转换到频域时,可能我在调用DCT函数之前事先并不知道图形或者图像的规模,因此这种传参方式较大限制了代码的使用。本文的一个改进就是,DCT函数的参数不再是二维数组,而是传入一个二维指针,通过手动寻址来实现函数功能。

离散余弦变换理论基础

我想大家比较熟知的是傅立叶变换。其实离散余弦变换跟傅立叶变换差不多。二维离散余弦变换的定义由下式表示:

反变换表示如下:

代码实现

根据上面的公式,很容易就能写出代码

// DCT - Discrete Cosine Transform
void DCT( double ** input, double ** output, int row, int col )
{
    cout<<"Test in DCT"<<endl;
    double ALPHA, BETA;
    int u = 0;
    int v = 0;
    int i = 0;
    int j = 0;

    for(u = 0; u < row; u++)
    {
        for(v = 0; v < col; v++)
        {
            if(u == 0)
            {
                ALPHA = sqrt(1.0 / row);
            }
            else
            {
                ALPHA = sqrt(2.0 / row);
            }

            if(v == 0)
            {
                BETA = sqrt(1.0 / col);
            }
            else
            {
                BETA = sqrt(2.0 / col);
            }

            double tmp = 0.0;
            for(i = 0; i < row; i++)
            {
                for(j = 0; j < col; j++)
                {
                    tmp += *((double*) input + row*i + j ) * cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col));
                }
            }
            *((double*) output + row*u + v) = ALPHA * BETA * tmp;
        }
    }

    cout << "The result of DCT:" << endl;
    for(int m  = 0; m < row; m++)
    {
        for(int n= 0; n < col; n++)
        {
            cout <<setw(8)<< *((double*) output + row*m + n)<<" \t";
        }
        cout << endl;
    }
}

注意代码中的函数参数不是二维数组,而是一个指向二维数组的指针。相应的反变换的代码如下:

// Inverse DCT
void IDCT( double ** input, double ** output, int row, int col )
{
    cout<<"Test in IDCT"<<endl;
    double ALPHA, BETA;
    int u = 0;
    int v = 0;
    int i = 0;
    int j = 0;

    for(i = 0; i < row; i++)
    {
        for( j = 0; j < col; j++)
        {
            double tmp = 0.0;
            for(u = 0; u < row; u++)
            {
                for(v = 0; v < col; v++)
                {
                    if(u == 0)
                    {
                        ALPHA = sqrt(1.0 / row);
                    }
                    else
                    {
                        ALPHA = sqrt(2.0 / row);
                    }
                    if(v == 0)
                    {
                        BETA = sqrt(1.0 / col);
                    }
                    else
                    {
                        BETA = sqrt(2.0 / col);
                    }
                    tmp += ALPHA * BETA * *((double*) input + row*u + v )* cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col));
                }
            }
            *((double*) output + row*i + j) = tmp;
        }
    }

    cout << "The result of IDCT:" << endl;
    for(int m  = 0; m < row; m++)
    {
        for(int n= 0; n < col; n++)
        {
            cout <<setw(8)<< *((double*) output + row*m + n)<<"\t";
        }
        cout << endl;
    }
}

测试代码

#include <iostream>
#include <math.h>
#include<cstdio>
#include <iomanip>
#include<algorithm>

using namespace std;
#define PI 3.1415926
int main()
{
    int i = 0;
    int j = 0;
    int u = 0;
    int v = 0;

    const int rows = 3;
    const int cols = 3;

    double inputdata[rows][cols] = {
        {89,101,114},
        {97,115,131},
        {114,134,159},
    };

    double outputdata[rows][cols];

    DCT( (double**)inputdata, (double**)outputdata,rows, cols );
    IDCT( (double**)outputdata, (double**)inputdata,rows,cols );

    system("pause");
    return 0;
}

程序运行结果如下:

小结

本文中给出的测试代码中,输入的数组行数和列数相同。当输入数组的函数和列数不相同时,输出的结果是错误的。但是当把函数设计为参数是二维数组时,输入数组的行数和列数不同时,也可以正常运行。我思考了许久,也没有想出具体的原因。目前觉得比较可能的原因是,当数组行数和列数不同时,寻址发生了错误?具体原因有待验证。

转载请注明出处:http://www.cnblogs.com/scut-linmaojiang/p/5013590.html

时间: 2024-10-23 09:56:51

C++实现离散余弦变换的相关文章

离散余弦变换

1 using System; 2 using System.Collections.Generic; 3 using System.Drawing; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace DFT 9 { 10 class FFT 11 { 12 int row; 13 int col; 14 double[,] FM; 15 double[,] FN; 16

AVS-P2中的8x8二维整数余弦变换(Integer Cosine Transform, ICT)

为何采用ICT? 基于块的DCT能很大程度上去除图像元素在变换域中的相关性,在图像和视频编码领域得到广泛的应用.但由于DCT存在计算量大以及存在反变换失配,因此AVS Part 2采用的是ICT,其性能接近8x8 DCT,但精确定义到每一位的运算避免了不同反变换之间的失配.ICT具有复杂度低.完全匹配等优点.ICT可用加法和移位直接实现. 何为ICT? 整数余弦变换(Integer Cosine Transform, ICT)源自离散余弦变换,是定点余弦变换的扩展.设一个二维数据块X大小为nxm

理解离散傅立叶变换(一. 傅立叶变换的由来)

理解离散傅立叶变换(一) ------傅立叶变换的由来 关于傅立叶变换,不管是书本还是在网上可以非常easy找到关于傅立叶变换的描写叙述,可是大都是些故弄玄虚的文章,太过抽象,尽是一些让人看了就望而生畏的公式的罗列,让人非常难可以从感性上得到理解,近期,我偶尔从网上看到一个关于数字信号处理的电子书籍,是一个叫Steven W. Smith, Ph.D.外国人写的,写得非常浅显,里面有七章由浅入深地专门讲述关于离散信号的傅立叶变换,尽管是英文文档,我还是硬着头皮看完了有关傅立叶变换的有关内容,看了

理解离散傅立叶变换(一. 傅立叶的起源变换)

理解离散傅立叶变换(一) ------傅立叶变换的由来 关于傅立叶变换,不管是书本还是在网上可以非常easy找到关于傅立叶变换的描写叙述,可是大都是些故弄玄虚的文章,太过抽象.尽是一些让人看了就望而生畏的公式的罗列,让人非常难可以从感性上得到理解.近期.我偶尔从网上看到一个关于数字信号处理的电子书籍,是一个叫Steven W. Smith, Ph.D.外国人写的,写得非常浅显,里面有七章由浅入深地专门讲述关于离散信号的傅立叶变换.尽管是英文文档.我还是硬着头皮看完了有关傅立叶变换的有关内容,看了

算法系列之二十四:离散傅立叶变换之音频播放与均衡器

导语 在算法系列的第二十二篇,我们介绍了离散傅立叶变换算法的实现,将时域的音频信号转换到频域进行分析,获取拨号音频的频率特征.这一篇我们将介绍一种频域均衡器的实现方法,所谓的频域均衡器,就是在频域信号的基础上对音频数据进行调整,然后再将频域信号转换成时域信号在回放设备上播放,从而达到音色调节的目的.将频域信号转换成时域信号的算法,就是离散傅立叶逆变换算法. 1 离散傅立叶逆变换 有从时域转换到频域的方法,就必然有从频域转换到时域的方法,相对于离散傅里叶变换,这个反向转换就是离散傅里叶逆变换(ID

离散傅立叶变换,快速傅立叶变换和傅里叶级数

目的:要学习通讯或者从事通讯行业都免不了要接触傅立叶变换,傅立叶变换有很多形式包括积分形式和离散形式的,公式也是各种积分或者累加,我在学习的初始是直接背下来这些公式,并没有想过每个公式里变量和积分以及累加的含义.因此现在有了写一篇关于傅立叶变换的博客的想法.本篇主要以最简单的cos(t)为例,以Matlab为媒介,比较Discrete Fourier Transform(DFT)和Fast Fourier Transform (FFT).这是因为DFT是我在学习信号处理时老师直接给的公式,而FF

算法系列之二十三:离散傅立叶变换之音频播放与频谱显示

算法系列之二十三:离散傅立叶变换之音频播放与频谱显示 算法系列之二十三离散傅立叶变换之音频播放与频谱显示 导语 什么是频谱 1 频谱的原理 2 频谱的选择 3 频谱的计算 显示动态频谱 1 实现方法 2 杂项说明 结果展示 导语 频谱和均衡器,几乎是媒体播放程序的必备物件,没有这两个功能的媒体播放程序会被认为不够专业,现在主流的播放器都具备这两个功能,foobar 2000的十八段均衡器就曾经让很多人着迷.在上一篇对离散傅立叶变换介绍的基础上,本篇就进一步介绍一下频谱是怎么回事儿,下一篇继续介绍

python 图像的离散傅立叶变换

图像(MxN)的二维离散傅立叶变换可以将图像由空间域变换到频域中去,空间域中用x,y来表示空间坐标,频域由u,v来表示频率,二维离散傅立叶变换的公式如下: 在python中,numpy库的fft模块有实现好了的二维离散傅立叶变换函数,函数是fft2,输入一张灰度图,输出经过二维离散傅立叶变换后的结果,但是具体实现并不是直接用上述公式,而是用快速傅立叶变换.结果需要通过使用abs求绝对值才可以进行可视化,但是视觉效果并不理想,因为傅立叶频谱范围很大,所以要用log对数变换来改善视觉效果. 另外,图

图像的余弦变换

1 问题的提出 2 一维离散余弦变换 3 二维离散余弦变换 4 余弦变换的性质 5 余弦变换的应用 原文地址:https://www.cnblogs.com/Terrypython/p/10960879.html