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 + 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)<<" \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 + 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)<<"\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;
}

程序运行结果如下:

小结

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

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

C++实现离散余弦变换(参数为二维指针)的更多相关文章

  1. C#微信公众号接口开发实例-高级接口-申请带参数的二维码

    最近公司涉及到微信绑定用户,做了高级接口-申请带参数的二维码,总结了下微信开发接口.微信接口开发都是除了消息用的xml 回复基本上都是用json的形式传递信息(post/get),开发的方法基本都是一 ...

  2. Force.com微信开发系列(八)生成带参数的二维码

    为了满足用户渠道推广分析的需要,公众平台提供了生成带二维码的接口.使用该接口可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送.目前有两种类型的二维码,分别是临时二维码和永久二维码 ...

  3. 微信开发之——Php批量生成带参数的二维码

    带参数的二维码对于渠道营销推广来说是很有用的,可以获得多个带不同场景值的二维码,用户扫描后,公众号可以接收到事件推送,可喜的是微信开通了这个接口,那下面就来研究一下吧. 具体接口说明请参见,微信公众平 ...

  4. C语言里的指针探析——type *name[] 在函数参数里面,是一个二维指针

    type *name[] 在函数参数里面声明和不在函数里面声明其实不一样. type *name[] 如果在函数参数里声明,则name 是一个二维指针,并不是一个指针数组,而如果不在函数参数里声明,则 ...

  5. 微信公众号生成带参数的二维码asp源码下载

    晚上闲着没事,一个朋友联系,让帮忙写一个微信公众号利用asp生成带参数的二维码,别人扫了后如果已经关注过该公众号的,则直接进入公众号里,如果没关注则提示关注,关注后自动把该微信用户资料获取到并且保存入 ...

  6. 通过数组初始化链表的两种方法:指向指针的引用node *&tail和指向指针的指针(二维指针)node **tail

    面试高频题:单链表的逆置操作/链表逆序相关文章 点击打开 void init_node(node *tail,char *init_array) 这样声明函数是不正确的,函数的原意是通过数组初始化链表 ...

  7. 【视频开发】OpenCV中Mat,图像二维指针和CxImage类的转换

    在做图像处理中,常用的函数接口有OpenCV中的Mat图像类,有时候需要直接用二维指针开辟内存直接存储图像数据,有时候需要用到CxImage类存储图像.本文主要是总结下这三类存储方式之间的图像数据的转 ...

  8. 二维指针*(void **)的研究(uC/OS-II案例) 《转载》

    uC/OS-II内存管理函数内最难理解的部分就是二维指针,本文以图文并茂的方式对二维指针进行了详细分析与讲解.看完本文,相信对C里面指针的概念又会有进一步的认识. 一.OSMemCreate( ) 函 ...

  9. 最长公共子序列的C++实现---附二维指针的使用方法

    想了挺久到底第一篇在这儿的博客写什么好,刚好这两天又一次看到动态规划的LCS算法觉得还是有点意思的,就拿来写了写,第一篇博客就发它吧. #include<iostream> #includ ...

随机推荐

  1. 关于JS中变量的作用域-实例

    先看问题,如下,自己运行一下吧! if (!('_qyzA' in window)) { var _qyzA = 1; } alert(_qyzA);//undefined 分析:首先,所有的全局变量 ...

  2. PKUSC 模拟赛 day1 下午总结

    下午到了机房之后又困又饿,还要被强行摁着看英文题,简直差评 第一题是NOIP模拟赛的原题,随便模拟就好啦 本人模拟功力太渣不小心打错了个变量,居然调了40多分钟QAQ #include<cstd ...

  3. Use windows batch script to create menu

    Background Recently, I find that we need  to  type some very long gradle commands to run build, chec ...

  4. linux进程的地址空间,核心栈,用户栈,内核线程

    linux进程的地址空间,核心栈,用户栈,内核线程 地址空间: 32位linux系统上,进程的地址空间为4G,包括1G的内核地址空间,和3G的用户地址空间. 内核栈: 进程控制块task_struct ...

  5. spring autoWire注解和@resource注解区别

    1.autoWire注解主要是按类型匹配.因为autowire的扫描机制,是按照接口类型来扫描bean的. 而JSR250 @resource注解是通过名称扫描注入的. @autowire注解的扫描方 ...

  6. HTML5入门1---Canvas画布

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...

  7. Swift入门(十一)——类型转换与is、as操作

    三种操作:is.as?和as! Swift是强类型语言,但也允许开发者通过is.as?和as!这三种操作来对类型进行判断和强制转换.其中is用作类型判断,而as?和as!则分别是类型转换的可选形式和强 ...

  8. 转TransactionProxyFactoryBean代理事务

    <?xml version="1.0" encoding="GBK"?> <!-- 指定Spring配置文件的DTD信息 --> < ...

  9. android rabbitMQ

    http://www.cnblogs.com/wufawei/archive/2012/03/31/2427823.html http://www.raywenderlich.com/5527/get ...

  10. DNSget Ip

    var address = Dns.GetHostEntry(Dns.GetHostName()).AddressList.FirstOrDefault(a => a.AddressFamily ...