好比有一幅图,图里面有一条线,左边很亮,右边很暗,那人眼就很容易识别这条线做为边缘.也就是像素的灰度值快速变化的地方.html
对于f(t),其导数f'(t)反映了每一处的变化趋势.在变化最快的位置其导数最大. sobel算子的思路就是模拟求一阶导数.python
sobel算子是一个离散差分算子.它计算图像像素点亮度值的近似梯度.
图像是二维的,即沿着宽度/高度两个方向.
咱们使用两个卷积核对原图像进行处理:c++
水平方向
很好理解,原始像素灰度值-->(右边像素值-左边像素值),反映了水平方向的变化状况.api
垂直方向
ide
这样的话,咱们就获得了两个新的矩阵,分别反映了每一点像素在水平方向上的亮度变化状况和在垂直方向上的亮度变换状况.函数
综合考虑这两个方向的变化,咱们使用
反映某个像素的梯度变化状况.
有时候为了简单起见,也直接用绝对值相加替代.
code
opencv里可使用了以下的卷积核,能够"放大像素的变化状况".
能够参考这个函数Scharrhtm
import cv2 as cv def test(): src = cv.imread("/home/sc/disk/keepgoing/opencv_test/sidetest.jpeg") src = cv.GaussianBlur(src, (3, 3), 0) gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY) grad_x = cv.Sobel(gray, -1, 1, 0, ksize=3) grad_y = cv.Sobel(gray, -1, 0, 1, ksize=3) grad = cv.addWeighted(grad_x, 0.5, grad_y, 0.5, 0) cv.imshow("origin",src) cv.imshow("grad",grad) cv.waitKey() test()
首先是高斯模糊去噪.某种意义上说高斯模糊是和sobel相反的过程.高斯模糊平滑了某点像素与周边像素的差别.那为何还要先高斯去噪呢?blog
噪声就是像素的强度相对于真值有个突变。从时域上讲,经过高斯滤波能让一个像素的强度与周围的点相关,就减少了突变的影响;从频域上讲,突变引入了高频份量,而高斯滤波器能够滤除高频份量。ip
高斯去噪是为了防止把噪点也检测为边缘.
而后计算grad_x,grad_y.即对原图作水平方向/垂直方向的sobel卷积核卷积
grad_x = cv.Sobel(gray, -1, 1, 0, ksize=3) grad_y = cv.Sobel(gray, -1, 0, 1, ksize=3)
sobel api
注意区分c++版本和python版本api. 在上述代码中,第二个参数-1表明咱们但愿输出的图像矩阵和原图有一样的depth,第3/4个参数分别表明在x/y方向作一阶差分.取值0或1.
ksize必须为奇数.
tips:一般咱们使用( xorder = 1, yorder = 0, ksize = 3) or ( xorder = 0, yorder = 1, ksize = 3)来计算水平/垂直方向的一阶差分矩阵.ksize=3用的是标准sobel卷积核.若是ksize传入FILTER_SCHARR,则使用的是以下卷积核:
最后将两个矩阵叠加,综合考虑水平和垂直方向的像素灰度值变化强度.获得边缘.
grad = cv.addWeighted(grad_x, 0.5, grad_y, 0.5, 0)
完整代码处理效果以下
ksize采用cv.FILTER_SCHARR效果以下:
grad_x = cv.Sobel(gray, -1, 1, 0, ksize=cv.FILTER_SCHARR) grad_y = cv.Sobel(gray, -1, 0, 1, ksize=cv.FILTER_SCHARR)