Opencv實現(xiàn)傅里葉變換
傅里葉變換將圖像分解成其正弦和余弦分量,它將圖像由空域轉換為時域。任何函數(shù)都可以近似的表示為無數(shù)正弦和余弦函數(shù)的和,傅里葉變換就是實現(xiàn)這一步的,數(shù)學上一個二維圖像的傅里葉變換為:

公式中,f是圖像在空域的值,F(xiàn)是頻域的值。轉換的結果是復數(shù),但是不可能通過一個真實圖像和一個復雜的圖像或通過大小和相位圖像去顯示這樣的一個圖像。然而,在整個圖像處理算法只對大小圖像是感興趣的,因為這包含了所有我們需要的圖像幾何結構的信息。
可通過以下幾步顯示一副傅里葉變換后的圖像
1、將圖像擴展到它的最佳尺寸,DFT(直接傅里葉變換)的性能依賴于圖片的尺寸,當圖像是2,3,5的倍數(shù)時往往是最快的。因此,為了達到最優(yōu)性能通常采用墊邊界值的方法,得到一個最佳的尺寸。
2、為傅立葉變換結果的實部和虛部分配存儲空間。傅里葉變換的結果是一個復數(shù),這意味著每幅圖的結果都有一個實部和虛部,此外,頻域范圍遠遠大于它對應的空間范圍。因此,我們這些通常至少以一個浮點數(shù)格式存儲這些數(shù)值。因此,我們會將我們的輸入圖像轉換為這種類型并且擴展它與另一通道存放復數(shù)值
3、進行傅里葉變換。
4、將復數(shù)轉換為幅值,DFT的幅值由以下公式得出:
5、切換到對數(shù)刻度。對圖像進行對數(shù)尺度的縮放,結果證明,傅立葉系數(shù)矩陣的動態(tài)范圍太大,無法顯示在屏幕上,我們無法通過這樣去觀察一些小的和高的變化值。因此那些高的數(shù)值將轉化成白點而小的數(shù)值會變成黑點,使用灰度值進行可視化,我們可以將線性刻度轉換為對數(shù)刻度,以便于觀察。

6、剪切和重分布幅度圖象,第一步我們擴展了圖像,這里我們去掉擴展的那部分值,基于可視化的目的,我們還可以重新排列結果的象限,使原點(0,0)對應于與圖像中心
7、歸一化。目前得到的幅值圖像仍然太大,超出了顯示的范圍,歸一化這范圍內的值,可以進一步達到可視化的目的
實現(xiàn)程序
void _DFT(){
//1以灰度模式讀取原圖像并顯示
Mat srcImage = imread("miFan.jpg",0);
if (!srcImage.data){ cout << "Error\n"; }
imshow("原圖像", srcImage);
//2將輸入圖像擴展到最佳尺寸,邊界用0補充
int m = getOptimalDFTSize(srcImage.rows);
int n = getOptimalDFTSize(srcImage.cols);
//將添加的像素初始化為0
Mat padded;
copyMakeBorder(srcImage, padded, 0, m - srcImage.rows,
0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0));
//3為傅里葉變換的結果(實部和虛部)分配存儲空間
//將數(shù)組組合合并為一個多通道數(shù)組
Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) };
Mat complexI;
merge(planes, 2, complexI);
//4進行傅里葉變換
dft(complexI, complexI);
//5將復數(shù)轉換為幅值,即=> log(1 + sqrt(Re(DFT(I))^2 + Im(DFT(I))^2))
//將多通道數(shù)組分離為幾個單通道數(shù)組
split(complexI, planes);//planes[0] = Re(DFT(I), planes[1] = Im(DFT(I))
magnitude(planes[0], planes[1], planes[0]);
Mat magImage = planes[0];
//6進行對數(shù)尺度縮放
magImage += Scalar::all(1);
log(magImage, magImage);//求自然對數(shù)
//7剪切和重分布幅度圖象限
//若有奇數(shù)行或奇數(shù)列,進行頻譜剪裁
magImage = magImage(Rect(0, 0, magImage.cols&-2, magImage.rows&-2));
//重新排列傅立葉圖像中的象限,使得原點位于圖像中心
int cx = magImage.cols / 2;
int cy = magImage.rows / 2;
Mat q0(magImage, Rect(0, 0, cx, cy));
Mat q1(magImage, Rect(cx, 0, cx, cy));
Mat q2(magImage, Rect(0,cy,cx,cy));
Mat q3(magImage, Rect(cx,cy,cx,cy));
//交換象限(左上與右下進行交換)
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);
//交換象限(右上與左下進行交換)
q1.copyTo(tmp);
q2.copyTo(q1);
tmp.copyTo(q2);
//8歸一化,用0到1的浮點值將矩陣變換為可視的圖像格式
normalize(magImage, magImage, 0, 1, CV_MINMAX);
//9顯示
imshow("頻譜增幅", magImage);
waitKey();
}

傅里葉變換后的圖片

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
基于Matlab實現(xiàn)野狗優(yōu)化算法的示例代碼
野狗優(yōu)化算法(Dingo?Optimization?Algorithm,?DOA)模仿澳大利亞野狗的社交行為。DOA算法的靈感來源于野狗的狩獵策略,即迫害攻擊、分組策略和食腐行為。本文將通過Matlab實現(xiàn)這一算法,感興趣的可以了解一下2022-04-04
詳解C語言的exp()函數(shù)和ldexp()函數(shù)以及frexp()函數(shù)
這篇文章主要介紹了詳解C語言的exp()函數(shù)和ldexp()函數(shù)以及frexp()函數(shù),注意這三個函數(shù)雖然看起來相似但實際功能卻大相徑庭!需要的朋友可以參考下2015-08-08
C語言循環(huán)隊列與用隊列實現(xiàn)棧問題解析
循環(huán)隊列又叫環(huán)形隊列,是一種特殊的隊列。循環(huán)隊列解決了隊列出隊時需要將所有數(shù)據(jù)前移一位的問題,本篇帶你一起看看循環(huán)隊列的問題和怎樣用隊列實現(xiàn)棧2022-04-04
C語言數(shù)據(jù)結構之動態(tài)分配實現(xiàn)串
這篇文章主要介紹了C語言數(shù)據(jù)結構之動態(tài)分配實現(xiàn)串的相關資料,希望通過本文能幫助到大家,讓大家實現(xiàn)數(shù)據(jù)結構中動態(tài)分配實現(xiàn)串的實例,需要的朋友可以參考下2017-10-10

