在很多應用中,圖像強度的變化情況是非常重要的信息。強度的變化可以灰度圖像的\(x\)和\(y\)方向導數\(I_x\)和\(I_y\)進行描述。圖像的梯度向量為\(\nabla I = [I_x, I_y]^T\)。梯度有兩個重要屬性,一個是梯度的大小:
\[| \nabla I | = \sqrt{I_x^2+I_y^2} \]
它描述了圖像強度變化的強弱,另一個是梯度的角度:
\[\alpha = arctan2(I_y, I_x) \]
描述了圖像中每個像素點上強度變化最大的方向。我們可以使用離散近似的方式來計算圖像的導數。圖像導數大多數可以通過卷積簡單地實現:
\[I_x = I*D_x \ 和\ I_y = I*D_y \]
對於\(D_x\)和\(D_y\),通常選擇Priwitt濾波器:
\[D_x = \left[ \begin{matrix} -1 & 0 & 1 \\ -1 & 0 & 1 \\ -1 & 0 & 1 \end{matrix} \right] 和D_y=\left[ \begin{matrix} -1 & -1 & -1 \\ 0 & 0 & 0 \\ 1 & 1 & 1 \end{matrix} \right] \]
或者Sobel濾波器:
\[D_x = \left[ \begin{matrix} -1 & 0 & 1 \\ 2 & 0 & 2 \\ -1 & 0 & 1 \end{matrix} \right] 和D_y=\left[ \begin{matrix} -1 & -2 & -1 \\ 0 & 0 & 0 \\ 1 & 2 & 1 \end{matrix} \right] \]
上面兩種計算圖像導數的方法存在一些缺陷:濾波器的尺度需要隨着圖像分辨率的變化而變化。為了在圖像噪聲方面更穩健,以及在任意尺度上計算導數,我們可以使用高斯導數濾波器:
\[I_x = I*G_{\sigma x} 和 I_y = I*G_{\sigma y} \]
其中,\(G_{\sigma x}\) 和 \(G_{\sigma y}\) 表示 \(G_\sigma\) 在\(x\)和\(y\)方向上的導數,\(G_\sigma\) 為標准差為\(\sigma\)的高斯函數。
樣例演示
from scipy.ndimage import filters
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
class ScipyFilter:
def __init__(self, path: str):
self.img = np.array(Image.open(path))
self.grayImg = np.array(Image.open(path).convert('L'))
self.Ix = np.zeros(self.grayImg.shape)
self.Iy = np.zeros(self.grayImg.shape)
self.manitude = np.zeros(self.grayImg.shape)
def cal_derivatives_sobel(self):
"""
使用sobel濾波器計算導數
:return:
"""
filters.sobel(self.grayImg, 1, self.Ix)
filters.sobel(self.grayImg, 0, self.Iy)
self.manitude = np.sqrt(self.Ix**2 + self.Iy**2)
def cal_derivatives_prewitt(self):
"""
使用prewitt濾波器計算導數
:return:
"""
filters.prewitt(self.grayImg, 1, self.Ix)
filters.prewitt(self.grayImg, 0, self.Iy)
self.manitude = np.sqrt(self.Ix**2 + self.Iy**2)
def cal_derivatives_gaussian(self, sigma):
"""
計算圖像高斯導數
:param img: 圖像數據
:param sigma: 標准差
:return:
"""
filters.gaussian_filter(self.grayImg, (sigma, sigma), (0, 1), self.Ix)
filters.gaussian_filter(self.grayImg, (sigma, sigma), (1, 0), self.Iy)
def plot(self):
# 繪圖
plt.figure()
plt.gray()
plt.subplot(221).set_title("original img")
plt.imshow(self.grayImg)
plt.axis('off')
plt.subplot(222).set_title('x-directional derivative')
plt.imshow(self.Ix)
plt.axis('off')
plt.subplot(223).set_title('y-directional derivative')
plt.imshow(self.Iy)
plt.axis('off')
plt.subplot(224).set_title("gradient magnitude")
plt.imshow(self.manitude)
plt.axis('off')
plt.show()
if __name__ == '__main__':
img_path = "./imgs/3.jpg"
sc = ScipyFilter(img_path)
sc.cal_derivatives_sobel()
sc.plot()
sc.cal_derivatives_prewitt()
sc.plot()
sc.cal_derivatives_gaussian(3)
sc.plot()
sc.cal_derivatives_gaussian(5)
sc.plot()
結果演示
sobel濾波
prewitt濾波
gaussian濾波,標准差設置為3
gaussian濾波,標准差設置為5
在圖像中,正導數顯示為亮的像素,負導數顯示為暗的像素。灰色區域表示導數的值接近零。
圖像高斯模糊
from PIL import Image
import numpy as np
from scipy.ndimage import filters
img = Image.open(r"girl.jpg").convert('L')
img = np.array(img)
img2 = filters.gaussian_filter(img, 2)
img3 = filters.gaussian_filter(img, 5)
img4 = filters.gaussian_filter(img, 10)
結果演示
更多參考上一篇