opencv图像处理之图像梯度

文章目录

      • 1.原理
      • 2.Sobel算子
      • 3.Laplacian算子
      • 4.代码和效果
      • 5.怎么理解用卷积核来检测边界呢?

1.原理

梯度简单来说就是求导。OpenCV 提供了三种不同的梯度滤波器,或者说高通滤波器:SobelScharrLaplacian
Sobel,Scharr 其实就是求一阶或二阶导数。Scharr 是对Sobel的优化(使用小的卷积核求解求解梯度角度时)。Laplacian 是求二阶导数。

2.Sobel算子

  • cv.Sobel()
sobelx=cv2.Sobel(gray,cv2.CV_64F,1,0,ksize=5)

参数按顺序为:原图、输出图像的深度、x方向求导的阶数、y方向求导的阶数、卷积核大小。
Sobel 算子是高斯平滑与微分操作的结合体,所以它的抗噪声能力很好。如果ksize=-1,会使用3x3 的Scharr 滤波器,它的的效果要比3x3 的Sobel 滤波器好(而且速度相同,所以在使用3x3 滤波器时应该尽量使用Scharr 滤波器)。3x3 的Scharr 滤波器卷积核如下:
opencv图像处理之图像梯度_第1张图片

3.Laplacian算子

  • cv.Laplacian()
laplacian=cv2.Laplacian(gray,cv2.CV_64F)

拉普拉斯算子可以使用二阶导数的形式定义,可假设其离散实现类似于二阶Sobel 导数,事实上,OpenCV 在计算拉普拉斯算子时直接调用Sobel 算子。

4.代码和效果

def gradient(self):
    gray=cv2.imread(self.infile,0)
    #参数1,0为只在x方向求一阶导数,最大可以求2阶导数。y方向同理。
    #参数cv2.CV_64F结果图像的深度,可以使用-1,与原图像保持一致(np.uint8)
    sobelx=cv2.Sobel(gray,cv2.CV_64F,1,0,ksize=5)
    sobely=cv2.Sobel(gray,cv2.CV_64F,0,1,ksize=5)
    laplacian=cv2.Laplacian(gray,cv2.CV_64F)

    titles = ['raw', 'sobelx','sobely','laplacian']
    images = [gray, sobelx,sobely,laplacian]
    for i in range(4):
        plt.subplot(1,4,i+1),plt.imshow(images[i],'gray')
        plt.title(titles[i])
        plt.xticks([]),plt.yticks([])
    plt.show()

opencv图像处理之图像梯度_第2张图片
下面打印了部分gray和sobelx的像素值。有点不太明白为什么出现大片的灰色。超出255和小于0的值是怎么处理的呢?

[[ 98 122 98 … 120 97 98]
[113 206 229 … 246 199 122]
[ 98 234 255 … 255 237 110]

[121 248 255 … 254 234 109]
[ 99 198 226 … 232 216 121]
[105 129 103 … 111 120 80]]
[[ 0. 2804. 1940. … -1938. -3142. 0.]
[ 0. 3515. 2286. … -2230. -3667. 0.]
[ 0. 4563. 2669. … -2555. -4429. 0.]

[ 0. 4397. 2688. … -2617. -4417. 0.]
[ 0. 3459. 2343. … -2115. -3467. 0.]
[ 0. 2854. 2036. … -1762. -2894. 0.]]

我们应该知道为什么要扩大图像的深度,而不采用原来的深度呢?

想象一下一个从黑到白的边界的导数是正数,而一个从白到黑的边界点导数却是负数。如果原图像的深度是np.int8 时,所有的负值都会被截断变成0,换句话说就是把从白到黑边界丢失掉。所以如果这两种边界你都想检测到,最好的的办法就是将输出的数据类型设置的更高,比如cv2.CV_16S,cv2.CV_64F 等。取绝对值然后再把它转回到cv2.CV_8U。

如下图所示:直接用-1为参数,从白色到黑色的边界被丢弃了。而先扩深度,再去绝对值并减小深度,是可以检测出从白色到黑色的边界的。
opencv图像处理之图像梯度_第3张图片
(1) 此时若把我的代码中的cv2.CV_64F都改为-1,得到结果如下:

sobelx=cv2.Sobel(gray,-1,1,0,ksize=5)
sobely=cv2.Sobel(gray,-1,0,1,ksize=5)
laplacian=cv2.Laplacian(gray,-1)

opencv图像处理之图像梯度_第4张图片
(2)若我把得到的图像先取绝对值,再把数据深度转为和原来相同的。

sobelx=np.uint8(np.abs(cv2.Sobel(gray,cv2.CV_64F,1,0,ksize=5)))
sobely=np.uint8(np.abs(cv2.Sobel(gray,cv2.CV_64F,0,1,ksize=5)))
laplacian=np.uint8(np.abs(cv2.Laplacian(gray,cv2.CV_64F)))

opencv图像处理之图像梯度_第5张图片

5.怎么理解用卷积核来检测边界呢?

可以参考卷积实现

你可能感兴趣的:(计算机视觉)