OpenCV Sobel算子水平和垂直方向导数问题

sobel算子是一种常用的边缘检测算法,在各种论文或书籍中,我们常常能看到类似这样的话,被检测的对象存在大量的竖直边,所以可以采用sobel算子来找到第一个水平导数,它可以用来在图像中查找竖直边缘。
它在opencv中的原型如下:

CV_EXPORTS_W void Sobel( InputArray src, 
                         OutputArray dst, 
                         int ddepth,
                         int dx, 
                         int dy,
                         int ksize=3,
                         double scale=1, 
                         double delta=0,
                         int borderType=BORDER_DEFAULT );
                       

第一个参数,输入图像,Mat类型。
第二个参数,目标图像,Mat类型。
第三个参数,目标图像的颜色深度。
第四个参数,int类型dx,表示对x对导数的阶数。
第五个参数,int类型dy,表示对x对导数的阶数。
第六个参数,int类型ksize,表示Sobel核的大小,默认值3。
第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1。
第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,默认值0。
第九个参数, int类型的borderType,边界模式,默认值为BORDER_DEFAULT。

在这里主要解释第四个和第五个参数,为什么对x求1阶导数用来检测竖直边缘,同样的对y求1阶导数用来检测水平边缘。
根据sobel算子的数学推导:
当内核为33时,横向和纵向方向上的卷积因子分别为:
这里写图片描述
假设原图像为A,分别做卷积可以得到:
这里写图片描述
具体运算为:
Gx = (-1)f(x-1, y-1) + 0f(x,y-1) + 1
f(x+1,y-1)

+(-2)f(x-1,y) + 0f(x,y)+2*f(x+1,y)

+(-1)f(x-1,y+1) + 0f(x,y+1) + 1*f(x+1,y+1)

= [f(x+1,y-1)+2f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2f(x-1,y)+f(x-1,y+1)]

Gy =1* f(x-1, y-1) + 2f(x,y-1)+ 1f(x+1,y-1)

+0f(x-1,y) 0f(x,y) + 0*f(x+1,y)

+(-1)*f(x-1,y+1) + (-2)*f(x,y+1) + (-1)*f(x+1, y+1)

= [f(x-1,y-1) + 2f(x,y-1) + f(x+1,y-1)]-[f(x-1, y+1) + 2*f(x,y+1)+f(x+1,y+1)]
由上述公式计算得到Gy和Gx后,可以计算得到G的值,一个点的G的代表该点的梯度,如果大于某一设定范围则认为该点是边缘点。
这里写图片描述
为了提高效率 使用不开平方的近似值:
这里写图片描述
因为opencv对图像坐标的定义为原点在左上角角位置,如何一个像素点的坐标为(x,y),那么(x+1,y+1)在该点的左下角,以此类推可以知道其余8个坐标的位置。

Gx及Gy分别代表经横向及纵向边缘检测的图像灰度值,如果为一幅图像有竖直边缘,该竖直边缘的水平两侧灰度将存在差异,同理如果存在水平边缘,该边缘的垂直两侧灰度将存在差异,soble算子利用这种差异实现竖直边缘和水平边缘的检测。
在这里面验算过程太麻烦,贴个照片吧:
假设A是一个3*3的二值图像,计算A中心处那个点是否为边缘点,
这里写图片描述
显然计算结果为Gx = 4,Gy = 0,也就是说该点在水平方向上两侧是存在差异的,在垂直方向上不存在差异,所以是一个竖直边缘。

最后我们返回opencv代码去验证一下检测效果,首先对输入图片进行高斯滤波,分别进行sobel水平和垂直检测,为了方便观看检测效果,选用otsu算法对边缘检测后的结果进行阈值分割。代码如下:

