图像傅里叶变换--OpenCV
傅里葉變換
? ? 傅里葉變換主要是將時間域上的信號轉變為頻率域上的信號,用來進行圖像降噪,圖像增強等處理。
? ? 對于數字圖像這種離散的信號,頻率大小表示信號變換的劇烈程度或者說信號變化的快慢。頻率越大,變換越劇烈,頻率越小,信號越平緩,對應到的圖像中,高頻信號往往是圖像中的邊緣信號和噪聲信號,而低頻信號包含圖像變化頻繁的圖像輪廓及背景燈信號。
? ? 故傅里葉變換的結果圖像中,中心的圖像表示低頻信號,邊緣的圖像代表高頻圖像,需要注意的是,原圖像和傅里葉變換結果的圖像不是一一對應的。
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]))? ? np.fft.fftshift()用于將FFT變換之后的頻譜顯示范圍從[0, N]變為:[-N/2, N/2-1](N為偶數)? 或者[-(N-1)/2, (N-1)/2](N為奇數),這一步的目的是在后續畫頻域圖時候,能將低頻部分移到中心,在使用IDFT時也需要進行這個操作。
第三句話用于計算傅里葉變換結果的幅值,Magnitude()函數的原理:
其中根號下為虛部與實部。20lg(x)是常用描述頻域的單位,故此次做這個處理。
import numpy as np import cv2 as cv from matplotlib import pyplot as pltimg = cv.imread(r'XXXXX') img = cv2.cv2.cvtColor(img, cv.COLOR_BGR2GRAY) 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()?
?從圖中可以看出,中心部分較亮,四周部分較暗,這說明圖像的低頻部分較多,高頻部分較少,這符合正常圖像的情況。
利用傅里葉變換可以完成許多操作,例如我們只提取低頻部分,然后利用反FFT重構圖像,完成模糊操作:
利用傅里葉變換進行操作:
實質上是先得到原圖像的FFT,再截取FFT圖像中的低頻部分,再IFFT得到圖像,完成模糊。
import cv2.cv2 import numpy as np import cv2 as cv from matplotlib import pyplot as pltimg = cv.imread(r'XXXXXX') img = cv2.cv2.cvtColor(img, cv.COLOR_BGR2GRAY) 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]))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] = 1 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('Vague'), plt.xticks([]), plt.yticks([]) plt.show()?
?同理可得,我們也可以得到高頻部分,很顯然,高頻部分即為邊緣:
import cv2.cv2 import numpy as np import cv2 as cv from matplotlib import pyplot as pltimg = cv.imread(r'XXXX') img = cv2.cv2.cvtColor(img, cv.COLOR_BGR2GRAY) 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]))rows, cols = img.shape crow,ccol = int(rows/2) , int(cols/2) mask = np.ones((rows,cols,2),np.uint8) mask[crow-30:crow+30, ccol-30:ccol+30] = 0 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('Vague'), plt.xticks([]), plt.yticks([]) plt.show()dft1 = cv.dft(np.float32(img_back), flags=cv.DFT_COMPLEX_OUTPUT) dft_shift1 = np.fft.fftshift(dft1) magnitude_spectrum1 = 20 * np.log(cv.magnitude(dft_shift1[:, :, 0], dft_shift1[:, :, 1])) plt.subplot(121), plt.imshow(magnitude_spectrum, cmap='gray') plt.title('Input Image'), plt.xticks([]), plt.yticks([]) plt.subplot(122), plt.imshow(magnitude_spectrum1, cmap='gray') plt.title('Vague'), plt.xticks([]), plt.yticks([]) plt.show()?
? ? ?這里有應該問題,為什么得到邊界圖像的FFT圖像仍然是中心較亮,四周較暗的模式呢?
? ? ?其實很容易想明白,這個FFT圖像還是由boundary原圖像得到的,對于傅里葉變換來說,考慮的是整幅圖像,而boundary原圖像中,黑色部分占大部分,這又構成低頻部分!
傅里葉變換優化
? ? 由于傅里葉變換的數學特性,其對圖像的長與寬有一個喜好,我們可以根據cv.getOptimalDFTSize()函數來找到這個最優的尺寸,需要注意的是,得到的尺寸是在原有尺寸的基礎上進行微量改變的。
img = cv.imread(r'XXXX') img = cv2.cv2.cvtColor(img, cv.COLOR_BGR2GRAY) rows,cols = img.shape print("{} {}".format(rows,cols)) nrows = cv.getOptimalDFTSize(rows) ncols = cv.getOptimalDFTSize(cols) print("{} {}".format(nrows,ncols))1050 750 1080 750可以看到,函數對我們的尺寸提出了改變。
那我們要怎么利用這個改變呢?有一個簡單的方法,即可以創造一些邊框來對圖像進行微量擴充:
right = ncols - cols bottom = nrows - rows img = cv.copyMakeBorder(img,0,bottom,0,right,cv.BORDER_CONSTANT, value = 0)其實實質上,拉普拉斯變化,sobel算子,scharr算子,高斯變化都可以利用傅里葉變換來解釋,但此處不再贅述。
總結
以上是生活随笔為你收集整理的图像傅里叶变换--OpenCV的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 柯杰下赢机器人_柯洁再战人工智能 大胜“
- 下一篇: 端口映射指导 ----- 配置文件方式