OpenCV Sobel算子水平和垂直方向导数问题
2017-01-12 10:33
309 查看
sobel算子是一种常用的边缘检测算法,在各种论文或书籍中,我们常常能看到类似这样的话,被检测的对象存在大量的竖直边,所以可以采用sobel算子来找到第一个水平导数,它可以用来在图像中查找竖直边缘。
它在opencv中的原型如下:
第一个参数,输入图像,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阶导数用来检测水平边缘。
根据soble算子的数学推导:
当内核为3*3时,横向和纵向方向上的卷积因子分别为:
假设原图像为A,分别做卷积可以得到:
具体运算为:
Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1)
+(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y)
+(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1)
= [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)]
Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1)
+0*f(x-1,y) 0*f(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代码去验证一下检测效果,首先对输入图片进行高斯滤波,分别进行soble水平和垂直检测,为了方便观看检测效果,选用otsu算法对边缘检测后的结果进行阈值分割。代码如下:
我们选用一张棱角分明的建筑图片:
进行灰度和滤波处理:
检测水平边缘并阈值分割:
检测竖直边缘并阈值分割:
soble算子对垂直和水平方向上的排列表达的较好,但对于其他角度的表达往往不够准确。
它在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阶导数用来检测水平边缘。
根据soble算子的数学推导:
当内核为3*3时,横向和纵向方向上的卷积因子分别为:
假设原图像为A,分别做卷积可以得到:
具体运算为:
Gx = (-1)*f(x-1, y-1) + 0*f(x,y-1) + 1*f(x+1,y-1)
+(-2)*f(x-1,y) + 0*f(x,y)+2*f(x+1,y)
+(-1)*f(x-1,y+1) + 0*f(x,y+1) + 1*f(x+1,y+1)
= [f(x+1,y-1)+2*f(x+1,y)+f(x+1,y+1)]-[f(x-1,y-1)+2*f(x-1,y)+f(x-1,y+1)]
Gy =1* f(x-1, y-1) + 2*f(x,y-1)+ 1*f(x+1,y-1)
+0*f(x-1,y) 0*f(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代码去验证一下检测效果,首先对输入图片进行高斯滤波,分别进行soble水平和垂直检测,为了方便观看检测效果,选用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);
我们选用一张棱角分明的建筑图片:
进行灰度和滤波处理:
检测水平边缘并阈值分割:
检测竖直边缘并阈值分割:
soble算子对垂直和水平方向上的排列表达的较好,但对于其他角度的表达往往不够准确。
相关文章推荐
- 对OpenCV mat进行水平和垂直方向的投影
- inline-block 属性的元素水平方向,垂直方向 间隙问题
- img (内联元素) (inline元素) 标签上下左右间隙问题原因及解决方案: 垂直方向间隙和水平方向间隙原因及解决方案:
- js控制图片缩放、水平和垂直方向居中对齐
- 未知大小图片在已知容器中的垂直和水平居中问题
- ipad开发中遇到的垂直模式和水平模式返回同样的view的尺寸问题
- Sobel算子实现水平边缘检测、垂直边缘检测;45度、135度角边缘检测
- 未知大小图片在容器的垂直和水平居中问题
- 水平和垂直方向的三级PopMenu-弹出菜单(DIV+CSS+JS)
- 未知大小图片在已知容器中的垂直和水平居中问题
- 在HTML页面中设置表格水平和垂直方向都居中的方法【原
- 水平垂直居中问题
- 未知大小图片在已知容器中的垂直和水平居中问题
- 我有个DIV层,里面放一张图片,我如何让这张图片水平和垂直方向都居中呢???
- 01-1 窗体水平移动、垂直移动、斜方向移动、随即移动的方法。
- 禁止uiscrollview垂直方向滚动,只允许水平方向滚动;或只允许垂直方向滚动
- ASP.NET 2.0提供了一个Menu 类,可以方便地创建水平或者垂直方向的下拉菜单,
- AndroidGUI23:水平方向和垂直方向同时滚动
- 点击链接,弹出最大化窗口或者水平和垂直方向都居中的小窗口
- 未知大小图片在容器的垂直和水平居中问题