五、c++实现离散傅里叶变换
C++离散傅里叶变换
一、序言:
该教程基于之前的图像处理类MYCV,是对其的补充。
二、设计目标
对图像进行简单的离散傅里叶变换,并输出生成的频谱图。
三、需要提前掌握的知识
二维傅里叶变换公式:

四、详细步骤
1.首先定义一个方法,该方法对输入的图像进行傅里叶变换
输入:MyImage 源图像
输出:ComplexNu 进行离散傅里叶变换后的复数数组
定义:
static ComplexNumber* Dft2(MyImage const &Scr);
实现:
ComplexNumber* MyCV::Dft2(MyImage const &Scr)
{
int width = Scr.m_width;
int height = Scr.m_height;
// 将 scr_data 转化为灰度
MyImage *grayimage = Gray(Scr);
unsigned char* gray_data = grayimage->m_data;
int gray_bytesPerLine = grayimage->m_bytesPerLine;
// 将 gray_data 转化为 double 型,并去掉用于填充的多余空间
double *double_data = new double[width*height];
for(int i=;i<height;i++)
for(int j=;j<width;j++)
{
double_data[i*width+j]=(double)gray_data[i*gray_bytesPerLine+j];
}
// 对 double_data 进行傅里叶变换
ComplexNumber *dft2_data = new ComplexNumber[width*height];
double fixed_factor_for_axisX = (- * PI) / height;
// evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
double fixed_factor_for_axisY = (- * PI) / width;
// evaluate -i2π/N of -i2πux/N, and store the value for computing efficiency
for (int u = ; u<height; u++) {
for (int v = ; v<width; v++) {
for (int x = ; x<height; x++) {
for (int y = ; y<width; y++) {
double powerX = u * x * fixed_factor_for_axisX; // evaluate -i2πux/N
double powerY = v * y * fixed_factor_for_axisY; // evaluate -i2πux/N
ComplexNumber cplTemp;
cplTemp.m_rl = double_data[y + x*width] * cos(powerX + powerY);
// evaluate f(x) * e^(-i2πux/N), which is equal to f(x) * (cos(-i2πux/N)+sin(-i2πux/N)i) according to Euler's formula
cplTemp.m_im = double_data[y + x*width] * sin(powerX + powerY);
dft2_data[v + u*width] = dft2_data[v + u*width] + cplTemp;
}
}
}
}
// 返回傅里叶数组
return dft2_data;
}
2.为了让傅里叶变换可视化,旭阳对其进行标准化和中性化
输入:ComplexNumber 离散傅里叶变换生成的复数数组
输出:MyImage 可视化后的图像
定义:
static MyImage* Dft22MyImage(ComplexNumber *Scr,int width,int height);
实现:
MyImage* MyCV::Dft22MyImage(ComplexNumber *Scr, int const width, int const height)
{
// 将傅里叶数组归一化
// 取模
double mold[width*height];
for(int i = ;i<width*height;i++)
{
mold[i] = Scr[i].get_mold();
}
// 获取最小值
double min = mold[];
for(int i = ;i<width*height;i++)
{
if(mold[i]<min)
min = mold[i];
}
// 获取去掉前几大值的最大值
double maxqueue[] = {.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.,.},max;
for(int i = ;i<width*height;i++){
if(mold[i]>maxqueue[])
maxqueue[] = mold[i];
}
for(int j =;j<;j++){
for(int i = ;i<width*height;i++){
if(mold[i]>maxqueue[j]&&mold[i]<maxqueue[j-])
maxqueue[j] = mold[i];
}
}
max = maxqueue[];
unsigned char *normalized_data = new unsigned char[width*height];
for(int i=;i<height;i++)
for(int j=;j<width;j++)
{
unsigned char t = (unsigned char)((mold[i*width+j]-min)/(max-min)*);
if(t>)
t = ;
normalized_data[i*width+j]=t;
}
// 将图像中心化
unsigned char* center_data = new unsigned char[width*height];
for (int u = ; u<height; u++)
{
for (int v = ; v<width; v++) {
if ((u<(height / )) && (v<(width / ))) {
center_data[v + u*width] =
normalized_data[width / + v + (height / + u)*width];
}
else if ((u<(height / )) && (v >= (width / ))) {
center_data[v + u*width] =
normalized_data[(v - width / ) + (height / + u)*width];
}
else if ((u >= (height / )) && (v<(width / ))) {
center_data[v + u*width] =
normalized_data[(width / + v) + (u - height / )*width];
}
else if ((u >= (height / )) && (v >= (width / ))) {
center_data[v + u*width] =
normalized_data[(v - width / ) + (u - height / )*width];
}
}
}
// 向中心化的数组填充空间
int bytesPerLine = (width*+)/*;
unsigned char *dst_data = new unsigned char[bytesPerLine*height];
for(int i=;i<height;i++)
for(int j=;j<width;j++)
{
dst_data[i*bytesPerLine+j] = center_data[i*width+j];
}
return new MyImage(dst_data,width,height,MyImage::format::GRAY8);
}
至此,离散傅里叶变换的方法实现完成,效果图如下:


如果上述教程或代码中有任何错误,欢迎批评和指证。
五、c++实现离散傅里叶变换的更多相关文章
- 离散傅里叶变换(DFT)
目录 一.研究的意义 二.DFT的定义 三.DFT与傅里叶变换和Z变换的关系 四.DFT的周期性 五.matlab实验 五.1 程序 ...
- opencv3.2.0图像离散傅里叶变换
源码: ##名称:离散傅里叶变换 ##平台:QT5.7.1+opencv3.2.0 ##日期:2017年12月13. /**** 新建QT控制台程序****/ #include <QCoreAp ...
- c语言数字图像处理(六):二维离散傅里叶变换
基础知识 复数表示 C = R + jI 极坐标:C = |C|(cosθ + jsinθ) 欧拉公式:C = |C|ejθ 有关更多的时域与复频域的知识可以学习复变函数与积分变换,本篇文章只给出DF ...
- Opencv 实现图像的离散傅里叶变换(DFT)、卷积运算(相关滤波)
我是做Tracking 的,对于速度要求非常高.发现傅里叶变换能够使用. 于是学习之. 核心: 最根本的一点就是将时域内的信号转移到频域里面.这样时域里的卷积能够转换为频域内的乘积! 在分析图像信号的 ...
- opencv 3 core组件进阶(3 离散傅里叶变换;输入输出XML和YAML文件)
离散傅里叶变换 #include "opencv2/core/core.hpp" #include "opencv2/imgproc/imgproc.hpp" ...
- 用matlab脚本语言写M文件函数时用三种方法简单实现实现DFT(离散傅里叶变换)
%用二重循环实现DFT: function xk=dt_0(xn); %define a function N=length(xn); %caculate the length of the vari ...
- 灰度图像--频域滤波 傅里叶变换之离散傅里叶变换(DFT)
学习DIP第23天 转载请标明本文出处:http://blog.csdn.net/tonyshengtan,欢迎大家转载,发现博客被某些论坛转载后,图像无法正常显示,无法正常表达本人观点,对此表示很不 ...
- 【转】离散傅里叶变换-DFT(FFT)基础
转:https://blog.csdn.net/zhangxz259/article/details/81627341 什么是离散傅里叶变换 matlab例子 本文是从最基础的知识开始讲解,力求用最通 ...
- OpenCV离散傅里叶变换
离散傅里叶变换 作用:得到图像中几何结构信息 结论:傅里叶变换后的白色部分(即幅度较大的低频部分),表示的是图像中慢变化的特性,或者说是灰度变化缓慢的特性(低频部分). 傅里叶变换后的黑色部分(即幅度 ...
随机推荐
- InnoDB recovery过程解析
本文来自网易云社区. InnoDB如果发生意外宕机了,数据会丢么?对于这个问题,稍微了解一点MySQL知识的人,都会斩钉截铁的回答:不会!为什么?他们也会毫不犹豫的说:因为有重做日志(redo log ...
- hdu3078(lca / RMQ在线)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=3078 题意: 给出一棵 n 个点的带点权值的树, 接下来有 q 组形如 k, x, y 的输入, 若 ...
- linux线程私有数据---TSD池
进程内的所有线程共享进程的数据空间,所以全局变量为所有线程共有.在某些场景下,线程需要保存自己的私有数据,这时可以创建线程私有数据(Thread-specific Data)TSD来解决.在线程内部, ...
- 洛谷P2052 道路修建
P2052 道路修建 题目描述 在 W 星球上有 n 个国家.为了各自国家的经济发展,他们决定在各个国家 之间建设双向道路使得国家之间连通.但是每个国家的国王都很吝啬,他们只愿 意修建恰好 n – 1 ...
- [Xcode 实际操作]四、常用控件-(18)MKMapView地图,将地理坐标转换为实际地名
目录:[Swift]Xcode实际操作 本文将演示将地理坐标转换为实际地名. 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit //首先往视 ...
- P3379 【模板】最近公共祖先(LCA)(倍增)
这题有毒!!!!!!!!!! TM我重新打的板子,然而...... 5分钟打完 debug两小时 我的写法常数太大了 每次DFS都要For去更新F 最后写了快读才A 改: 只处理f[i][0] dfs ...
- express-http-proxy 的基础使用
const app = express() app.use(matchPath, proxy(serverAddress, { proxyReqPathResolver: function(req) ...
- Vue里的nextTick方法
官方解释: 在下次 DOM 更新循环结束之后执行延迟回调.在修改数据之后立即使用这个方法,获取更新后的 DOM. 自己总结: `Vue.nextTick(callback)`,当数据发生变化,更新后执 ...
- POJ 3537 Crosses and Crosses(sg博弈)
题目:在1*n 的棋盘里面,A和B都在里面画叉 , 如果谁可以画了一个叉后,可以连成3个叉,那谁胜利 : 分析: 首先考虑如果我在玩游戏,我最希望对手可以画出-x-x or -xx- , 这种 ...
- 设计模式——原型模式(Prototype)
用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象.——DP UML类图 模式说明 如果把在一张纸上手写一篇简历的过程看成是类的实例化过程,那么通过原型模式创建对象的过程就是拿着这张纸到复印 ...