第14章:傅里叶变换
第14章:傅里葉變換
- 一、理論基礎:
- 二、Numpy實現傅里葉變換:
- 1. 實現傅里葉變換:
- 2. 逆傅里葉變換:
- 3. 高通濾波示例:
- 三、OpenCV實現傅里葉變換:
- 1. 實現傅里葉變換:
- 2. 實現逆傅里葉變換:
- 3. 低通濾波示例:
圖像處理一般分為空間域處理和頻率域處理。
空間域:
空間域處理是直接對圖像內的像素點進行處理。空間域處理主要劃分為灰度變換和空間濾波兩種形式。灰度變換是對圖像內的單個像素進行處理,比如調節對比度和處理域值等。空間濾波涉及圖像的質量改變,比如圖像平滑處理。空間域處理的計算簡單方便,運算速度更快。
頻率域:
頻率域處理是先將圖像變換的頻率域,然后在頻率域對圖像進行處理,最后在通過反變換將圖像從頻率域變換到空間域。傅里葉變換是應用最廣泛的一種頻域變換,它能夠將圖像從空間域變換到頻率域,而你傅里葉變換能夠將頻率域信息變換到空間域內。傅里葉變換在圖像處理領域有著非常重要的作用。
下面從理論基礎、基本實現、具體應用等角度對傅里葉變回進行簡單的介紹。
一、理論基礎:
傅里葉變換非常抽象,很多人在工程中用了很多年的傅里葉變換也沒有徹底了解傅里葉變回到底是怎么回事。為了更好的說明傅里葉變換,我們先看生活中的一個例子。
下表所示是某飲料的配方,該配方是一個以時間形式表示的表格,表格很長,這里僅僅截取了其中一部分。該表中記錄沖時刻“00:00”開始到某個特定時間“00:11”內的操作。
分析表格發現,該配方:
- 每隔1分鐘放一塊冰糖。
- 每隔2分鐘放3粒紅豆。
- 每隔3分鐘放2粒綠豆。
- 每隔4分鐘放4塊西紅柿。
- 每隔5分鐘放1杯純凈水。
上述文字是從操作頻率的角度對配方進行說明。
在數據處理過程中,經常使用圖表的形式表述信息。如果從時域的角度,該配方表可以表示為如下圖形式。
如果從頻率(周期)的角度表示,這個配方表可以表示為如下圖形式,圖中橫坐標是周期(頻率的倒數),縱坐標是配料的份數。
對于函數,同樣可以將其從時域變換到頻域。下圖是一個頻率為5(1秒5個周期)、振幅為1的正弦曲線。
如果從頻率的角度考慮,則可以將其繪制為如下圖所示的頻域圖。圖中橫坐標是頻率,縱坐標是振幅。
上述兩圖是等價的,他們是一個函數的兩種不同表示方式。可以通過頻域表示得到對應的時域表示,也可以通過時域表示得到對應的頻域表示。
法國數學家傅里葉指出,任何周期函數都可以表示為不同頻率的正弦函數和的形式。在今天看來,這個理論是理所當然的,但是這個理論難以理解,在但是遭受了很大的質疑。
下面我們來看傅里葉變換的具體過程。例如,周期函數的曲線如下圖左上角所示。該周期函數可以表示為:
- y = 3 * np.sin(0.8 * x) + 7 * np.sin(0.5 * x) +2 * np.sin(0.2 * x)
因此,該函數可以看成是由下列三個函數的和構成的:
- y1 = 3 * np.sin(0.8 * x)
- y2 = 7 * np.sin(0.5 * x)
- y3 = 2 * np.sin(0.2 * x)
上述三個函數對應的函數曲線分別如下圖右上角、左下角、右下角的圖所示。
如果從頻域的角度考慮,上述三個正弦函數可以分別表示為下圖中的三根柱子,圖中橫坐標是頻率,縱坐標是振幅。
通過以上分析可知,圖中左上角的曲線可以表示為上圖所示的頻域圖。
從左上角的時域函數圖形,構造出上圖所示頻域圖像的過程,就是傅里葉變換。
左上角的時域函數圖形,與上圖的頻域圖形表示的是完全相同的信息。傅里葉變換就是從頻域的角度完整地表述時域信息。
除了上述的頻率和振幅外,還要考慮時間的問題。例如,飲料配方為了控制風味,需要嚴格控制加入配料的時間。上表中“00:00”時刻的操作,在更精細的控制下,實際上如下表所示。
如果加入配料的時間發生了變換,飲料的風味就會發生變化。所以,在實際處理過程中,還要考慮時間差。這個時間差,在傅里葉變換中就是相位。相位表述的時域時間差相關的信息。
例如,函數
- y = 3 * np.sin(0.8 * x) + 7 * np.sin(0.5 * 2 + 2) + 2 * np.sin(0.2 * x + 2)
可以看成下列三個函數的和的形式:
- y1 = 3 * np.sin(0.8 * x)
- y2 = 7 * np.sin(0.5 * x + 2)
- y3 = 2 * np.sin(0.2 * x + 3)
上述的四個函數分別對應的函數曲線為下圖中的左上角、右上角、左下角、右下角。
? 在本例中,如果把橫坐標看成開始時間,則構成函數y的三個正弦函數并不都是從0時刻開始的,他們之間存在時間差。如果直接使用沒有時間差的函數,則無法構成上圖左上角所示的函數,而是會構成前面我們所說到的那個周期函數y = 3 * np.sin(0.8 * x) + 7 * np.sin(0.5 * x) +2 * np.sin(0.2 * x)。所以,相差是傅里葉變換中一個非常重要的條件。
? 上面分別用飲料配方和函數的例子介紹了時域與頻域轉換的可行性,以幫助我們來理解傅里葉變換。
? 在圖形處理過程中,傅里葉變換就是將圖像分解成正弦分量和余弦分量兩部分,即將圖像從空間域轉換到頻率域。 數字圖像經過傅里葉變換后,得到的頻域是復數。因此,顯示傅里葉變換的結果需要使用實數圖像(real image)加虛數圖像(complex image),或者幅度圖像(magnitude image)加相位圖像(phase image)的形式。
? 因為幅度圖像中包含了原圖我們所需要的大部分信息,所以圖像處理過程中,通常僅使用幅度圖像。當然,如果希望在頻域內對圖像進行處理,在通過逆傅里葉變換得到修改后的空域圖像。就必須同時保留幅度圖像和相位圖像。
? 對圖像進行傅里葉變換后,我們會得到圖像中低頻和高頻的信息。低頻信息對應圖像中變化緩慢的灰度分量。高頻信息對應圖像內變換越來越快的灰度分量,是由灰度的尖銳過渡造成的。例如,在一幅大草原的圖像中,低頻信息就對應著廣袤的顏色趨于一致的草原等細節信息,而高頻信息則對應著獅子的輪廓等各種邊緣及噪聲信息。
? 傅里葉變換的目的,就是為了將圖像從空域轉換到頻域,并在頻域內實現對圖像的特定處理,然后再對經過處理的頻域圖像進行逆傅里葉變換得到空域圖像。 傅里葉變換在圖像處理領域發揮著非常關鍵的作用,可以實現圖像增強、圖像去噪、邊緣檢測、特征提取、圖像壓縮和加密等。
二、Numpy實現傅里葉變換:
Numpy模塊提供了傅里葉變換功能,Numpy模塊中的fft2()函數可以實現圖像的傅里葉變換。本節介紹如何用Numpy模塊實現圖像的傅里葉變換,以及在頻域內過濾圖像的低頻信息,保留高頻信息,實現高通濾波。
1. 實現傅里葉變換:
Numpy模塊提供了實現傅里葉變換的函數numpy.fft.fft2(),它的語法格式是:
- 返回值=numpy.fft.fft2(原始圖像)
這里需要注意的是,參數“原始圖像”的類型是灰度圖像,函數的返回值是一個復數數組(complex ndarray)。
? 經過該函數的處理,就能得到圖像的頻譜信息。此時,圖像頻譜中的零頻率分量位于頻譜圖像(頻域圖像)的左上角,為了便于觀察,通常會使用numpy.fft.fftshift()函數將零頻率成分移動到頻域圖像的中心位置,如圖所示。
函數numpy.fft.fftshift()的語法格式是:
- 返回值=numpy.fft.fftshift(原始頻譜)
? 使用該函數處理后,圖像頻譜中的零頻率分量會被移到頻域圖像的中心位置,對于觀察傅里葉變換后頻譜中的零頻率部分非常有效。
? 對圖像進行傅里葉變換后,得到的是一個復數數組。為了顯示為圖像,需要將它們的值調整到[0,255]的灰度空間內,使用的公式為:
- 像素新值=20*np.log(np.abs(頻譜值))
示例1:實現傅里葉變換
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../lena.bmp', 0)f = np.fft.fft2(img) fshift = np.fft.fftshift(f) magnitude_spectrum = 20 * np.log(np.abs(fshift))plt.subplot(1, 2, 1) plt.imshow(img, cmap='gray') plt.title('original') plt.axis('off')plt.subplot(1, 2, 2) plt.imshow(magnitude_spectrum, cmap='gray') plt.title('result') plt.axis('off') plt.show()2. 逆傅里葉變換:
? 需要注意的是,如果在傅里葉變換過程中使用了numpy.fft.fftshift()函數移動零頻率分量,那么在逆傅里葉變換過程中,需要先使用numpy.fft.ifftshift()函數將零頻率分量移到原來的位置,再進行逆傅里葉變換。
函數numpy.fft.ifftshift()是numpy.fft.fftshift()的逆函數,其語法格式為:
- 調整后的頻譜=numpy.fft.ifftshift(原始頻譜)
numpy.fft.ifft2()函數是numpy.fft.fft2()的逆函數。用來實現逆傅里葉變換,返回空域的復數數組。該函數的語法格式為:
- 返回值=numpy.fft.ifft2(頻域數據)
函數numpy.fft.ifft2()的返回值仍舊是一個復數數組(complex ndarray)。
逆傅里葉變換得到的空域信息是一個復數數組,需要將該信息調整至[0,255]灰度空間內,使用的公式為:
- iimg=np.abs(逆傅里葉變換結果)
示例1:實現逆傅里葉變換
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../boat.512.tiff', 0) f = np.fft.fft2(img) fshift = np.fft.fftshift(f) magnitude_spectrum = 20 * np.log(np.abs(fshift))ishift = np.fft.ifftshift(fshift) iimg = np.fft.ifft2(ishift) iimg = np.abs(iimg)plt.subplot(131) plt.imshow(img, cmap='gray') plt.title('img') plt.axis('off')plt.subplot(132) plt.imshow(magnitude_spectrum, cmap='gray') plt.title('fft2') plt.axis('off')plt.subplot(133) plt.imshow(iimg, cmap='gray') plt.title('iimg') plt.axis('off') plt.show()3. 高通濾波示例:
在一幅圖像內,同時存在著高頻信號和低頻信號。
- 低頻信號對應圖像內變化緩慢的灰度分量。例如,在一幅大草原的圖像中,低頻信號對應著顏色趨于一致的廣袤草原。
- 高頻信號對應圖像內變化越來越快的灰度分量,是由灰度的尖銳過渡造成的。如果在上面的大草原圖像中還有一頭獅子,那么高頻信號就對應著獅子的邊緣等信息。
濾波器能夠允許一定頻率的分量通過或者拒絕其通過,按照其作用方式可以劃分為低通濾波器和高通濾波器。
- 允許低頻信號通過的濾波器稱為低通濾波器。低通濾波器使高頻信號衰減而對低頻信號放行,會使圖像變模糊。
- 允許高頻信號通過的濾波器稱為高通濾波器。高通濾波器使低頻信號衰減而讓高頻信號通過,將增強圖像中尖銳的細節,但是會導致圖像的對比度降低。
? 傅里葉變換可以將圖像的高頻信號和低頻信號分離。 例如,傅里葉變換可以將低頻信號放置到傅里葉變換圖像的中心位置,如前圖所示,低頻信號位于右圖的中心位置。可以對傅里葉變換得到的高頻信號和低頻信號分別進行處理,例如高通濾波或者低通濾波。在對圖像的高頻或低頻信號進行處理后,再進行逆傅里葉變換返回空域,就完成了對圖像的頻域處理。通過對圖像的頻域處理,可以實現圖像增強、圖像去噪、邊緣檢測、特征提取、壓縮和加密等操作。
? 例如,在下圖所示,左圖original是原始圖像,中間的圖像result是對左圖original進行傅里葉變化后得到的結果,右圖則是對result進行高通濾波后的結果。將傅里葉變換結果圖像result中的低頻分量值都替換為0(處理為黑色),就屏蔽了低頻信號,只保留高頻信號,實現高通濾波。
要將上圖中右圖中間的像素值都置零,需要先計算其中心位置的坐標,然后選取以該坐標為中心,上下左右各30個像素大小的區域,將這個區域內的像素值置零。該濾波器的實現方法為:
-
rows,cols=img.shape
crow,ccol=int(rows/2),int(cols/2)
fshift[crow-30:crow+30,ccol-30:ccol+30]=0
三、OpenCV實現傅里葉變換:
OpenCV提供了函數cv2.dft()和cv2.idft()來實現傅里葉變換和逆傅里葉變換。
1. 實現傅里葉變換:
OpenCV中使用函數cv2.dft()進行傅里葉變換,語法格式為:
- 返回結果=cv2.dft(原始圖像,轉換標識)
在使用該函數時,需要注意參數的使用規范:
- 對于參數“原始圖像”,要首先使用np.float32()函數將圖像轉換成np.float32格式。
- “轉換標識”的值通常為“cv2.DFT_COMPLEX_OUTPUT”,用來輸出一個復數陣列。
? 函數cv2.dft()返回的結果與使用Numpy進行傅里葉變換得到的結果是一致的,但是它返回的值是雙通道的,第1個通道是結果的實數部分,第2個通道是結果的虛數部分。
? 經過函數 cv2.dft()的變換后,我們得到了原始圖像的頻譜信息。此時,零頻率分量并不在中心位置,為了處理方便需要將其移至中心位置,可以用函數numpy.fft.fftshift()實現。例如,如下語句將頻譜圖像 dft 中的零頻率分量移到頻譜中心,得到了零頻率分量位于中心的頻譜圖像dftshift。
- dftShift=np.fft.fftshift(dft)
? 經過上述處理后,頻譜圖像還只是一個由實部和虛部構成的值。要將其顯示出來,還要做進一步的處理才行。
函數cv2.magnitude()可以計算頻譜信息的幅度。該函數的語法格式為:
- 返回值=cv2.magnitude(參數1,參數2)
- 參數1:浮點型x坐標值,也就是實部。
- 參數2:浮點型y坐標值,也就是虛部,它必須和參數1具有相同的大小(size值的大小,不是value值的大小)。
函數cv2.magnitude()的返回值是參數1和參數2的平方和的平方根,公式為:
I表示原始圖像,dst表示目標圖像。
得到頻譜信息的幅度后,通常還要對幅度值做進一步的轉換,以便將頻譜信息以圖像的形式展示出來。簡單來說,就是需要將幅度值映射到灰度圖像的灰度空間[0,255]內,使其以灰度圖像的形式顯示出來。
這里使用的公式為:
- result=20*np.log(cv2.magnitude(實部,虛部))
示例1:
import cv2 import numpy as npimg = cv2.imread('../lena.bmp', 0) dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft)result = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))print(dft) print(dft_shift) print(result)示例2:用OpenCV函數對圖像進行傅里葉變換,并展示其頻譜信息。
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../lena.bmp', 0) dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft) result = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1])) plt.subplot(121) plt.imshow(img, cmap='gray') plt.title('original') plt.axis('off')plt.subplot(122) plt.imshow(result, cmap='gray') plt.title('result') plt.axis('off')plt.show()2. 實現逆傅里葉變換:
在OpenCV中,使用函數cv2.idft()實現逆傅里葉變換,該函數是傅里葉變換函數cv2.dft()的逆函數。其語法格式為:
- 返回結果=cv2.idft(原始數據)
? 對圖像進行傅里葉變換后,通常會將零頻率分量移至頻譜圖像的中心位置。如果使用函數numpy.fft.fftshift()移動了零頻率分量,那么在進行逆傅里葉變換前,要使用函數numpy.fft.ifftshift()將零頻率分量恢復到原來位置。
注意,在進行逆傅里葉變換后,得到的值仍舊是復數,需要使用函數cv2.magnitude()計算其幅度。
示例:
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../boat.512.tiff', 0) dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft)rst = 20 * np.log(cv2.magnitude(dft_shift[:, :, 0], dft_shift[:, :, 1]))ishift = np.fft.ifftshift(dft_shift) iimg = cv2.idft(ishift) iimg = cv2.magnitude(iimg[:, :, 0], iimg[:, :, 1])plt.subplot(131) plt.imshow(img, cmap='gray') plt.title('original') plt.axis('off')plt.subplot(132) plt.imshow(rst, cmap='gray') plt.title('rst') plt.axis('off')plt.subplot(133) plt.imshow(iimg, cmap='gray') plt.title('iimg') plt.axis('off')plt.show()3. 低通濾波示例:
? 前面講過,在一幅圖像內,低頻信號對應圖像內變化緩慢的灰度分量。例如,在一幅大草原的圖像中,低頻信號對應著顏色趨于一致的廣袤草原。低通濾波器讓高頻信號衰減而讓低頻信號通過,圖像進行低通濾波后會變模糊。
? 例如,在下圖中,左圖original是原始圖像,中間的圖像result是對original進行傅里葉變換后得到的結果,右圖是低通濾波后的圖像。將傅里葉變換結果圖像result中的高頻信號值都替換為0(處理為黑色),就屏蔽了高頻信號,只保留低頻信號,從而實現了低通濾波。
在實現低通濾波時,可以專門構造一個如下圖左圖所示的掩碼圖像,用它與原圖的傅里葉變換頻譜圖像進行與運算,就能將頻譜圖像中的高頻信號過濾掉。
import cv2 import numpy as np import matplotlib.pyplot as pltimg = cv2.imread('../boat.512.tiff', 0) dft = cv2.dft(np.float32(img), flags=cv2.DFT_COMPLEX_OUTPUT) dft_shift = np.fft.fftshift(dft)rows, cols = img.shape crow, ccol = int(rows / 2), int(cols / 2) mask = np.zeros((rows, cols, 2), np.uint8) mask[crow - 30: crow + 30, ccol - 30: ccol + 30] = 1f_shift = dft_shift * mask print(f_shift)# mask = np.zeros((rows, cols), np.uint8) # mask[crow - 30: crow + 30, ccol - 30: ccol + 30] = 1 # f_shift = cv2.bitwise_and(dft_shift, dft_shift, mask=mask) # print(f_shift)ishift = np.fft.ifftshift(f_shift) iimg = cv2.idft(ishift) iimg = cv2.magnitude(iimg[:, :, 0], iimg[:, :, 1])plt.subplot(121) plt.imshow(img, cmap='gray') plt.title('original') plt.axis('off')plt.subplot(122) plt.imshow(iimg, cmap='gray') plt.title('iimg') plt.axis('off')plt.show()總結
以上是生活随笔為你收集整理的第14章:傅里叶变换的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: unity算法面试_Unity面试准备
- 下一篇: FlexPod上安装vSphere 5.