一、離散傅里葉變換
離散傅里葉變換是高數中的內容了,自己都不大記得具體的原理了,在這里先復習並記錄下來,方便以后查閱。英文全稱為Discrete Fourier Transform,簡稱DFT,是指傅里葉變換在時域和頻域都呈現離散的形式,將時域的信號采樣變換為在離散時間傅里葉變換頻域的采樣。在形式上做變換的兩端的序列是有限長的,實際上這兩組序列都應當被認為是離散周期信號的主值序列。即使對有限序列的信號做DTF,也應當對其進行周期延拓成為周期信號在進行變換。通常使用快速傅里葉變換來高效計算DFT。
對於一張圖片進行傅里葉變換就是將它分解為正弦和余弦兩部分,以完成從空間域到頻域的轉換。在轉換到頻域時以復數的形式存在,因此變換后的結果需要使用實數圖像和虛數圖像,或者幅度圖像加相位圖像的形式。但是在實際處理當中僅僅使用了幅度圖像(magitude Image),因為幅度圖像包含了幾乎所有的原圖像的幾何信息。但是如果想用傅里葉逆變換就需要同時保留幅度圖像和相位圖像,才能實現對原圖像的操作。
在頻域里,對於一幅圖像,高頻部分代表了圖像的、紋理信息;低頻部分則代表了圖像的輪廓信息。如果圖像受到的噪聲恰好在某個特定的頻率范圍內,就可以使用濾波器來恢復原來的圖像。因此傅里葉變換在圖像處理中可以做到圖像增強和去噪、圖像分割之邊緣檢測、圖像特征提取和壓縮等。
二、opencv傅里葉變換的處理函數
ˇdft()函數
1 void dft(InputArray src, OutputArray dst, int flags = 0, int nonzeroRows = 0);
ˇ第一個參數:InputArray類型的src,輸入矩陣,可以為實數或者虛數。
ˇ第二個參數:OutputArray類型的dst,運算結果保存在這里,其尺寸和類型取決於第三個參數
ˇ第三個參數:int類型的flags。轉換的標識符,默認值為0,取值可以為:
1 DFT_INVERSE -----> 一維或者二維逆變換 2 DFT_SCALE -----> 輸出結果以1/N進行縮放,通常結合DFT_INVERSE使用
3 DFT_ROWS -----> 對輸入矩陣的每行進性正向或者逆向變換,用於在處理多種矢量的時候用於減小資源開銷,通常用於三維或者高維變換的操作
4 DFT_COMPLEX_OUTPUT -----> 進行一維或者二維實數數組的正變換。其結果是復數陣列,擁有復數的共軛對稱性也可以寫成一個同樣尺寸的實數陣列
5 DFT_REAL_OUTPUT -----> 進行一維或二維復數數組反變換。其結果是一個同樣大小的復矩陣,如果輸入的矩陣具有共軛對稱性,便會輸出實數矩陣
ˇ第四個參數:默認為0,非0時,函數會假設只有輸入矩陣的一個非0行包含非0元素(設置了DFT_INVERSE)或只有輸出矩陣的第一個非0行包含非0元素(設置了DFT_INVERSE)。這樣的話,函數就可以對其它進行更高效的處理,以節省時間開銷,尤其是在計算矩陣卷積時非常有效。
ˇgetOPtimalDFTSize()返回DFT最優尺寸大小
1 int getOptimalDFTSize(int vecsize);
該函數的參數即向量尺寸,圖像的rows、cols
ˇcopyMakeBorder()擴充圖像邊界
1 void copyMakeBorder(InputArray src, OutPutArray dst, int top, int bottom, int left, int right, int borderType, const Scalar& value = Scalar());
ˇ第一個參數:輸入的原圖像
ˇ第二個參數:輸出結果,需和原圖片有一樣的尺寸和類型,且size大小為Size(src.cols + left + right, src.rows + top + bottom)
ˇ第三~六個參數:向四個方向擴充多少像素,例如top = 2;即向上邊界擴充兩個像素寬度的邊界
ˇ第七個參數:邊界類型,常用取值為BORDER_CONSTANT
ˇ第八個參數:默認值Scalar(),標記BORDER_CONSTANT時,改參數表示邊界值
ˇmagnitude()計算二維矢量的幅值
1 void magnitude(InputArray x, InputArray y, OutputArray maginute);
ˇ第一個參數:輸入的矢量的浮點型X坐標值,即實部
ˇ第二個參數:輸入的矢量的浮點型Y坐標值,即虛部
ˇ第三個參數:輸出的maginute,與x有相同的尺寸和類型
ˇlog()計算自然對數
1 void log(InputArray src, OuyputArray dst);
ˇ第一個參數:輸入的圖像
ˇ第二個參數:得到的對數值
ˇnormolize()矩陣歸一化
1 void normalize( InputArray src, OutputArry dst, double alpha = 1, double beta = 0, int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray() );
ˇ第一個參數:輸入的原圖像
ˇ第二個參數:運算結果的存放,與原圖像擁有相同大小和類型
ˇ第三個參數:歸一后的最大值,默認為1
ˇ第四個參數:歸一后的最大值,默認為0
ˇ第五個參數:歸一化類型,NORM_L1、NORM_L2、NORM_INF、NORM_MINMUX等
ˇ第六個參數:默認值-1,此時與src類型相同,若設置大於0折與src尺寸相同
ˇ第七個參數:可選的操作掩膜,默認noArray()
三、離散傅里葉變換測試

