图像梯度的算法有很多方法:sabel算子,scharr算子,laplacian算子,sanny边缘检测(下个随笔)。。。
这些算子的原理可参考:https://blog.****.net/poem_qianmo/article/details/25560901
下面是我的一些理解:
sabel算子:
sobel算子主要用于获得数字图像的一阶梯度,常见的应用和物理意义是边缘检测。
函数:
Python: cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]]) → dst (参数就不一一说了,常用的就那几个,其他默认即可)
Parameters: |
|
---|
原理
算子使用两个33的矩阵(图1)算子使用两个33的矩阵(图1)去和原始图片作卷积,分别得到横向G(x)和纵向G(y)的梯度值,如果梯度值大于某一个阈值,则认为该点为边缘点
Gx方向的相关模板:
Gy方向的相关模板:
具体计算如下:
图像的每一个像素的横向及纵向灰度值通过以下公式结合,来计算该点灰度的大小:
通常,为了提高效率使用不开平方的近似值:
#sobels算子
img = cv.imread("E:/pictures/lena.jpg",cv.IMREAD_UNCHANGED)
sobelx= cv.Sobel(img,cv.CV_64F,1,0) #cv.CV_64F将像素值转换为double型,不然计算后为负值的像素会被截断为0
sobelx = cv.convertScaleAbs(sobelx) #转换为uint8类型(x方向)
sobely = cv.Sobel(img,cv.CV_64F,0,1)
sobely = cv.convertScaleAbs(sobely)
sobelxy11 = cv.Sobel(img,cv.CV_64F,1,1) #直接x,y方向一起计算(效果不好,应分开计算,再求权重和)
sobelxy11 = cv.convertScaleAbs(sobelxy11)
sobelxy = cv.addWeighted(sobelx,0.5,sobely,0.5,0) #图像权重和
cv.imshow("orginal",img) #dst = cv.addWidget(src1,alpha,src2,beta,gamma)
cv.imshow("sobelx",sobelx) #src1 图一 alpha->图一的权重 src2->图二 beta->图二的权重 gamma->修正值
cv.imshow("sobely",sobely) #dst = src1*alpha+src2*beta+gamma
cv.imshow("sobelxy",sobelxy)
cv.imshow("sobelxy11",sobelxy11)
cv.waitKey()
cv.destroyAllWindows()
用sobel函数同时对想x,y方向检测的效果并不好,一般不用。
scharr算子:
函数:
Python: cv2.Scharr(src, ddepth, dx, dy[, dst[, scale[, delta[, borderType]]]]) → dst
Parameters: |
|
---|
scharr算子是对sabel算子的增强,可以看到上图中很多细小的边缘都没检测到,那么scharr算子就是解决这个问题的,它比sabel算子更精确,速度和复杂程度却一样,只是因为用的核不一样
是scharr 的卷积核,他的原理和sabel算子一样。
#scharr算子 scharr算子是对sabel算子的增强 scharr算子等价于ksize=-1的sabel算子
img = cv.imread("E:/pictures/lena.jpg",cv.IMREAD_GRAYSCALE)
scharrx= cv.Scharr(img,cv.CV_64F,1,0) #scharrx算子要满足dx>=0&&dy>=0&&dx+dy=1
scharrx = cv.convertScaleAbs(scharrx)
scharry = cv.Scharr(img,cv.CV_64F,0,1)
scharry = cv.convertScaleAbs(scharry)
scharrxy = cv.addWeighted(scharrx,0.5,scharry,0.5,0)
#sabel算子和 scharr算子的比较
sobelx= cv.Sobel(img,cv.CV_64F,1,0)
sobelx = cv.convertScaleAbs(sobelx)
sobely = cv.Sobel(img,cv.CV_64F,0,1)
sobely = cv.convertScaleAbs(sobely)
sobelxy = cv.addWeighted(sobelx,0.5,sobely,0.5,0)
cv.imshow("orginal",img)
cv.imshow("sobelxy",sobelxy)
cv.imshow("scharrxy",scharrxy)
cv.waitKey()
cv.destroyAllWindows()
laplacian算子:
Laplace算子和Sobel算子一样,属于空间锐化滤波操作,只不过是用的二阶微分,看官网的一些解释:
The function calculates the Laplacian of the source image by adding up the second x and y derivatives calculated using the Sobel operator:
This is done when ksize > 1 . When ksize == 1 , the Laplacian is computed by filtering the image with the following aperture:
cv.Laplace(src, dst, ksize=3) → None
Parameters: |
|
---|
#拉普拉斯算子
img = cv.imread("E:/pictures/erode1.jpg",cv.IMREAD_GRAYSCALE)
r = cv.Laplacian(img,cv.CV_64F)
r = cv.convertScaleAbs(r) #关键代码就这两行,拉普拉斯算子不用再求x,y的权重和,因为这个函数都计算好了
cv.imshow("orginal",img)
cv.imshow("laplacian",r)
cv.waitKey()
cv.destroyAllWindows()
Canny边缘检测:
Python: cv2.Canny(image, threshold1, threshold2[, edges[, apertureSize[, L2gradient]]]) → edges
threshold1和threshold2是两个阈值,越小检测效果越好
import cv2 as cv
import numpy as np img = cv.imread("E:/pictures/lena.jpg")
result1 = cv.Canny(img,50,100)
result2 = cv.Canny(img,100,200)
cv.imshow("orginal",img)
cv.imshow("result1",result1)
cv.imshow("result2",result2)
cv.waitKey()
cv.destroyAllWindows()