OpenCV 離散傅里葉變換

離散傅里葉變換(DFT)

定義

離散傅里葉變換(Discrete Fourier Transform麦锯,縮寫為DFT)骡技,是傅里葉變換在時域和頻域上都呈離散的形式柑土,將信號的時域采樣變換為其DFT的頻域采樣榛斯。

傅里葉變換

對于N點序列{X[n]}(0 <= n <= N),它的離散傅里葉變換為:

離散傅里葉變換

dft() 函數(shù)

dft()函數(shù)的作用是對一維或二維的浮點數(shù)數(shù)組進(jìn)行正向或反向的離散傅里葉變換。

函數(shù)原型

void dft(
    InoutArray src,  //輸入矩陣
    OutputArray dst, ///輸出矩陣
    int flags = 0,  //轉(zhuǎn)換的標(biāo)識符
    int onozeroRows,  
)

第三個參數(shù)永票,轉(zhuǎn)換的標(biāo)識符分為:

  • DFT_INVERSE 用一維或二維逆變換代替默認(rèn)的正向變換卵贱。
  • DFT_SCALE 縮放比例標(biāo)識符,輸出的結(jié)果都會以1 / N進(jìn)行縮放侣集。
  • DFT_CMPLEX_OUTPUT键俱、DFT_REAL_OUTPUT 進(jìn)行一維或二維的數(shù)組反變換。

返回DFT最優(yōu)尺寸大惺婪帧:getOptimalDFTSize()函數(shù)

void int getOptimalDFTSize(int vecsize);

擴(kuò)充圖像邊界:copyMakeBorder()函數(shù)

void copyMakeBorder(
    InputArray src,  //輸入圖像
    OutputArray dst,  //輸出圖像
    int top,  //在圖像上方擴(kuò)充的像素值
    int bottom,  //在圖像下方擴(kuò)充的像素值
    int left,  //在圖像左方擴(kuò)充的像素值
    int right,  //在圖像右方擴(kuò)充的像素值
    int borderType, //邊界類型·
    const Scalars,
)

計算二維矢量的幅值:magnitude()函數(shù)

用于計算二維矢量的幅值

void magnitude(
    InputArray x,  //表示矢量的浮點型X坐標(biāo)值,即實部
    InputArray y,  //表示矢量的浮點型Y坐標(biāo)值编振,即虛部
    OutputArray magnitude,  //輸出的幅值
)

計算自然對數(shù):log() 函數(shù)

log()函數(shù)的功能是計算每個數(shù)組元素絕對值的自然對數(shù)

void log(
    InputArray src,
    OutputArray dst,
);

原理即為:

if(src(I) != 0)
    log|src(I)|
else
    C

矩陣歸一化:normalize()函數(shù)

void normalize(
    InputArray src,
    OutputArray dst,
    double alpha = 1,  //歸一化之后的最大值,有默認(rèn)值1
    double beta = 0,  //歸一化之后的最大值臭埋,有默認(rèn)值0
    int norm_type = NORM_L2,  //歸一化類型
    int dtype = -1,   //為負(fù)數(shù)時輸出矩陣和src有同樣的類型踪央,否則臀玄,它和src有同樣的通道數(shù),深度為CV_MAT_DEPTH
    InputArray mask=noArray(),  //可選的操作掩模
)

getOptimalDFTSize函數(shù)

該函數(shù)返回給定向量尺寸的傅里葉最優(yōu)尺寸大小畅蹂。為了提高離散傅里葉變換的運行速度镐牺,需要擴(kuò)充圖像。

使用dft函數(shù)計算兩個二維實矩陣卷積的示例核心片段

  • 其中MulSpectrums的作用是計算兩個傅里葉頻譜的每個元素的乘法
