热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

C++实现二维fft和ifft

我是搜遍了没找到实现方法,要么是opencv,要么是dft,然而dft效率差的惊人,随便一个图像都跑不出来二维傅里叶变换相当于先按行变换,再按列变换所以首先是一维fft的封装,但封

我是搜遍了没找到实现方法,要么是opencv,要么是dft,然而dft效率差的惊人,随便一个图像都跑不出来

二维傅里叶变换相当于先按行变换,再按列变换

所以首先是一维fft的封装,但封装fft前,得先是复数类的封装


complex.h

#ifndef COMPLEX_H
#define COMPLEX_H
#define MAX_MATRIX_SIZE 4194304 // 2048 * 2048
#define PI 3.141592653
#define EXP 2.718281828
#include
#include
#include
class Complex
{
private:
public:
double real;
double imag;
Complex();
Complex(double rl, double im);
~Complex(void);
// 重载四则运算符号
inline Complex operator +(const Complex &c) {
return Complex(real + c.real, imag + c.imag);
}
inline Complex operator -(const Complex &c) {
return Complex(real - c.real, imag - c.imag);
}
inline Complex operator *(const Complex &c) {
return Complex(real*c.real - imag*c.imag, imag*c.real + real*c.imag);
}
inline Complex operator /(const Complex &c) {
if ((0==c.real) && (0==c.imag)) {
qDebug()<<"11111 ComplexNumber ERROR: divider is 0!";
return Complex(real, imag);
}
return Complex((real*c.real + imag*c.imag) / (c.real*c.real + c.imag*c.imag),
(imag*c.real - real*c.imag) / (c.real*c.real + c.imag*c.imag));
}
inline Complex operator /(const double &c) {
if (0==c) {
qDebug()<<"11111 ComplexNumber ERROR: divider is 0!";
return Complex(real, imag);
}
return Complex(real/c,imag/c);
}
inline Complex operator =(const Complex &c){
real=c.real;
imag=c.imag;
return *this;
}
inline bool operator ==(const Complex &c){
return (real==c.real)&&(imag==c.imag);
}
friend QDebug operator <<(QDebug debug, const Complex &c) {
debug <<"("<<((abs(c.real)<0.000001)?0:c.real) <<"+" <<((abs(c.imag)<0.000001)?0:c.imag)<<"i)";
return debug;
}
double mod(){
return sqrt(real*real+imag*imag);
}
void SetValue(double rl, double im);
};
#endif // COMPLEX_H

complex.cpp

#include "complex.h"
Complex::Complex()
{
real = 0;
imag = 0;
}
Complex::Complex(double rl, double im)
{
real = rl;
imag = im;
}
Complex::~Complex(void)
{
}
void Complex::SetValue(double rl, double im) {
real = rl;
imag = im;
}

然后是一维fft和ifft


dft_one.h

#ifndef DFT_ONE_H
#define DFT_ONE_H
#include
#include "complex.h"
class DFT_one
{
public:
DFT_one(void);
~DFT_one(void);
bool fft(double vec[], int len); // 一维离散傅里叶变换
bool fft(Complex vec[], int len); // 一维离散傅里叶变换
bool ifft(double vec[], int len); // 一维离散傅里叶变换
bool ifft(Complex vec[], int len); // 一维离散傅里叶变换
double *idft(int &ilen); // 一维离散傅里叶逆变换
bool has_dft_vector(); // 是否已存有变换结果
void clear_dft_vector(); // 清除已有的变换结果
void clear_idft_vector();
void print(); // 打印变换结果
Complex *m_dft_vector; // 保存变换结果的容器
Complex *m_idft_vector;
QVectord1_vector;
QVectorid1_vector;
private:
bool m_has_dft_vector;
int m_dft_vector_size; // 变换结果的长度
bool m_has_idft_vector;
int m_idft_vector_size;
};
#endif // DFT_ONE_H

dft_one.cpp

