【OpenCV 例程300篇】250. 梯度算子的传递函数
『youcans 的 OpenCV 例程300篇 - 總目錄』
【youcans 的 OpenCV 例程300篇】250. 梯度算子的傳遞函數
1. 空間卷積與頻域濾波
空間域圖像濾波是圖像與濾波器核的卷積,而空間卷積的傅里葉變換是頻率域中相應變換的乘積,因此頻率域圖像濾波是頻率域濾波器(傳遞函數)與圖像的傅里葉變換相乘。頻率域中的濾波概念更加直觀,濾波器設計也更容易。
對于二維圖像處理,通常使用 x,yx, yx,y 表示離散的空間域坐標變量,用 u,vu,vu,v 表示離散的頻率域變量。二維離散傅里葉變換(DFT)和反變換(IDFT)為:
F(u,v)=∑x=0M?1∑y=0N?1f(x,y)e?j2π(ux/M+vy/N)f(x,y)=1MN∑u=0M?1∑v=0N?1F(u,v)ej2π(ux/M+vy/N)\begin{aligned} F(u,v) &= \sum_{x=0}^{M-1} \sum_{y=0}^{N-1} f(x,y) e^{-j 2\pi (ux/M+vy/N)}\\ f(x,y) &= \frac{1}{MN} \sum_{u=0}^{M-1} \sum_{v=0}^{N-1} F(u,v) e^{j 2\pi (ux/M+vy/N)} \end{aligned} F(u,v)f(x,y)?=x=0∑M?1?y=0∑N?1?f(x,y)e?j2π(ux/M+vy/N)=MN1?u=0∑M?1?v=0∑N?1?F(u,v)ej2π(ux/M+vy/N)?
空間取樣和頻率間隔是相互對應的,頻率域所對應的離散變量間的間隔為:Δu=1/MΔT,Δv=1/NΔZ\Delta u = 1/M \Delta T,\Delta v = 1/N \Delta ZΔu=1/MΔT,Δv=1/NΔZ。即:頻域中樣本之間的間隔,與空間樣本之間的間隔及樣本數量的乘積成反比。
空間域濾波器和頻率域濾波器也是相互對應的,形成一個傅里葉變換對:
f(x,y)?h(x,y)?F(u,v)H(u,v)f(x,y)h(x,y)?F(u,v)?H(u,v)f(x,y) \otimes h(x,y) \Leftrightarrow F(u,v)H(u,v) \\f(x,y) h(x,y) \Leftrightarrow F(u,v) \otimes H(u,v) f(x,y)?h(x,y)?F(u,v)H(u,v)f(x,y)h(x,y)?F(u,v)?H(u,v)
這表明 F 和 H 分別是 f 和 h 的傅里葉變換;f 和 h 的空間卷積的傅里葉變換,是它們的變換的乘積。
因此,計算兩個函數的空間卷積,可以直接在空間域計算,也可以在頻率域計算:先計算每個函數的傅里葉變換,再對兩個變換相乘,最后進行傅里葉反變換轉換回空間域。
也就是說,空間域濾波器和頻率域濾波器實際上是相互對應的,也是可以相互轉換的。空間域濾波的核心是卷積核,頻域濾波的核心是構造濾波器的傳遞函數。有些空間域濾波器在頻率域通過傅里葉變換實現會更方便、更快速。
在空間濾波中,除Laplacian算子之外還討論了Sobel算子、Scharr算子,但在頻域濾波中卻很少提及。這是因為空間濾波中的平滑(模糊)/銳化的概念,與頻域濾波中的低通濾波/高通濾波雖然相似,也有密切聯系,但在本質上卻是不同的。平滑濾波相當于低通濾波,但銳化與高通濾波是不同的。
對空間濾波器核進行傅里葉變換,得到空間濾波器在頻域的傳遞函數,可以清晰和直觀地理解二者的聯系和區別。
2. 梯度算子在空間域的卷積核
2.1 拉普拉斯卷積核(Laplacian)
各向同性卷積核的響應與方向無關。最簡單的各向同性導數算子(卷積核)是拉普拉斯算子(Laplace):
K1=[0101?41010],K2=[1111?81111],K3=[0?10?14?10?10],K4=[?1?1?1?18?1?1?1?1]K1= \begin{bmatrix} 0 & 1 &0\\ 1 & -4 &1\\ 0 & 1 &0\\ \end{bmatrix}, \ K2= \begin{bmatrix} 1 & 1 &1\\ 1 & -8 &1\\ 1 & 1 &1\\ \end{bmatrix}, \ K3= \begin{bmatrix} 0 & -1 &0\\ -1 & 4 &-1\\ 0 & -1 &0\\ \end{bmatrix}, \ K4= \begin{bmatrix} -1 & -1 &-1\\ -1 & 8 &-1\\ -1 & -1 &-1\\ \end{bmatrix} K1=???010?1?41?010????,?K2=???111?1?81?111????,?K3=???0?10??14?1?0?10????,?K4=????1?1?1??18?1??1?1?1????
2.2 Sobel 梯度算子
Sobel 算子是一種離散的微分算子,是高斯平滑和微分求導的聯合運算,抗噪聲能力強。
Sobel 梯度算子利用局部差分尋找邊緣,計算得到梯度的近似值。
Sobel 梯度算子的卷積核為:
Kx=[?101?202?101],Ky=[?1?2?1000121]K_x = \begin{bmatrix} -1 & 0 &1\\ -2 & 0 &2\\ -1 & 0 &1\\ \end{bmatrix}, \ K_y = \begin{bmatrix} -1 &-2 &-1\\ 0 &0 &0\\ 1 &2 &1\\ \end{bmatrix} Kx?=????1?2?1?000?121????,?Ky?=????101??202??101????
2.3 Scharr 梯度算子
Scharr 算子是 Soble 算子在 ksize=3 時的優化,與 Soble 的速度相同,且精度更高。Scharr 算子與 Sobel 算子的不同點是在平滑部分,其中心元素占的權重更重,相當于使用較小標準差的高斯函數,也就是更瘦高的模板。
Scharr 算子的卷積核為:
Gx=[?303?10010?303],Gy=[?310?300103103]G_x = \begin{bmatrix} -3 & 0 &3\\ -10 & 0 &10\\ -3 & 0 &3\\ \end{bmatrix}, \ G_y = \begin{bmatrix} -3 &10 &-3\\ 0 &0 &10\\ 3 &10 &3\\ \end{bmatrix} Gx?=????3?10?3?000?3103????,?Gy?=????303?10010??3103????
3. 【例程】梯度算子的傳遞函數
本例程給出由空間濾波器核計算頻域傳遞函數的子程序,比較常用空間域濾波器和梯度算子的傳遞函數。
import cv2 as cv import numpy as np from matplotlib import pyplot as pltdef getTransferFun(kernel, r): # 計算濾波器核的傳遞函數hPad, wPad = r-kernel.shape[0]//2, r-kernel.shape[1]//2kernPadded = cv.copyMakeBorder(kernel, hPad, hPad, wPad, wPad, cv.BORDER_CONSTANT)kernFFT = np.fft.fft2(kernPadded)fftShift = np.fft.fftshift(kernFFT)kernTrans = np.log(1 + np.abs(fftShift))transNorm = np.uint8(cv.normalize(kernTrans, None, 0, 255, cv.NORM_MINMAX))return transNormif __name__ == '__main__':radius = 64plt.figure(figsize=(9, 5.5))# (1) 盒式濾波器plt.subplot(241), plt.axis('off'), plt.title("1. BoxFilter")kernBox = np.ones((5,5), np.float32) # BoxF 濾波器核HBox = getTransferFun(kernBox, radius) # BoxF 傳遞函數plt.imshow(HBox, cmap='gray', vmin=0, vmax=255)# (2) 高斯低通濾波器plt.subplot(242), plt.axis('off'), plt.title("2. Gaussian")kernX = cv.getGaussianKernel(5, 0) # 一維高斯核kernGaussian = kernX * kernX.T # 二維高斯核HGaussian = getTransferFun(kernGaussian, radius) # 高斯低通傳遞函數plt.imshow(HGaussian, cmap='gray', vmin=0, vmax=255)# (3) 拉普拉斯算子 K1plt.subplot(243), plt.axis('off'), plt.title("3. Laplacian K1")kernLaplacian1 = np.array([[0, 1, 0], [1, -4, 1], [0, 1, 0]]) # Laplacian K1hLaplacian1 = getTransferFun(kernLaplacian1, radius) # Laplacian K1 傳遞函數plt.imshow(hLaplacian1, cmap='gray', vmin=0, vmax=255)# (4) 拉普拉斯算子 K2plt.subplot(244), plt.axis('off'), plt.title("4. Laplacian K2")kernLaplacian2 = np.array([[1, 1, 1], [1, -8, 1], [1, 1, 1]]) # Laplacian K2hLaplacian2 = getTransferFun(kernLaplacian2, radius) # Laplacian K2 傳遞函數plt.imshow(hLaplacian2, cmap='gray', vmin=0, vmax=255)# (5) Sobel 算子,X軸方向plt.subplot(245), plt.axis('off'), plt.title("5. Sobel-X")kernSobelX = np.array([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]])HSobelX = getTransferFun(kernSobelX, radius) # Sobel-X 傳遞函數plt.imshow(HSobelX, cmap='gray', vmin=0, vmax=255)# (6) Sobel 算子,Y軸方向plt.subplot(246), plt.axis('off'), plt.title("6. Sobel-Y")kernSobelY = np.array([[-1, -2, -1], [0, 0, 0], [1, 2, 1]])HSobelY = getTransferFun(kernSobelY, radius) # Sobel-Y 傳遞函數plt.imshow(HSobelY, cmap='gray', vmin=0, vmax=255)# (7) Scharr 算子,X軸方向plt.subplot(247), plt.axis('off'), plt.title("7. Scharr-X")kernScharrX = np.array([[-3, 0, 3], [-10, 0, 10], [-3, 0, 3]])HScharrX = getTransferFun(kernScharrX, radius) # Scharr-X 傳遞函數plt.imshow(HScharrX, cmap='gray', vmin=0, vmax=255)# (8) Scharr 算子,Y軸方向plt.subplot(248), plt.axis('off'), plt.title("8. Scharr-Y")kernScharrY = np.array([[-3, -10, -3], [0, 0, 0], [3, 10, 3]])HScharrY = getTransferFun(kernScharrY, radius) # Scharr-X 傳遞函數plt.imshow(HScharrY, cmap='gray', vmin=0, vmax=255)plt.tight_layout()plt.show()
【本節完】
版權聲明:
youcans@xupt 原創作品,轉載必須標注原文鏈接:(https://blog.csdn.net/youcans/article/details/127751487)
Copyright 2022 youcans, XUPT
Crated:2022-11-08
總結
以上是生活随笔為你收集整理的【OpenCV 例程300篇】250. 梯度算子的传递函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Codecombat复赛闯关攻略
- 下一篇: js室内地图开发_入门指南-室内地图 J