图像梯度计算的是图像变化的速度。对于图像的边缘部分,其灰度值变化较大,梯度值也较大;相反,对于图像中比较平滑的部分,其灰度值变化较小,相应的梯度值也较小。一般情况下,图像梯度计算的是图像的边缘信息。
在点f(x,y)处,f(x,y)的梯度为
∇ f ( x , y ) = [ G x G y ] T = [ ∂ f ∂ x ∂ f ∂ y ] T = ( G x 2 + G y 2 ) \nabla f(x,y)=[G_{x} \ G_{y}]^T=[\frac{\partial f}{\partial x} \ \frac{\partial f}{\partial y}]^T=\sqrt{(G_{x}^2+G_{y}^2)} ∇f(x,y)=[Gx Gy]T=[∂x∂f ∂y∂f]T=(Gx2+Gy2)
而
G x = f ( x + 1 , y ) − f ( x − 1 , y ) 2 G y = f ( x , y + 1 ) − f ( x , y − 1 ) 2 G_{x}=\frac{f(x+1,y)-f(x-1,y)}{2}\\ G_{y}=\frac{f(x,y+1)-f(x,y-1)}{2} Gx=2f(x+1,y)−f(x−1,y)Gy=2f(x,y+1)−f(x,y−1)
当Sobel算子与原始图像src进行卷积计算,可以计算水平方向上的像素变化情况,水平方向偏导数 G x G_{x} Gx的计算方式为:
G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ s c r G_x= \left [ \begin{matrix} -1&0&1\\ -2&0&2\\ -1&0&1 \end{matrix} \right]*scr Gx=⎣ ⎡−1−2−1000121⎦ ⎤∗scr
上式中,scr为原始图像。假设其中有9个像素点,如图所示。
G x = [ − 1 0 1 − 2 0 2 − 1 0 1 ] ∗ [ P 1 P 2 P 3 P 4 P 5 P 6 P 7 P 8 P 9 ] G_x=\left [ \begin{matrix} -1&0&1\\ -2&0&2\\ -1&0&1 \end{matrix} \right]* \left [ \begin{matrix} P_1&P_2&P_3\\ P_4&P_5&P_6\\ P_7&P_8&P_9 \end{matrix} \right] Gx=⎣ ⎡−1−2−1000121⎦ ⎤∗⎣ ⎡P1P4P7P2P5P8P3P6P9⎦ ⎤
则可得像素点 P 5 P_5 P5的水平方向偏导数为:
P 5 x = ( P 3 − P 1 ) + 2 ∗ ( P 6 − P 4 ) + ( P 9 − P 7 ) P_5x=(P_3-P_1)+2*(P_6-P_4)+(P_9-P_7) P5x=(P3−P1)+2∗(P6−P4)+(P9−P7)
即用像素点 P 5 P_5 P5右侧像素点的值减去左侧像素点的值,其中,中间像素点距离像素点 P 5 P_5 P5较近,其像素值差值的权重为2,其余差值权重均为1.
当Sobel算子与原始图像src进行卷积计算,可以计算垂直方向上的像素变化情况,垂直方向偏导数 G y G_{y} Gy的计算方式为:
G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ s c r G_y= \left [ \begin{matrix} -1&-2&-1\\ 0&0&0\\ 1&2&1 \end{matrix} \right]*scr Gy=⎣ ⎡−101−202−101⎦ ⎤∗scr
上式中,scr为原始图像。假设其中有9个像素点,如图所示。
G y = [ − 1 − 2 − 1 0 0 0 1 2 1 ] ∗ [ P 1 P 2 P 3 P 4 P 5 P 6 P 7 P 8 P 9 ] G_y=\left [ \begin{matrix} -1&-2&-1\\ 0&0&0\\ 1&2&1 \end{matrix} \right]* \left [ \begin{matrix} P_1&P_2&P_3\\ P_4&P_5&P_6\\ P_7&P_8&P_9 \end{matrix} \right] Gy=⎣ ⎡−101−202−101⎦ ⎤∗⎣ ⎡P1P4P7P2P5P8P3P6P9⎦ ⎤
则可得像素点 P 5 P_5 P5的垂直方向偏导数为:
P 5 y = ( P 7 − P 1 ) + 2 ∗ ( P 8 − P 2 ) + ( P 9 − P 3 ) P_5y=(P_7-P_1)+2*(P_8-P_2)+(P_9-P_3) P5y=(P7−P1)+2∗(P8−P2)+(P9−P3)
即用像素点 P 5 P_5 P5下一行像素点的值减去上一行像素点的值,其中,中间像素点距离像素点 P 5 P_5 P5较近,其像素值差值的权重为2,其余差值权重均为1.
∇ f ( x , y ) = ( G x 2 + G y 2 ) \nabla f(x,y)=\sqrt{(G_{x}^2+G_{y}^2)} ∇f(x,y)=(Gx2+Gy2)
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
import time
plt.rcParams['font.sans-serif']=['SimHei']
def Sobel(img,filter1,filter2):
b=time.time()
h,w=img.shape[:2]
new_img=np.zeros((h+2,w+2),np.uint8)
new_img[1:h+1,1:w+1]=img#填充
out=[]
for i in range(1,h+1):
for j in range(1,w+1):
dx=np.sum(np.multiply(new_img[i-1:i+2,j-1:j+2],filter1))
dy=np.sum(np.multiply(new_img[i-1:i+2,j-1:j+2],filter2))
out.append(
np.clip(int(np.sqrt(dx**2+dy**2)),0,255)
)
out=np.array(out).reshape(h,w)
e=time.time()
print(e-b)
return out
if __name__=="__main__":
path="D:\\code\\python\\opencv\\lena.jpg"
img=cv.imread(path,0)
filter1=np.array([
[-1,0,1],
[-2,0,2],
[-1,0,1]
])
filter2=np.array([
[-1,-2,-1],
[0,0,0],
[1,2,1]
])
# img=np.array([
# [0,0,1,255,254,254,254],
# [1,1,1,254,253,254,254],
# [0,0,0,255,255,253,253],
# [1,1,0,254,254,254,254]
# ],dtype=np.uint8)
plt.figure(figsize=(6,8))
plt.subplot(121)
plt.imshow(Sobel(img,filter1,filter2),cmap='gray')
plt.title('自定义函数')
在Opencv内,使用函数cv2.Sobel()实现Sobel算子运算:
dst=cv2.Sobel(src,ddepth,dx,dy)
示例代码:
sobley=cv.Sobel(img,cv.CV_64F,0,1)
soblex=cv.Sobel(img,cv.CV_64F,1,0)
为得到结果为正数的偏导数,需要对Sobel函数求出的偏导数取绝对值,在Opencv中,使用函数cv2.convertScaleAbs()对参数取绝对值,即
dst=cv2.convertScaleAbs(src)
示例代码:
absy=cv.convertScaleAbs(sobley)
如果想要获取x方向和y方向的边缘叠加,需要将水平方向和垂直方向的边缘图进行相加,在Opencv中,使用函数cv2.addweighted()进行叠加,即:
dst=cv2.addweighted(src1,alpha,src2,gamma)
示例代码:
dst=cv.addWeighted(absx,0.5,absy,0.5,0)
import numpy as np
import matplotlib.pyplot as plt
import cv2 as cv
import time
plt.rcParams['font.sans-serif']=['SimHei']
def Sobel(img,filter1,filter2):
b=time.time()
h,w=img.shape[:2]
new_img=np.zeros((h+2,w+2),np.uint8)
new_img[1:h+1,1:w+1]=img#填充
out=[]
for i in range(1,h+1):
for j in range(1,w+1):
dx=np.sum(np.multiply(new_img[i-1:i+2,j-1:j+2],filter1))
dy=np.sum(np.multiply(new_img[i-1:i+2,j-1:j+2],filter2))
out.append(
np.clip(int(np.sqrt(dx**2+dy**2)),0,255)
)
out=np.array(out).reshape(h,w)
e=time.time()
print(e-b)
return out
if __name__=="__main__":
path="D:\\code\\python\\opencv\\lena.jpg"
img=cv.imread(path,0)
filter1=np.array([
[-1,0,1],
[-2,0,2],
[-1,0,1]
])
filter2=np.array([
[-1,-2,-1],
[0,0,0],
[1,2,1]
])
# img=np.array([
# [0,0,1,255,254,254,254],
# [1,1,1,254,253,254,254],
# [0,0,0,255,255,253,253],
# [1,1,0,254,254,254,254]
# ],dtype=np.uint8)
plt.figure(figsize=(6,8))
plt.subplot(121)
plt.imshow(Sobel(img,filter1,filter2),cmap='gray')
plt.title('自定义函数')
sobelx =cv.Sobel(img,cv.CV_64F,1,0)
absx=cv.convertScaleAbs(sobelx)
sobley=cv.Sobel(img,cv.CV_64F,0,1)
absy=cv.convertScaleAbs(sobley)
dst=cv.addWeighted(absx,0.5,absy,0.5,0)
plt.subplot(122)
plt.imshow(dst,cmap='gray')
plt.title('opencv函数')
plt.show()
Laplacian算子(拉普拉斯)是一种二阶导数算子,其具有旋转不变性,可以满足不同方向的图像边缘锐化(边缘检测)的要求。通常情况下,其算子的系数之和需要为零。例如,一个3x3大小的Laplacian算子如下所示。
[ 0 1 0 1 − 4 1 0 1 0 ] \left[ \begin{matrix} 0 &1&0\\ 1&-4&1\\ 0&1&0 \end{matrix} \right] ⎣ ⎡0101−41010⎦ ⎤
Laplacian算子类似二阶Sobel导数,需要计算两个方向的梯度值。例如:
L a p = [ 0 1 0 1 − 4 1 0 1 0 ] ∗ [ P 1 P 2 P 3 P 4 P 5 P 6 P 7 P 8 P 9 ] Lap=\left [ \begin{matrix} 0&1&0\\ 1&-4&1\\ 0&1&0 \end{matrix} \right]* \left [ \begin{matrix} P_1&P_2&P_3\\ P_4&P_5&P_6\\ P_7&P_8&P_9 \end{matrix} \right] Lap=⎣ ⎡0101−41010⎦ ⎤∗⎣ ⎡P1P4P7P2P5P8P3P6P9⎦ ⎤
则可得像素点 P 5 P_5 P5的近似导数值为:
P 5 l a p = ( P 2 + P 4 + P 6 + P 8 ) − 4 ⋅ P 5 P_5lap=(P_2+P_4+P_6+P_8)-4·P_5 P5lap=(P2+P4+P6+P8)−4⋅P5
在Opencv内使用函数cv2.Laplacian()实现Laplacian算子的计算,该函数的语法格式为:
dst=cv2.Laplacian(src,ddepth,ksize)
path='D:\\code\\python\\opencv\\lena.jpg'
img=cv.imread(path,0)
plt.imshow(cv.Laplacian(img,cv.CV_64F),cmap='gray')
plt.title('Opencv')
plt.show()