在學完一維的傅里葉變換後,緊接着就是二維的傅里葉變換了。直接上乾貨吧!!!
途中會用到opencv讀取與顯示圖片。
一. 公式
- M表示圖像的行數,N表示圖像的列數。
- 經過歐拉公式可以得一下形式,這樣就可以輕鬆得到實部和虛部了。
- 其逆變換
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 !!!!