zoukankan      html  css  js  c++  java
  • C++实现离散余弦变换(参数为二维指针)

    C++实现离散余弦变换(参数为二维指针)

    写在前面

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

    离散余弦变换理论基础

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

    enter description here

    反变换表示如下:
    enter description here

    代码实现

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

    // 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 + col*i + j ) * cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col));
                    }
                }
                *((double*) output + col*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 + col*m + n)<<" 	";
            }
            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 + col*u + v )* cos((2*i+1)*u*PI/(2.0 * row)) * cos((2*j+1)*v*PI/(2.0 * col));
                    }
                }
                *((double*) output + col*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 + col*m + n)<<"	";
            }
            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;
    }
    

    程序运行结果如下:
    enter description here

    小结

    之后可以对代码进行升级,不再使用二维数组作为参数传递,而是使用Eigen类型作为参数,这样代码更加清晰,并且内存管理等方面也更加方便。

     

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

  • 相关阅读:
    [JavaScript-PHP]无刷新Ajax+POST使用阿里云短信平台发送短信
    [PHP]开源php拼音库的使用方法
    redis远程连接不上解决办法
    ServiceStack.Redis连接阿里云redis服务时使用连接池出现的(密码验证)问题
    .Net使用Redis详解之ServiceStack.Redis
    Windows下Redis的使用
    axios文件流下载(excel文件)
    生成线上用https证书,支持通配符和多域名,初学Let's Encrypt用于IIS,纯本地手动
    什么是TXT记录?如何设置、检测TXT记录
    v-cloak 的用法
  • 原文地址:https://www.cnblogs.com/scut-linmaojiang/p/5013590.html
Copyright © 2011-2022 走看看