#include "dft_one.h"
DFT_one::DFT_one()
{
m_dft_vector = NULL;
m_has_dft_vector = false;
m_dft_vector_size = 0;
}
DFT_one::~DFT_one(void)
{
if (m_has_dft_vector && (NULL != m_dft_vector) && (m_dft_vector_size>0))
delete[] m_dft_vector;
}
bool DFT_one::has_dft_vector()
{
return m_has_dft_vector;
}
void DFT_one::clear_dft_vector()
{
if (m_has_dft_vector && (NULL != m_dft_vector) && (m_dft_vector_size>0)) {
delete[] m_dft_vector;
m_has_dft_vector = false;
m_dft_vector_size = 0;
}
}
void DFT_one::clear_idft_vector()
{
if (m_has_idft_vector && (NULL != m_idft_vector) && (m_idft_vector_size>0)) {
delete[] m_idft_vector;
m_has_idft_vector = false;
m_idft_vector_size = 0;
}
}
void DFT_one::print()
{
if ((!m_has_dft_vector) || (NULL == m_dft_vector) || (m_dft_vector_size <= 0))
return;
for (int i = 0; i qDebug()< }
for (int i = 0; i qDebug()< }
}
bool DFT_one::fft(Complex vec[], int len)
{
this->clear_dft_vector();
this->d1_vector.clear();
int old_len=len,r=0;
if((len<=0) || (NULL==vec))
return false;
clear_dft_vector();
d1_vector.clear();
if(len&(len-1)==0){
int k=1;
while(k!=len){
r++;
k=k*2;
}
}else{
int k=1;
while(k r++;
k=k*2;
}
len=k;
}
m_dft_vector = new Complex[len];
Complex *cp=new Complex[len];
for (int u = 0; u m_dft_vector[u].SetValue(0, 0);
if(u cp[u]=vec[u];
}else{
cp[u]=Complex(0,0);
}
}
int i,j,k; // 循环变量
int bfsize,p;
double angle; // 角度
Complex *W,*X1,*X2,*X;
len = 1 < // 分配运算所需存储器
W = new Complex[len / 2];
X1 = new Complex[len];
X2 = new Complex[len];
// 计算加权系数
for(i = 0; i {
angle = -i * PI * 2 / len;
W[i] = Complex (cos(angle), sin(angle));
}
// 将时域点写入X1
for(int i=0;i X1[i]=cp[i];
}
// 采用蝶形算法进行快速付立叶变换
for(k = 0; k {
for(j = 0; j <1 < {
bfsize = 1 <<(r-k);//做蝶形运算两点间距离
for(i = 0; i {
p = j * bfsize;
X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2])
* W[i * (1< }
}
X = X1;
X1 = X2;
X2 = X;
}
// 重新排序
for(j = 0; j {
p = 0;
for(i = 0; i {
if (j&(1< {
p+=1<<(r-i-1);
}
}
m_dft_vector[j]=X1[p];
d1_vector.push_back(X1[p]);
}
delete W;
delete X1;
delete X2;
m_has_dft_vector = true;
m_dft_vector_size = len;
return true;
}
bool DFT_one::ifft(Complex vec[], int len)
{
int old_len=len,r=0;
if((len<=0) || (NULL==vec))
return false;
clear_idft_vector();
id1_vector.clear();
if(len&(len-1)==0){
int k=1;
while(k!=len){
r++;
k=k*2;
}
}else{
int k=1;
while(k r++;
k=k*2;
}
len=k;
}
m_idft_vector = new Complex[len];
Complex *cp=new Complex[len];
for (int u = 0; u m_idft_vector[u].SetValue(0, 0);
if(u cp[u]=vec[u];
}else{
cp[u]=Complex(0,0);
}
}
int i,j,k; // 循环变量
int bfsize,p;
double angle; // 角度
Complex *W,*X1,*X2,*X;
len = 1 < // 分配运算所需存储器
W = new Complex[len / 2];
X1 = new Complex[len];
X2 = new Complex[len];
// 计算加权系数
for(i = 0; i {
angle = -i * PI * 2 / len;
W[i] = Complex (cos(angle), -sin(angle));
}
// 将时域点写入X1
for(int i=0;i X1[i]=cp[i];
}
// 采用蝶形算法进行快速付立叶变换
for(k = 0; k {
for(j = 0; j <1 < {
bfsize = 1 <<(r-k);//做蝶形运算两点间距离
for(i = 0; i {
p = j * bfsize;
X2[i + p] = X1[i + p] + X1[i + p + bfsize / 2];
X2[i + p + bfsize / 2] = (X1[i + p] - X1[i + p + bfsize / 2])
* W[i * (1< }
}
X = X1;
X1 = X2;
X2 = X;
}
// 重新排序
for(j = 0; j {
p = 0;
for(i = 0; i {
if (j&(1< {
p+=1<<(r-i-1);
}
}
m_idft_vector[j]=X1[p]/len;
id1_vector.push_back(X1[p]/len);
}
delete W;
delete X1;
delete X2;
m_has_idft_vector = true;
m_idft_vector_size = len;
return true;
}
bool DFT_one::fft(double vec[], int len)
{
Complex *v=new Complex[len];
for(int i=0;i v[i]=Complex(vec[i],0);
}
bool fd=fft(v,len);
return fd;
}

dft_two.h

#ifndef DFT_TWO_H
#define DFT_TWO_H
#include "complex.h"
#include "dft_one.h"
#include
#include
#include
#include
class DFT_two
{
public:
DFT_two(void);
~DFT_two(void);
public:
bool fft2(double matrix[], int width, int height);
bool ifft2(Complex matrix[], int width, int height);
void re_normalize_spectrum(double fp[], double width, double height);
bool has_dft2_matrix(); // 是否已存有变换结果
void clear_dft2_matrix(); // 清除已有的变换结果
void clear_idft2_matrix();
void print_matrix(); // 打印变换结果
public:
Complex *m_dft2_matrix;
double max;
QVector d2_matrix;
QVector d2_data;
Complex *m_idft2_matrix;
QVector id2_data;
double *re_m_spectrum_data;
protected:
bool m_has_dft_matrix;
bool m_is_normalized;
bool m_is_spectrum_shifted;
int m_dft_matrix_height;
int m_dft_matrix_width;
bool m_has_idft_matrix;
int m_idft_matrix_height;
int m_idft_matrix_width;
};
#endif // DFT_TWO_H

dft_two.cpp

#include "dft_two.h"
DFT_two::DFT_two(){
m_dft2_matrix = NULL;
m_has_dft_matrix = false;
m_is_normalized = false;
m_is_spectrum_shifted = false;
m_dft_matrix_height = 0;
m_dft_matrix_width = 0;
}
DFT_two::~DFT_two(void)
{
if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0))
delete[] m_dft2_matrix;
}
bool DFT_two::has_dft2_matrix()
{
return m_has_dft_matrix;
}
void DFT_two::clear_dft2_matrix()
{
if (m_has_dft_matrix && (NULL != m_dft2_matrix) && ((m_dft_matrix_height*m_dft_matrix_width)>0)) {
delete[] m_dft2_matrix;
m_has_dft_matrix = false;
m_dft_matrix_height = 0;
m_dft_matrix_width = 0;
}
}
void DFT_two::clear_idft2_matrix()
{
if (m_has_idft_matrix && (NULL != m_idft2_matrix) && ((m_idft_matrix_height*m_idft_matrix_width)>0)) {
delete[] m_idft2_matrix;
m_has_idft_matrix = false;
m_idft_matrix_height = 0;
m_idft_matrix_width = 0;
}
}
void DFT_two::print_matrix()
{
if ((!m_has_dft_matrix) || (NULL == m_dft2_matrix) || (m_dft_matrix_height <= 0) || (m_dft_matrix_width <= 0))
return;
for (int u = 0; u for (int v = 0; v qDebug()< }
}
}
bool DFT_two::fft2( double matrix[], int width, int height){
if (((width*height) <= 0) || (NULL == matrix))
return false;
clear_dft2_matrix();
d2_matrix.clear();
m_dft2_matrix = new Complex[width*height];
DFT_one d1;
for(int i=0;i d1.clear_dft_vector();
d1.fft(matrix+i*width,width);
for(int j=0;j m_dft2_matrix[j+i*width]=d1.d1_vector[j];
d2_matrix.push_back(d1.d1_vector[j]);
}
}
for(int i=0;i Complex *yl=new Complex[height];
for(int j=0;j yl[j]=m_dft2_matrix[i+j*width];
}
d1.clear_dft_vector();
d1.fft(yl,height);
for(int j=0;j m_dft2_matrix[i+j*width]=d1.d1_vector[j];
d2_matrix[i+j*width]=d1.d1_vector[j];
}
}
m_has_dft_matrix = true;
m_dft_matrix_height = height;
m_dft_matrix_width = width;
return true;
}
bool DFT_two::ifft2( Complex matrix[], int width, int height){
if (((width*height) <= 0) || (NULL == matrix))
return false;
clear_idft2_matrix();
m_idft2_matrix = new Complex[width*height];
DFT_one d1;
for(int i=0;i for(int j=0;j m_idft2_matrix[j+i*width]=matrix[i*width+j];
}
}
for(int i=0;i Complex *yl=new Complex[height];
for(int j=0;j yl[j]=m_idft2_matrix[i+j*width];
}
d1.clear_idft_vector();
d1.ifft(yl,height);
for(int j=0;j m_idft2_matrix[i+j*width]=d1.id1_vector[j];
}
}
for(int i=0;i d1.clear_idft_vector();
d1.ifft(m_idft2_matrix+i*width,width);
for(int j=0;j m_idft2_matrix[j+i*width]=d1.id1_vector[j];
}
}
m_has_idft_matrix = true;
m_idft_matrix_height = height;
m_idft_matrix_width = width;
return true;
}

拿Qt做的一个图像增强


mainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "complex.h"
#include "dft_one.h"
#include "dft_two.h"
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_choiceButton_clicked();
void on_paintButton_clicked();
void on_paintButton_2_clicked();
private:
Ui::MainWindow *ui;
QString path;
QVectorimg;
int width;
int height;
QImage *res;
};
#endif // MAINWINDOW_H

mainWindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_choiceButton_clicked()
{
path = QFileDialog::getOpenFileName(this, tr("open image file"),
"./", tr("Image files(*.bmp *.jpg *.pbm *.pgm *.png *.ppm *.xbm *.xpm);;All files (*.*)"));
QPixmap p(path);
QImage image = p.toImage();
if(path.isEmpty()==false)
{
img.clear();
// ui->imgLabel->setPixmap(p.scaled(ui->imgLabel->width(),
// ui->imgLabel->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
ui->imgLabel->setPixmap(p);
警告","打开图片失败!");
return;
}
}
double H(double D2,double rH,double rL,int D0){
double c=1;
return (rH-rL)*(1-exp(-c*D2/pow(D0,2)))+rL;
}
void MainWindow::on_paintButton_clicked()
{
double rH=5,rL=0.95;
int D0=200;
int xk=2,yk=2;
while(1){
if(pow(2,xk-1)=width) break;
xk++;
}
while(1){
if(pow(2,yk-1)=height) break;
yk++;
}
int new ';
d2.ifft2(d2.m_dft2_matrix,newWidth,newHeight);
for(int i=0;i if(d2.m_idft2_matrix[i].real>255) d2.m_idft2_matrix[i].real=255;
if(d2.m_idft2_matrix[i].real<0) d2.m_idft2_matrix[i].real=0;
if(matrix[i]>255) matrix[i]=255;
if(matrix[i]<0) matrix[i]=0;
}
QImage *hz=new QImage(width, height, QImage::Format_ARGB32);
for(int i=0;i for(int j=0;j hz->setPixel(j,i,qRgb(d2.m_idft2_matrix[j+i*newWidth].real,
d2.m_idft2_matrix[j+i*newWidth].real,
d2.m_idft2_matrix[j+i*newWidth].real));
}
}
// ui->imgLabel_2->setPixmap(QPixmap::fromImage(*hz).scaled(ui->imgLabel_2->width(),
// ui->imgLabel_2->height(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
ui->imgLabel_2->setPixmap(QPixmap::fromImage(*hz));
//用于保存
res=hz;
}
void MainWindow::on_paintButton_2_clicked()
{
QString filename1 = QFileDialog::getSaveFileName(this,tr("Save Image"),"图片.bmp",tr("Images (*.png *.bmp *.jpg)")); //选择路径
res->save(filename1);
}

原图


处理后



推荐阅读
  • 如何实现织梦DedeCms全站伪静态
    本文介绍了如何通过修改织梦DedeCms源代码来实现全站伪静态,以提高管理和SEO效果。全站伪静态可以避免重复URL的问题,同时通过使用mod_rewrite伪静态模块和.htaccess正则表达式,可以更好地适应搜索引擎的需求。文章还提到了一些相关的技术和工具,如Ubuntu、qt编程、tomcat端口、爬虫、php request根目录等。 ... [详细]
  • PHP玩家基地系统毕业设计(附源码、运行环境)的用户登录界面、游戏管理和玩家作品管理
    本文介绍了一个PHP玩家基地系统的毕业设计,包括用户登录界面、游戏管理和玩家作品管理等功能。附带源码和运行环境,并提供免费赠送本源代码和数据库的方式,请私信获取详细信息。摘要共计约XXX字。 ... [详细]
  • 本文描述了作者第一次参加比赛的经历和感受。作者是小学六年级时参加比赛的唯一选手,感到有些紧张。在比赛期间,作者与学长学姐一起用餐,在比赛题目中遇到了一些困难,但最终成功解决。作者还尝试了一款游戏,在回程的路上感到晕车。最终,作者以110分的成绩取得了省一会的资格,并坚定了继续学习的决心。 ... [详细]
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • PHP图片截取方法及应用实例
    本文介绍了使用PHP动态切割JPEG图片的方法,并提供了应用实例,包括截取视频图、提取文章内容中的图片地址、裁切图片等问题。详细介绍了相关的PHP函数和参数的使用,以及图片切割的具体步骤。同时,还提供了一些注意事项和优化建议。通过本文的学习,读者可以掌握PHP图片截取的技巧,实现自己的需求。 ... [详细]
  • 关羽败走麦城时路过马超封地 马超为何没有出手救人
    对当年关羽败走麦城,恰好路过马超的封地,为啥马超不救他?很感兴趣的小伙伴们,趣历史小编带来详细的文章供大家参考。说到英雄好汉,便要提到一本名著了,没错,那就是《三国演义》。书中虽 ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • 本文介绍了使用Java实现大数乘法的分治算法,包括输入数据的处理、普通大数乘法的结果和Karatsuba大数乘法的结果。通过改变long类型可以适应不同范围的大数乘法计算。 ... [详细]
  • PHP设置MySQL字符集的方法及使用mysqli_set_charset函数
    本文介绍了PHP设置MySQL字符集的方法,详细介绍了使用mysqli_set_charset函数来规定与数据库服务器进行数据传送时要使用的字符集。通过示例代码演示了如何设置默认客户端字符集。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 橱窗设计的表现手法及其应用
    本文介绍了橱窗设计的表现手法,包括直接展示、寓意与联想、夸张与幽默等。通过对商品的折、拉、叠、挂、堆等陈列技巧,橱窗设计能够充分展现商品的形态、质地、色彩、样式等特性。同时,寓意与联想可以通过象形形式或抽象几何道具来唤起消费者的联想与共鸣,创造出强烈的时代气息和视觉空间。合理的夸张和贴切的幽默能够明显夸大商品的美的因素,给人以新颖奇特的心理感受,引起人们的笑声和思考。通过这些表现手法,橱窗设计能够有效地传达商品的个性内涵,吸引消费者的注意力。 ... [详细]
  • HDU 2372 El Dorado(DP)的最长上升子序列长度求解方法
    本文介绍了解决HDU 2372 El Dorado问题的一种动态规划方法,通过循环k的方式求解最长上升子序列的长度。具体实现过程包括初始化dp数组、读取数列、计算最长上升子序列长度等步骤。 ... [详细]
  • faceu激萌变老特效的使用方法详解
    本文介绍了faceu激萌变老特效的使用方法,包括打开faceu激萌app、点击贴纸、选择热门贴纸中的变老特效,然后对准人脸进行拍摄,即可给照片添加变老特效。操作简单,适合新用户使用。 ... [详细]
author-avatar
手机用户2502922083
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有