1 // DTF.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。 2 //采用傅里葉變換將圖片從空間域轉換到頻域 3 // 4 5 #include <iostream> 6 #include <opencv2/core/core.hpp> 7 #include <opencv2/highgui/highgui.hpp> 8 #include <opencv2/imgproc/imgproc.hpp> 9 10 using namespace std; 11 using namespace cv; 12 13 int main(int argc, char** argv) 14 { 15 system("color 2f"); 16 17 //這里必須是灰度圖片 18 Mat srcImage = imread("1.jpg", 0); 19 if (!srcImage.data) 20 { 21 cout << "載入圖片出錯" << endl; 22 return -1; 23 } 24 imshow("原圖像", srcImage); 25 26 int m = getOptimalDFTSize(srcImage.rows); 27 int n = getOptimalDFTSize(srcImage.cols); 28 29 Mat padded; 30 copyMakeBorder(srcImage, padded, 0, m - srcImage.rows, 0, n - srcImage.cols, BORDER_CONSTANT, Scalar::all(0)); 31 32 Mat planes[] = { Mat_<float>(padded), Mat::zeros(padded.size(), CV_32F) }; 33 Mat complexI; 34 merge(planes, 2, complexI); 35 36 dft(complexI, complexI); 37 38 split(complexI, planes); 39 magnitude(planes[0], planes[1], planes[0]); 40 Mat magnitudeImage = planes[0]; 41 42 magnitudeImage += Scalar::all(1); 43 log(magnitudeImage, magnitudeImage); 44 45 magnitudeImage = magnitudeImage(Rect(0, 0, magnitudeImage.cols & -2, magnitudeImage.rows & -2)); 46 int cx = magnitudeImage.cols / 2; 47 int cy = magnitudeImage.rows / 2; 48 Mat q0(magnitudeImage, Rect(0, 0, cx, cy)); 49 Mat q1(magnitudeImage, Rect(cx, 0, cx, cy)); 50 Mat q2(magnitudeImage, Rect(0, cy, cx, cy)); 51 Mat q3(magnitudeImage, Rect(cx, cy, cx, cy)); 52 53 Mat tmp; 54 q0.copyTo(tmp); 55 q3.copyTo(q0); 56 tmp.copyTo(q3); 57 58 q1.copyTo(tmp); 59 q2.copyTo(q1); 60 tmp.copyTo(q2); 61 62 normalize(magnitudeImage, magnitudeImage, 0, 1, NORM_MINMAX); 63 imshow("頻譜賦值", magnitudeImage); 64 waitKey(); 65 66 67 return 0; 68 }
累了累了休息會