在学完一维的傅里叶变换后,紧接着就是二维的傅里叶变换了。直接上干货吧!!!
途中会用到opencv读取与显示图片。
一. 公式
M表示图像的行数,N表示图像的列数。
2.经过欧拉公式可以得一下形式,这样就可以轻松得到实部和虚部了。
3.其逆变换
4. 将傅里叶保护后的图像中心化。只需要在傅里叶变换的f(x,y)前面成以一个(-1)的x+y次方就可以了。其数学推导可以自行去百度。
看完上面的公式之后,下面开始编程实现拉,使用的是C++。
二. 编程实现DTF
代码中有详细的注释。就不在这里作过多的解释了。
头文件包含及以下宏定义
#include<opencv2/opencv.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/core/core.hpp> #include<iostream> #include<opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; #define PI 3.1415926535 //定义π #define col 100 //图像的行数为100,再大的话运算量太大的。 #define row 100 //图像的列数为100。
类的定义
class FFT { private: double img[col][row]; //保存输入的数据,输入的数据只有实部 double re[col][row]; //保存DFT后的实部 double im[col][row]; //保存DFT后的虚部 Mat a = imread("1.jpg", 0); //读取图像 public: void init(); //将读取的图像数据写入img中 void dft(); //进行DFT变换 void idft(); //进行DFT逆变换 void reserve(); void fudu(); //计算幅度值。 void show(); };
init()函数
void FFT::init() { int b; resize(a, a, Size(100, 100)); //将图像resize到(100,100) for (int i = 0; i < 100; i++) { for (int j = 0; j < 100; j++) { b = a.at<uchar>(i, j); //得到每一个像素值 img[i][j] = b; } } }
dft()函数
void FFT::dft() { double a, b; for(int n=0;n<col;n++) for (int m = 0; m < row; m++) { a = 0.0; b = 0.0; for (int i = 0; i < col; i++) { for (int j = 0; j < row; j++) { //根据公式列表达式 a += pow(-1, i + j)*img[i][j] * cos(2 * PI*(((double(n*i) / double(col))+(double((m*j))/double(row))))); b += pow(-1, i + j)*img[i][j] * sin(2 * PI*(((double(n*i) / double(col)) + (double((m*j)) / double(row))))); } } //将计算的值写入对应的变量中,这里已经进行了中心化操作 re[n][m] = a; im[n][m] = -b; } }
idft()函数
void FFT::idft() { double a; for (int n = 0; n < col; n++) { for (int m = 0; m < row; m++) { a = 0.0; for (int i = 0; i < col; i++) { for (int j = 0; j < row; j++) { //这里只求其逆变换的实部,与原图片对比。 a += re[i][j] * cos(2 * PI*((double(n*i) / double(col)) + (double(m*j) / double(row)))) - im[i][j] * sin(2 * PI*((double(n*i) / double(col)) + (double(m*j) / double(row)))); } } re[n][m] = ((1. / (10000.))*a); } } }
fudu()函数
void FFT::fudu() { int b; for(int i=0;i<col;i++) for (int j = 0; j < row; j++) { //计算幅度值 b = sqrt(re[i][j] * re[i][j] + im[i][j] * im[i][j]); b = b / 255; //归一化到0-255 //写入Mat中,便于可视化 a.at<uchar>(i, j) = b; } //显示DTF幅度场 imshow("aa", a); waitKey(0); }
show()函数
//显示逆变换后的图像,看看与原始图像是不是一样的。 void FFT::show() { for(int i=0;i<col;i++) for (int j = 0; j < row; j++) { a.at<uchar>(i, j) = re[i][j]; } imshow("aa", a); waitKey(0); }
main()函数
int main(void) { FFT a; a.init(); a.dft(); a.idft(); a.fudu(); //a.show(); return 0; }
所有的函数都实现了,下面来看看实现的效果吧!
原始图像
DFT后的振幅场
逆变换后的图像,差距有点大O(∩_∩)O。
Thank for your reading !!!!
公众号:FPGA之旅