前言
前面学习了一阶微分的几个经典算子:
05Priwitt
04Sobel
03Roberts
今天学习的是二阶微分的Laplacian算子。
一、为什么模板是那样?
在学习的过程中,很多时候,他直接把模板给了,说这个是xxx算子的模板,但是为什么呢,为什么这个模板就是这个算子,为什么它可以实现某些功能呢?
下面简单介绍一下原理。
Laplacian 算子是一种二阶导数算子,对一个连续函数f(x,y),它在(x,y)处的拉普拉斯值定义为
如下图所示,对于阶跃状边缘,其二阶导数在边缘点出现零交叉,并且边缘点两旁像素的二阶导数异号。
拉普拉斯算子的推导过程如下:
写成模板就是:
看模板就看出来这个算子是与方向无关的各向同性(旋转轴对称)边缘检测算子,当我们只关心边缘点的位置而不顾其周围的实际灰度差,就可以选择该算子进行检测。
当然了,这个模板不是唯一的,因为对角邻域的数字近似方法是多种多样的,也可以借助其他模板来计算函数的拉普拉斯值,模板的基本要求是中心为负值,周边为正,但总和要为0。
二、代码验证
1.卷积函数
代码如下(示例):
import numpy as np
def my_filter2D(img,kernel):
"""
卷积函数
:param image: 原图像,是灰度图
:param kernel: 卷积核
:return: 卷积后的图像
"""
k_rows,k_cols = kernel.shape[:2]
i_rows,i_cols = img.shape[:2]
new_img = np.zeros((img.shape[0],img.shape[1]),dtype=np.float32)
#进行遍历操作
for row in range(i_rows-k_rows+1):
for col in range(i_cols-k_cols+1):
#创建一个视图window,大小与kernel一致
windows=img[row:row+k_rows,col:col+k_cols]
#完成卷积操作
out=abs(np.sum(windows * np.flip(kernel), axis=(0, 1)))
#赋值 3*3的kernel是row+1,但是2*2 此时的位置是左上,那就等于row,col,将下面修改一下。
#new_img[row+1,col+1] = out
new_img[row+k_rows//2,col+k_cols//2] = out
new_img = np.clip(new_img, 0, 255).astype(np.uint8)
return new_img
2.验证
代码如下(示例):
import cv2
import numpy as np
import matplotlib.pyplot as plt
import img_filter2D
img = cv2.imread("lena.bmp",0)
#给拉普拉斯算子的模板
H1 = np.array([[0,1,0],[1,-4,1],[0,1,0]])
H2 = np.array([[1,1,1],[1,-8,1],[1,1,1]])
#使用卷积函数
new_img1 = img_filter2D.my_filter2D(img,H1)
new_img2 = img_filter2D.my_filter2D(img,H1)
#打印图片
figure_ = plt.figure()
ax1 = figure_.add_subplot(131)
ax1.set_title('original img')
plt.imshow(img,cmap='gray')#不要忘记这一步
ax2= figure_.add_subplot(132)
ax2.set_title('H1')
plt.imshow(new_img1,cmap='gray')
ax3 = figure_.add_subplot(133)
ax3.set_title('H2')
plt.imshow(new_img2,cmap='gray')
plt.show()
为了改善锐化效果,可以脱离微分的计算原理,在原有的算子基础上,对模板系数进行调整。下面将上面的卷积模板改成H3,H4,H5,H6得到的结果如下,可以看到,每个模板得到的效果都不太一样的,具体使用哪一个,还需要进一步的选择。
#调整系数的算子模板
H3 = np.array([[0,-1,0],[-1,4,-1],[0,-1,0]])
H4 = np.array([[1,-2,1],[-2,4,-2],[1,-2,1]])
H5 = np.array([[-1,2,-1],[2,-4,2],[-1,2,-1]])
H6 = np.array([[-1,-1,--1],[-1,8,-1],[-1,-1,-1]])
看到了一个很不同的模板,别的模板的和都是0,而下面的这个模板的和为1,与上面的H6有点像,这种和为1的模板其实是很接近原图的,可能会拿Laplacian算子来进行滤波操作的使用到。
#特殊的模板
H7 = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])
总结
在图像中,边缘通常是像素值的急剧变化。因此,在边缘附近,像素值的变化率很高。拉普拉斯算子的主要目标是找到这种突然的变化,因此只关心边缘点的位置。而且,如果考虑周围像素之间的实际灰度差异,可能会使边缘检测更难以实现,因为它们可能会引入噪声或毛刺。因此,在实际操作中,通常会使用拉普拉斯算子以及其他边缘检测算子来识别图像中的边缘。
还需要注意的是,梯度算子和Laplacian算子都对噪声很敏感,一般在使用它们检测边缘前要对图像进行平滑处理。