理論
傅立葉變換用于分析各種濾波器的頻率特性。對于圖像,使用?2D離散傅里葉變換(DFT)?查找頻域。快速算法稱為?快速傅立葉變換(FFT)?用于計算DFT。
Numpy中的傅立葉變換
首先,我們將看到如何使用Numpy查找傅立葉變換。Numpy具有FFT軟件包來執行此操作。np.fft.fft2()?為我們提供了頻率轉換,它將是一個復雜的數組。它的第一個參數是輸入圖像,即灰度圖像。第二個參數是可選的,它決定輸出數組的大小。如果它大于輸入圖像的大小,則在計算FFT之前用零填充輸入圖像。如果小于輸入圖像,將裁切輸入圖像。如果未傳遞任何參數,則輸出數組的大小將與輸入的大小相同。
現在,一旦獲得結果,零頻率分量(DC分量)將位于左上角。如果要使其居中,只需通過函數?np.fft.fftshift()?即可完成。(它更容易分析)。找到頻率變換后,就可以找到幅度譜。
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
f = np.fft.fft2(img)
fshift = np.fft.fftshift(f)
magnitude_spectrum = 20*np.log(np.abs(fshift))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
結果如下:
可以在中心看到更多白色區域,這表明低頻內容更多。
因此,您已經進行了頻率變換,您可以在頻域中執行一些操作,例如高通濾波和重建圖像,若進行逆DFT。為此,您需用尺寸為60x60的矩形窗口遮罩來消除低頻。然后,使用?np.fft.ifftshift()?應用反向移位,以使DC分量再次出現在左上角。然后使用?np.ifft2()?函數找到逆FFT 。同樣,結果將是一個復數。
rows, cols = img.shape
crow,ccol = rows//2 , cols//2
fshift[crow-30:crow+31, ccol-30:ccol+31] = 0
f_ishift = np.fft.ifftshift(fshift)
img_back = np.fft.ifft2(f_ishift)
img_back = np.real(img_back)
plt.subplot(131),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(img_back, cmap = 'gray')
plt.title('Image after HPF'), plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(img_back)
plt.title('Result in JET'), plt.xticks([]), plt.yticks([])
plt.show()
結果如下:
結果表明高通濾波是邊緣檢測操作。
如果您仔細觀察結果,尤其是最后一張JET顏色的圖像,您會看到一些偽像(我用紅色箭頭標記的一個實例)。它在那里顯示出一些波紋狀結構,稱為?振鈴效應?。這是由我們用于遮罩的矩形窗口引起的。此蒙版轉換為正弦形狀,從而導致此問題。因此,矩形窗口不用于過濾。更好的選擇是高斯窗口。
OpenCV中的傅立葉變換
OpenCV 為此提供了功能?cv.dft()?和?cv.idft()?。它返回與以前相同的結果,但是有兩個通道。第一個通道將具有結果的實部,第二個通道將具有結果的虛部。輸入的圖像應首先轉換為np.float32?。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.jpg',0)
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
dft_shift = np.fft.fftshift(dft)
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
注意?還可以使用?cv.cartToPolar()?一次返回大小和相位
因此,現在我們必須進行逆DFT。在上一部分中,我們創建了一個HPF,這次我們將看到如何去除圖像中的高頻內容,即我們將LPF應用于圖像。實際上會使圖像模糊。為此,我們首先創建一個在低頻時具有高值(1)的蒙版,即,我們傳遞LF含量,并在HF區域傳遞0。
rows, cols = img.shape
crow,ccol = rows/2 , cols/2
# create a mask first, center square is 1, remaining all zeros
mask = np.zeros((rows,cols,2),np.uint8)
mask[crow-30:crow+30, ccol-30:ccol+30] = 1
# apply mask and inverse DFT
fshift = dft_shift*mask
f_ishift = np.fft.ifftshift(fshift)
img_back = cv.idft(f_ishift)
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])
plt.subplot(121),plt.imshow(img, cmap = 'gray')
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img_back, cmap = 'gray')
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
plt.show()
查看結果:
注意?像往常一樣,OpenCV函數?cv.dft()?和?cv.idft()?比Numpy對應函數要快。但是Numpy功能更加人性化。
DFT的性能優化
對于某些陣列大小,DFT計算的性能更好。當陣列大小為2的冪時,它是最快的。大小為2、3和5的乘積的數組也得到了有效處理。因此,如果您擔心代碼的性能,可以在找到DFT之前將數組的大小修改為任何最佳大小(通過填充零)。對于OpenCV,您必須手動填充零。但是對于Numpy,您可以指定FFT計算的新大小,它將自動為您填充零。
那么我們如何找到這個最佳尺寸呢?OpenCV 為此提供了一個函數?cv.getOptimalDFTSize()?。它適用于?cv.dft()?和?np.fft.fft2()?。讓我們使用IPython magic命令timeit檢查它們的性能。
In [16]: img = cv.imread('messi5.jpg',0)
In [17]: rows,cols = img.shape
In [18]: print("{} {}".format(rows,cols))
342 548
In [19]: nrows = cv.getOptimalDFTSize(rows)
In [20]: ncols = cv.getOptimalDFTSize(cols)
In [21]: print("{} {}".format(nrows,ncols))
360 576
參見,將大小(342,548)修改為(360,576)。現在讓我們用零填充(對于OpenCV),并找到其DFT計算性能。您可以通過創建一個新的大零數組并將數據復制到其中來完成此操作,或者使用?cv.copyMakeBorder()?。
nimg = np.zeros((nrows,ncols))
nimg[:rows,:cols] = img
要么:
right = ncols - cols
bottom = nrows - rows
bordertype = cv.BORDER_CONSTANT #just to avoid line breakup in PDF file
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
現在,我們計算Numpy函數的DFT性能比較:
In [22]: %timeit fft1 = np.fft.fft2(img)
10 loops, best of 3: 40.9 ms per loop
In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
100 loops, best of 3: 10.4 ms per loop
它顯示了4倍的加速。現在,我們將嘗試使用OpenCV函數。
In [24]: %timeit dft1= cv.dft(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 13.5 ms per loop
In [27]: %timeit dft2= cv.dft(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)
100 loops, best of 3: 3.11 ms per loop
它還顯示了4倍的加速。可以看到OpenCV函數比Numpy函數快3倍左右。
apachecn.github.io/opencv-doc-zh/#/