OpenCV中對影象進行二維離散傅立葉變換
#include <highgui.h>
#include <iostream>
#include <cv.h>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
using namespace std;
int main ()
{
//第一步,讀入影象,進行錯誤檢測
Mat src=imread("logo.png",0); //千萬不要忘了讀取的是灰度影象!!!!
if(!src.data)
cout<<"wrong"<<endl;
//第二步,利用函式getOptimalDFTSize獲取最佳的DFT尺寸,並且利用copymakeBorder補充影象
int a=getOptimalDFTSize (src.rows);
int b=getOptimalDFTSize (src.cols); //當影象的尺寸是2,3,5的整數倍時,計算速度最快。
Mat padded;
copyMakeBorder (src,padded,0,a-src.rows,0,b-src.cols,BORDER_CONSTANT,Scalar::all(0));
//第三步,用兩個容器合成一個東西,去儲存傅立葉變換的結果,結果是虛部和實部;
//cout<<padded.size()<<endl;
Mat kong=Mat::zeros(padded.size(),CV_32F);
padded.convertTo(padded,CV_32F);
Mat planes[] = {padded,kong};
Mat complex;
merge(planes,2,complex);
cout<<"type="<<complex.type()<<endl;
//Mat planes[2];
// planes[0]=Mat::zeros(padded.size(), CV_32F);
// planes[1]=Mat::zeros(padded.size(), CV_32F);
//Mat complex;
//merge(planes,2,complex);
//cout<<complex<<endl;
//第四步,dft()
dft(complex,complex);
cout<<"dft()之後,comlpex"<<complex<<endl;
//第五步,magniude()函式計算幅度值,將幅度值對數化
split(complex,planes);
magnitude(planes[0],planes[1],planes[0]);
Mat magtitudeImg=planes[0];
magtitudeImg+=Scalar::all(1);
log(magtitudeImg,magtitudeImg);
//第六步,減去補充部分
magtitudeImg=magtitudeImg(Rect(0,0,magtitudeImg.cols&-2,magtitudeImg.rows&-2));
//我們知道x&-2代表x與-2按位相與,而-2的二進位制形式是2的二進位制取反加一的結果(這是補碼的問題)。2 的二進位制結果是(假設用8位表示,實際整型是32位,但是描述方式是一樣的,為便於描述,用8位表示)0000 0010,則-2的二進位制形式為:1111 1110,在x與-2按位相與後,不管x是奇數還是偶數,最後x都會變成一個偶數。
//cout<<"magtitudeImg.size="<<magtitudeImg.size();//第七步,座標中心化
int cx=magtitudeImg.cols/2;
int cy=magtitudeImg.rows/2;
Mat xiangxian1=magtitudeImg(Rect(0,0,cx,cy));
Mat xiangxian2=magtitudeImg(Rect(cx,0,cx,cy));
Mat xiangxian3=magtitudeImg(Rect(0,cy,cx,cy));
Mat xiangxian4=magtitudeImg(Rect(cx,cy,cx,cy));
Mat temp1;
temp1=xiangxian1.clone();
xiangxian1=xiangxian4.clone();
xiangxian4=temp1.clone();
temp1=xiangxian2.clone();
xiangxian2=xiangxian3.clone();
xiangxian3=temp1.clone();
//cout<<magtitudeImg<<endl;
//第八步,歸一化,並顯示影象
normalize(magtitudeImg,magtitudeImg,0,1,NORM_MINMAX);
imshow("dd",magtitudeImg);
waitKey(0);
}
易錯點:寫這個程式,出現的最大錯誤是,讀入圖片時沒有進行灰度化,所以導致後面merge等函式連連出錯。
主要問題:理解這個程式的內在,主要還需要理解三個問題:
1.傅立葉變換的內在原理
通俗的說:離散情況下,傅立葉變換一定存在。岡薩雷斯版<影象處理>裡面的解釋非常形象:一個恰當的比喻是將傅立葉變換比作一個玻璃稜鏡。稜鏡是可以將光分解為不同顏色的物理儀器,每個成分的顏色由波長(或頻率)來決定。傅立葉變換可以看作是數學上的稜鏡,將函式基於頻率分解為不同的成分。傅立葉變換的物理意義是將影象的灰度分佈函式變換為影象的頻率分佈函式,傅立葉逆變換是將影象的頻率分佈函式變換為灰度分佈函式。
從數學的角度說:
2.對頻譜進行歸一化的原因
函式歸一化輸入陣列使它的範數或者數值範圍在一定的範圍內,最後一個引數的意義是:
NORM_MINMAX:陣列的數值被平移或縮放到一個指定的範圍,線性歸一化,一般較常用。
NORM_INF: 此型別的定義沒有查到,根據OpenCV 1的對應項,可能是歸一化陣列的C-範數(絕對值的最大值)
NORM_L1 :歸一化陣列的L1-範數(絕對值的和)
NORM_L2:歸一化陣列的(歐幾里德)L2-範數
這裡NORM_MINMAX的數學過程是:
dst(i,j)=(src(i,j)-min(src))*(b‘-a‘)/(max(src)-min(src))+ a‘
其中b‘=MAX(a,b), a‘=MIN(a,b);
3.平移頻譜的原因
dft()直接獲得的結果中,低頻部分位於四角,高頻部分位於中間,這樣做是為了將中點移到中心處。為什麼要對傅立葉變換的結果進行座標轉換,才能看到那種中間亮,周圍暗的頻率圖。這是因為對於正常的傅立葉變換,其變換的結果都是在0~2*pi之間的,如果將其轉換為-pi~pi之間,實質上是沒有變化的,但是為了方便人觀察,才將結果轉換到-pi~pi中。