opencv 傅立葉變換及其逆變換例項及其理解
阿新 • • 發佈:2018-12-21
傅立葉變換是把影象從空間域轉化到頻率域的變換。
空間域
一般的情況下,空間域的影象是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; }
執行結果
接下來介紹一下執行結果
左邊到右邊,第一副影象是原圖,第二圖是幅值圖,第三副圖是逆變換後的結果
幅值圖,結果和預料的一樣
逆變換的結果顯示,多了一圈黑邊,這是因為填充後的結果