天天看點

二維離散傅裡葉變換

在學完一維的傅裡葉變換後,緊接着就是二維的傅裡葉變換了。直接上幹貨吧!!!

途中會用到opencv讀取與顯示圖檔。

一. 公式

  1. M表示圖像的行數,N表示圖像的列數。
    二維離散傅裡葉變換
  2. 經過歐拉公式可以得一下形式,這樣就可以輕松得到實部和虛部了。
    二維離散傅裡葉變換
  3. 其逆變換
    二維離散傅裡葉變換
    4. 将傅裡葉保護後的圖像中心化。隻需要在傅裡葉變換的f(x,y)前面成以一個(-1)的x+y次方就可以了。其數學推導可以自行去百度。
    二維離散傅裡葉變換
    看完上面的公式之後,下面開始程式設計實作拉,使用的是C++。

二. 程式設計實作DTF

  1. 代碼中有詳細的注釋。就不在這裡作過多的解釋了。
  2. 頭檔案包含及以下宏定義
#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。
           
  1. 類的定義
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();
};
           
  1. 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;
		}
	}
}
           
  1. 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;
		}
}
           
  1. 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);
		}
	}
}
           
  1. 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);
}
           
  1. 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);
}
           
  1. 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 !!!!

繼續閱讀