Mat img_gray = imread("building.png",CV_LOAD_IMAGE_GRAYSCALE);  
Mat input = imread("building.png");  
imshow("原图",input);
blur(img_gray,img_gray,Size(5,5));  
imshow("滤波",img_gray);
vertical lines  
Mat img_sobel;  
Sobel(img_gray, img_sobel, CV_8U, 1, 0, 3, 1, 0, BORDER_DEFAULT);
imshow("检测垂直",img_sobel);
Mat img_sobel2; 
Sobel(img_gray, img_sobel2, CV_8U, 0, 1, 3, 1, 0, BORDER_DEFAULT);
imshow("检测水平",img_sobel2);
Mat img_threshold;  
threshold(img_sobel, img_threshold, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);  
imshow("检测垂直阈值分割",img_threshold);
Mat img_threshold2;  
threshold(img_sobel2, img_threshold2, 0, 255, CV_THRESH_OTSU+CV_THRESH_BINARY);  
imshow("检测水平阈值分割",img_threshold2);

我们选用一张棱角分明的建筑图片:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2waIX4TE-1586405516462)(https://img-blog.csdn.net/20170112102639957?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2hhaXBwMDYwNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]

进行灰度和滤波处理:

这里写图片描述

检测水平边缘并阈值分割:

这里写图片描述

这里写图片描述

检测竖直边缘并阈值分割:

这里写图片描述

这里写图片描述

soble算子对垂直和水平方向上的排列表达的较好,但对于其他角度的表达往往不够准确。

### OpenCVSobel算子的使用与实现 #### Sobel算子简介 Sobel算子是一种用于计算数字图像梯度的重要工具,在计算机视觉领域广泛应用。它通过两个 \(3 \times 3\) 的卷积核分别计算水平方向 (\(G_x\)) 垂直方向 (\(G_y\)) 的一阶偏导数,从而提取图像边缘信息[^4]。 #### 实现函数 `cv::Sobel` 在OpenCV库中,`cv::Sobel` 函数提供了便捷的方式来应用Sobel算子。以下是其基本语法: ```cpp void cv::Sobel( InputArray src, // 输入图像 OutputArray dst, // 输出图像 int ddepth, // 输出图像的深度 int dx, // x 方向上的导数阶数 int dy, // y 方向上的导数阶数 int ksize = 3, // 卷积核大小,默认为3 double scale = 1, // 缩放因子 double delta = 0, // 可选增量值 int borderType = BORDER_DEFAULT // 边界填充方式 ); ``` 其中,参数 `dx` `dy` 分别表示沿x轴y轴的方向导数阶次;当两者均为1时,则实现了标准的一阶Sobel算子操作[^2]。 #### Python代码示例 下面是一个简单的Python脚本,展示了如何使用OpenCV中的Sobel算子来检测灰度图的边缘: ```python import cv2 import numpy as np from matplotlib import pyplot as plt # 加载原始图片并转换成灰度模式 img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE) # 应用Sobel算子 sobelx = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) # 计算X方向梯度 sobely = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5) # 计算Y方向梯度 # 显示结果 plt.subplot(2,2,1), plt.imshow(img,cmap='gray') plt.title('Original'), plt.xticks([]), plt.yticks([]) plt.subplot(2,2,2), plt.imshow(sobelx,cmap='gray') plt.title('Sobel X'), plt.xticks([]), plt.yticks([]) plt.subplot(2,2,3), plt.imshow(sobely,cmap='gray') plt.title('Sobel Y'), plt.xticks([]), plt.yticks([]) plt.show() ``` 上述代码加载了一张名为 'image.jpg' 的图像文件,并对其执行了基于Sobel算子的边缘增强处理[^1]。 #### 结果解释 运行以上程序后可以看到原图以及经过Sobel滤波器处理后的效果对比图。这些效果图能够清晰显示出物体轮廓其他显著变化区域的位置信息[^3]。 #### 注意事项 为了防止数据溢出或者精度损失问题,在调用 `cv::Sobel()` 方法之前通常会指定较高的目标位深(如 CV_16S 或者 CV_64F)。另外还需要注意的是如果输入源是彩色RGB格式的话则需先转为单通道灰度形式再做进一步分析。 ---
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值