void convolveDft(InputArray A, InputArray B, OutputArray C)
{
    //初始化輸出矩陣
    C.create(abs(A.rows - B.rows) + 1, abs(A.cols - B.cols) + 1, A.type);

    //計算DFT變換的尺寸
    dftSize.width = getOptimalDFTSize(A.cols + B.cols - 1);
    dftSize.height = getOptimalDFTSize(A.rows + B.rows - 1);

    //分配臨時緩沖區(qū)并初始化置0
    Mat tempA(dftSize,A.type(),Scalar::all(0));
    Mat tempB(dftSize,B.type(),Scalar::all(0));

    //分別復(fù)制A和B到tempA和tempB的左上角
    Mat roiA(tempA,Rect(0,0,A.cols,A.rows));
    A.copyTo(roiA);
    Mat roiB(tempB,Rect(0,0,B.cols,B.rows));
    B.copyTO(roiB);

    //就地操作魁莉,進(jìn)行快速傅里葉變換睬涧,并將nonzeroRows 參數(shù)置為零,以進(jìn)行更加快速的處理旗唁。
    dft(tempA,tempA,0,A.rows);
    dft(tempB,tempB,0,B.rows);

    //將得到的頻譜相乘畦浓,結(jié)果存放于tempA當(dāng)中
    mulSpectrums(tempA,tempB,tempA);  

    //將結(jié)果變換為頻域,盡管結(jié)果行(result.rows)都為非零检疫,我們只需其中的C.rows的第一行讶请,所以采用nonzeroRows == C.rows
    dft(tempA,tempA,EFT_INVERSE + EFT_SCALE,C.rows);

    //將結(jié)果復(fù)制到C當(dāng)中
    tempA(Rect(0,0,C.cols,C.rows)).copyTo(C);

    //所有的臨時緩存區(qū)將被自動釋放,所以無需收尾操作
}

例示程序:離散傅里葉變換

【1】載入原始圖像

//【1】ui灰度模式讀取原始圖像并顯示
Mat srcImage = imread("D:\\Desktop\\lena.jpg",0);
if (!srcImage.data)
{
    cout << "lena圖片讀取錯誤" << endl;
    return false;
}
imshow("原始圖像", srcImage);

【2】將圖像擴(kuò)大到合適的尺寸

//【2】將輸入的圖像延擴(kuò)到最佳的尺寸屎媳,邊界用0補充
int m = getOptimalDFTSize(I.rows);
int n = getOptimalDFTSize(I.cols);
//將添加的像素初始化為0
Mat padded;
copyMakeBorder(I,padded,0,m - I,rows,0,n - I.cols,BORDER_CONSTANT,Scalar::all(0));

【3】為傅里葉變換的結(jié)果分配儲存空間

傅里葉變換的結(jié)果是復(fù)數(shù)夺溢,每個原圖像值,結(jié)果會有兩個圖像值烛谊。

為傅里葉變換的結(jié)果(實部和虛部)分配儲存空間
//將planes數(shù)組組合合并成一個多通道的數(shù)組complexI
Mat planes[] = (Mat_<float>(padded),Mat::zeros(padded.size(),CV_32F));
Mat complexI;
merge(planes,2,complexI);

【4】進(jìn)行離散傅里葉變換

def(complexI,complexI);

【5】將復(fù)數(shù)轉(zhuǎn)換為幅值

離散傅里葉變換的結(jié)果是復(fù)數(shù)风响,對應(yīng)的幅值可表示為:

