1.sobel算子:
sobel算子可以计算图像梯度,计算图像梯度的作用是提取边界,一般我们用一个3x3的卷积核去指示sobel算子是如何运算的:
图中左边就是计算水平梯度时的卷积核,简单来说就是右边减左边,权重由卷积核规定。这里我们可以联想一下高中生物,那时候我们常考的一种题目就是细胞膜两边的浓度梯度差的问题。细胞膜就是边界,它两边浓度不一样形成了梯度差,同样在图像里面我们也借用了这样一个形象的概念:如果在垂直方向上存在有边界,那么它两边的值就是一边大,一边小,形成了一个落差,也就是梯度。如果我们拿一边减去另一边结果差值很大就说明中间存在一条边界。这也体现出图像中的边界属于是高频性信息。上图右边就是一幅图像的一个部分,我们把这个部分按照卷积核规定的权重值去运算得到一个结果,把这个结果替换掉中间的像素值,按照这样的规则我们对图像的像素进行一次遍历得到的就是水平梯度的结果,作用是提取到垂直方向的边界。
上图是计算垂直方向梯度的卷积核,如果在垂直方向上存在有较大的差值就说嘛存在有水平边界。
故水平梯度运算提取垂直方向的边界,垂直方向的梯度运算得到水平方向的边界。
2 scharr算子
scharr与sobel算子思想一样,只是卷积核的系数不同,scharr算子提取边界也更加灵敏,能提取到更细小的边界,但请注意,越是灵敏就越是可能误判
下图左边是计算水平梯度时的卷积核,右边是计算垂直梯度时的卷积核
3.Laplacian算子
Laplacian算子也是用来计算图像梯度的,作用也是提取边界。它与上面两种算子的不同是:
sobel算子和scharr算子一般先算一个水平梯度,再算一个垂直方向梯度,然后把两个结果按照0.5的权重进行图像融合以得到完整的边界。
但Laplacian算子则不同,它本身就是一个二阶的算子,它的运算规则就是在水平方向运算两次,垂直方向运算两次,两个结果相叠加替换中心点(锚点)的像素值(灰度值):规则如下
4.三种算子运算结果的对比
#sobel与scharr,拉普拉斯的对比
import cv2 as cv
img = cv.imread("D:\\OpenCV\\testimg\\lena.png",cv.IMREAD_UNCHANGED)
img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sobelx=cv.Sobel(img,cv.CV_64F,1,0)
sobely=cv.Sobel(img,cv.CV_64F,0,1)
sobelx=cv.convertScaleAbs(sobelx)
sobely=cv.convertScaleAbs(sobely)
scharrx=cv.Scharr(img,cv.CV_64F,1,0)
scharry=cv.Scharr(img,cv.CV_64F,0,1)
scharrx=cv.convertScaleAbs(scharrx)
scharry=cv.convertScaleAbs(scharry)
lap=cv.Laplacian(img,cv.CV_64F)
lap=cv.convertScaleAbs(lap)
cv.imshow("origin",img)
cv.imshow("sobel",cv.addWeighted(sobelx,0.5,sobely,0.5,0))
cv.imshow("scharr",cv.addWeighted(scharrx,0.5,scharry,0.5,0))
cv.imshow("laplacian",lap)
cv.waitKey()
cv.destroyAllWindows()
程序说明:在梯度运算中,很可能会出现负的灰度值,我们不能再采用uint8类型作为像素的数据类型,而是采用了CV_64F这种有负数范围的类型,运算结果里的负数我们也不能不处理,否则在显示的时候就会被截断为0,这样就会丢失边界信息。convertScaleAbs函数就是把梯度运算后的图像给正值化,也就是取绝对值
程序运行结果如下: