1. 程式人生 > >opencv 傅立葉變換及其逆變換例項及其理解

opencv 傅立葉變換及其逆變換例項及其理解

傅立葉變換是把影象從空間域轉化到頻率域的變換。

空間域

一般的情況下,空間域的影象是f(x,y)=灰度級(0-255),形象一點就是一個二維矩陣,每個座標對應一個顏色值。

頻率域

先介紹幾個概念

頻率:對於影象來說可以指影象顏色值的梯度,即灰度級的變化速度

幅度:可以簡單的理解為是頻率的權,即該頻率所佔的比例

能量=幅度(可能不太準確)

變換結果為F(u,v)

F代表幅度值,u代表x方向的頻率,v代表y方向的頻率

一般會對變換結果進行一定的處理,以便以圖片的形式展現,結果就是幅度值被當作灰度級,亮的地方表示能量高

影象的主要部分集中在低頻部分,邊界和噪聲主要集中在高頻部分

由於影象變換的結果原點在邊緣部分,不容易顯示,所以會將原點移動到中心部分。

那麼結果便是中間一個亮點朝著周圍發散開來,越遠離中心位置的能量越低(越暗)。

接下來展示一下程式碼

 

#include<opencv2/opencv.hpp>
#include<iostream>
using namespace std;
using namespace cv;
int main(int a,char **p)
{
	Mat input=imread(p[1],CV_LOAD_IMAGE_GRAYSCALE);//以灰度影象的方式讀入圖片
        //如果不知到怎麼傳入p[1]。可以改為
       //Mat input=imread("image.jpg",CV_LOAD_IMAGE_GRAYSCALE);      
 imshow("input",input);//顯示原圖
	int w=getOptimalDFTSize(input.cols);
	int h=getOptimalDFTSize(input.rows);//獲取最佳尺寸,快速傅立葉變換要求尺寸為2的n次方
	Mat padded;
	copyMakeBorder(input,padded,0,h-input.rows,0,w-input.cols,BORDER_CONSTANT,Scalar::all(0));//填充影象儲存到padded中
	Mat plane[]={Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F)};//建立通道
	Mat complexIm;
	merge(plane,2,complexIm);//合併通道
	dft(complexIm,complexIm);//進行傅立葉變換,結果儲存在自身
	split(complexIm,plane);//分離通道
	magnitude(plane[0],plane[1],plane[0]);//獲取幅度影象,0通道為實數通道,1為虛數,因為二維傅立葉變換結果是複數
	int cx=padded.cols/2;int cy=padded.rows/2;//一下的操作是移動影象,左上與右下交換位置,右上與左下交換位置
	Mat temp;
	Mat part1(plane[0],Rect(0,0,cx,cy));
	Mat part2(plane[0],Rect(cx,0,cx,cy));
	Mat part3(plane[0],Rect(0,cy,cx,cy));
	Mat part4(plane[0],Rect(cx,cy,cx,cy));
	

	part1.copyTo(temp);
	part4.copyTo(part1);
	temp.copyTo(part4);
	
	part2.copyTo(temp);
	part3.copyTo(part2);
	temp.copyTo(part3);
//*******************************************************************

	
	//Mat _complexim(complexIm,Rect(padded.cols/4,padded.rows/4,padded.cols/2,padded.rows/2));
	//opyMakeBorder(_complexim,_complexim,padded.rows/4,padded.rows/4,padded.cols/4,padded.cols/4,BORDER_CONSTANT,Scalar::all(0.75));
	Mat _complexim;
	complexIm.copyTo(_complexim);//把變換結果複製一份,進行逆變換,也就是恢復原圖
	Mat iDft[]={Mat::zeros(plane[0].size(),CV_32F),Mat::zeros(plane[0].size(),CV_32F)};//建立兩個通道,型別為float,大小為填充後的尺寸
	idft(_complexim,_complexim);//傅立葉逆變換
	split(_complexim,iDft);//結果貌似也是複數
	magnitude(iDft[0],iDft[1],iDft[0]);//分離通道,主要獲取0通道
	normalize(iDft[0],iDft[0],1,0,CV_MINMAX);//歸一化處理,float型別的顯示範圍為0-1,大於1為白色,小於0為黑色
	imshow("idft",iDft[0]);//顯示逆變換
//*******************************************************************
	plane[0]+=Scalar::all(1);//傅立葉變換後的圖片不好分析,進行對數處理,結果比較好看
	log(plane[0],plane[0]);
	normalize(plane[0],plane[0],1,0,CV_MINMAX);

	imshow("dft",plane[0]);
	waitKey(100086110);
	return 0;
}
	

執行結果

 

接下來介紹一下執行結果

左邊到右邊,第一副影象是原圖,第二圖是幅值圖,第三副圖是逆變換後的結果

幅值圖,結果和預料的一樣

逆變換的結果顯示,多了一圈黑邊,這是因為填充後的結果