1、sobel算子
先读进来一个原型白色图
img = cv2.imread('pie.png',cv2.IMREAD_GRAYSCALE)
cv2.imshow("img",img)
cv2.waitKey()
cv2.destroyAllWindows()
打印结果:
如图有两个3*3的卷积核,其中A是原始图片中的一个3*3的区域,这个A和3*3的卷积核所谓对应位置相乘的结果就分别是左右梯度和上下梯度
假如A是这个矩阵:
那么Gx的计算结果就为:-x1+x3-2x4+2x6-x7+x9
代码实现就很简单了,直接一行就行:
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
cv_show(sobelx,'sobelx')
dst = cv2.Sobel(src, ddepth, dx, dy, ksize)
- src:原始图像
- ddepth:图像的深度
- dx和dy分别表示水平和竖直方向
- ksize是Sobel算子的大小,就是一个卷积核的大小
打印一个图片可以做出一个函数:
def cv_show(img,name):
cv2.imshow(name,img)
cv2.waitKey()
cv2.destroyAllWindows()
将上面的结果打印出来:
cv_show(sobelx,'sobelx')
因为我们指定的是dx=1,dy=0,所以只计算了水平方向,很显然只有边界的地方才会有梯度
2、梯度计算方法
安装第1节的计算方法,白色减去黑色结果是正的,黑色减去白色结果就会为负数,而openCV的像素值在0-255,所以会将负数显示为0。如果加上绝对值就可以显示成右边的一圈白色了。
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
cv_show(sobelx,'sobelx')
打印结果:
同样的方法计算一下上下梯度:
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
cv_show(sobely,'sobely')
打印结果:
分别计算水平方向和竖直方向再打印:
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')
打印结果:
不建议直接把dx和dy都直接设置成1:
sobelxy=cv2.Sobel(img,cv2.CV_64F,1,1,ksize=3)
sobelxy = cv2.convertScaleAbs(sobelxy)
cv_show(sobelxy,'sobelxy')
打印结果:
换一个图做一遍,先打印原图:
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
cv_show(img,'img')
打印结果:
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
cv_show(sobelxy,'sobelxy')
第二行、第四行分别计算sobelx和sobely,第三行、第五行分别取绝对值,第六行最后融合在一起
,打印结果:
3、scharr算子和lapkacian算子
scharr夏尔
lapkacian拉普拉斯
scharr算子就是让结果更加敏感一些,lapkacian算子在推导过程使用了二阶导,lapkacian对噪音点会比较敏感,但是对于梯度的计算或者说边缘检测就不是那么友好了,所以lapkacian算子经常和其他方法结合在一起进行使用。
如上图,它不是和其他算子一样,有一个左右和上下的计算,它将目标像素值乘以-4然后加上上下左右的值。因为lapkacian没有分水平和竖直两个方式,所以不需要分开再合并了。
将三种方法都做一遍,放在一起进行比较:
#不同算子的差异
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=3)
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=3)
sobelx = cv2.convertScaleAbs(sobelx)
sobely = cv2.convertScaleAbs(sobely)
sobelxy = cv2.addWeighted(sobelx,0.5,sobely,0.5,0)
scharrx = cv2.Scharr(img,cv2.CV_64F,1,0)
scharry = cv2.Scharr(img,cv2.CV_64F,0,1)
scharrx = cv2.convertScaleAbs(scharrx)
scharry = cv2.convertScaleAbs(scharry)
scharrxy = cv2.addWeighted(scharrx,0.5,scharry,0.5,0)
laplacian = cv2.Laplacian(img,cv2.CV_64F)
laplacian = cv2.convertScaleAbs(laplacian)
res = np.hstack((sobelxy,scharrxy,laplacian))
cv_show(res,'res')
打印结果:
很明显scharr算子更加敏感一下,计算出了更多的细节和线条
最后看看原始图长什么样子:
img = cv2.imread('lena.jpg',cv2.IMREAD_GRAYSCALE)
cv_show(img,'img')