復(fù)數(shù)變幅值
//將復(fù)數(shù)轉(zhuǎn)換為幅值,即=> log(1 + sqrt(Re(DFT(I)) ^ 2 + Im(DFT(I)) ^ 2))
split(complexI,planes);  //將多通道complexI分離成幾個單通道數(shù)組
planes[0] = Re(DFT(I),planes[1] = Im(DFT(I))
magnitude(planes[0],planes[1],planes[0]);
Mat magnitudeImage = planes[0];

【6】進(jìn)行對數(shù)尺度縮放

傅里葉變換的幅度之范圍大到不合適在屏幕上顯示丹禀。高值在屏幕上顯示為白點状勤,而低值為黑點,高低值的變化無法有效判斷双泪。為了在屏幕上凸顯出高低變化的連續(xù)性持搜,可以用對數(shù)尺度來代替線性尺度,公式如下:

尺度縮放
//進(jìn)行對數(shù)尺度縮放
magnitudeImage += Scalar::all(1);
log(magnitudeImage,magnitudeImage);  //求自然對數(shù)

【7】剪切和重分布幅度圖像象限

因為在第二步中延擴(kuò)了圖像焙矛,那現(xiàn)在是時候?qū)⑿绿砑拥南袼靥蕹撕巍榱朔奖泔@示,可以重新分布圖像象限位置村斟。

//若有奇數(shù)行或技術(shù)列贫导,進(jìn)行譜寫裁剪
magnitudeImage = magnitudeImage(Rect(0,0,magnitudeImage.cols & -2,magnitudeImage.rows & -2));
//重新排列傅里葉圖像中的象限,使得原點位于圖像中心
int cx = magnitudeImage.cols / 2;
int cy = magnitudeImage.rows / 2;
Mat q0(magnitudeImage,Rect(0,0,cx,cy)); //ROI區(qū)域的左上
Mat q1(magnitudeImage,Rect(cx,0,cx,cy));  //ROI區(qū)域的右上
Mat q2(magnitudeImage,Rect(0,cy,cx,cy));  //ROI區(qū)域的左下
Mat q3(magnitudeImage,Rect(cx,cy,cx,cy));  //ROI區(qū)域的右下

//交換象限(左上與右下)
Mat tmp;
q0.copyTo(tmp);
q3.copyTo(q0);
tmp.copyTo(q3);

//交換象限(右上與左下)
q1.copyTo(tmp);
q4.copyTo(q1);
tmp.copyTo(q4);

【8】歸一化

現(xiàn)在有了重分布后的幅度圖邓梅,但是幅度值仍然超過可顯示范圍[0,1],我們可以使用 normalize()函數(shù)歸一化到可顯示范圍脱盲。

normalize(magnitudeImage,magnitudeImage,0,1,NORM_MINMAX);

【9】顯示效果

imshow("頻譜幅值",magnitudeImage);

效果

效果
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末日缨,一起剝皮案震驚了整個濱河市钱反,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖面哥,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哎壳,死亡現(xiàn)場離奇詭異,居然都是意外死亡尚卫,警方通過查閱死者的電腦和手機(jī)归榕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吱涉,“玉大人刹泄,你說我怎么就攤上這事≡蹙簦” “怎么了特石?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鳖链。 經(jīng)常有香客問我姆蘸,道長,這世上最難降的妖魔是什么芙委? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任逞敷,我火速辦了婚禮,結(jié)果婚禮上灌侣,老公的妹妹穿的比我還像新娘推捐。我一直安慰自己,他們只是感情好顶瞳,可當(dāng)我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布玖姑。 她就那樣靜靜地躺著愕秫,像睡著了一般慨菱。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上戴甩,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天符喝,我揣著相機(jī)與錄音,去河邊找鬼甜孤。 笑死协饲,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缴川。 我是一名探鬼主播茉稠,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼把夸!你這毒婦竟也來了而线?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎膀篮,沒想到半個月后嘹狞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡誓竿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年磅网,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片筷屡。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡涧偷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出毙死,到底是詐尸還是另有隱情嫂丙,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布规哲,位于F島的核電站跟啤,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏唉锌。R本人自食惡果不足惜隅肥,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望袄简。 院中可真熱鬧腥放,春花似錦、人聲如沸绿语。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吕粹。三九已至种柑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間匹耕,已是汗流浹背聚请。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留稳其,地道東北人驶赏。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像既鞠,于是被迫代替她去往敵國和親煤傍。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,697評論 2 351