1. 前言

众所周知,在传统的图像边缘检测算法中,最常用的一种算法是利用Sobel算子完成的。Sobel算子一共有

个,一个是检测水平边缘的算子,另一个是检测垂直边缘的算子。

2. Sobel算子优缺点

Sobel算子的优点是可以利用快速卷积函数,简单有效,且对领域像素位置的影响做了加权,可以降低边缘模糊程度,有较好效果。然而Sobel算子并没有基于图像的灰度信息进行处理,所以在提取图像边缘信息的时候可能不会让人视觉满意。

3. 手动构造Sobel算子

我们来看一下怎么构造Sobel算子?

Sobel算子是在一个坐标轴的方向进行非归一化的高斯平滑,在另外一个坐标轴方向做一个差分,

大小的Sobel算子是由

平滑算子差分算子全卷积得到,其中

代表Sobel算子的半径,必须为奇数。

对于窗口大小为

非归一化Sobel平滑算子等于

阶的二项式展开式的系数,而

Sobel平滑算子等于

阶的二项式展开式的系数两侧补
,然后向前差分。

举个例子:构造一个

阶的Sobel非归一化的

Sobel平滑算子和Sobel差分算子

Sobel平滑算子: 取二项式的阶数为

,然后计算展开式系数为,
也即是
,这就是
阶的非归一化的Sobel平滑算子。

Sobel差分算子:取二项式的阶数为

,然后计算二项展开式的系数,即为:
,两侧补
并且前向差分得到
,第
项差分后可以直接删除。

Sobel算子

阶的Sobel平滑算子和Sobel差分算子进行全卷积

,即可得到

的Sobel算子。

其中

方向的Sobel算子为:

方向的Sobel算子为:

4. 代码实现

const int fac[9]={1, 1, 2, 6, 24, 120, 720, 5040, 40320};
//Sobel平滑算子
Mat getSmmoothKernel(int ksize){Mat Smooth = Mat::zeros(Size(ksize, 1), CV_32FC1);for(int i = 0; i < ksize; i++){Smooth.at<float>(0, i) = float(fac[ksize-1]/(fac[i] * fac[ksize-1-i]));}return Smooth;
}
//Sobel差分算子
Mat getDiffKernel(int ksize){Mat Diff = Mat::zeros(Size(ksize, 1), CV_32FC1);Mat preDiff = getSmmoothKernel(ksize-1);for(int i = 0; i < ksize; i++){if(i == 0){Diff.at<float>(0, i) = 1;}else if(i == ksize-1){Diff.at<float>(0, i) = -1;}else{Diff.at<float>(0, i) = preDiff.at<float>(0, i) - preDiff.at<float>(0, i-1);}}return Diff;
}
//调用filter2D实现卷积
void conv2D(InputArray src, InputArray kernel, OutputArray dst, int dep, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT){Mat kernelFlip;flip(kernel, kernelFlip, -1);filter2D(src, dst, dep, kernelFlip, anchor, 0.0, borderType);
}
//先进行垂直方向的卷积,再进行水平方向的卷积
void sepConv2D_Y_X(InputArray src, OutputArray dst, int dep, InputArray kernelY, InputArray kernelX, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT){Mat Y;conv2D(src, kernelY, Y, dep, anchor, borderType);conv2D(Y, kernelX, dst, dep, anchor, borderType);
}
//先进行水平方向的卷积,再进行垂直方向的卷积
void sepConv2D_X_Y(InputArray src, OutputArray dst, int dep, InputArray kernelX, InputArray kernelY, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT){Mat X;conv2D(src, kernelX, X, dep, anchor, borderType);conv2D(X, kernelY, dst, dep, anchor, borderType);
}
//Sobel算子提取边缘信息
Mat Sobel(Mat &src, int x_flag, int y_flag, int kSize, int borderType){Mat Smooth = getSmmoothKernel(kSize);Mat Diff = getDiffKernel(kSize);Mat dst;if(x_flag){sepConv2D_Y_X(src, dst, CV_32FC1, Smooth.t(), Diff, Point(-1, -1), borderType);}else if(x_flag == 0 && y_flag){sepConv2D_X_Y(src, dst, CV_32FC1, Smooth, Diff.t(), Point(-1, -1), borderType);}return dst;
}
int main(){Mat src = imread("../lena.jpg");Mat gray;cvtColor(src, gray, CV_BGR2GRAY);Mat dst1 = Sobel(gray, 1, 0, 3, BORDER_DEFAULT);Mat dst2 = Sobel(gray, 0, 1, 3, BORDER_DEFAULT);//转8位灰度图显示convertScaleAbs(dst1, dst1);convertScaleAbs(dst2, dst2);imshow("origin", gray);imshow("result-X", dst1);imshow("result-Y", dst2);imwrite("../result.jpg", dst1);imwrite("../result2.jpg", dst2);waitKey(0);return 0;
}

5. 效果

可以看到两种不同的操作顺序会获得不完全一样的边缘检测效果。

6. 结论

这篇文章介绍了边缘检测是如何手动构造的,只要熟记二项式展开的系数,以此为出发点就比较好分析了。后面的源码实现也是比较朴素的实现,如果你想加速那么重心可以放在filter2D也即是卷积操作上,以后会来分享的。


欢迎关注GiantPandaCV, 在这里你将看到独家的深度学习分享,坚持原创,每天分享我们学习到的新鲜知识。( • ̀ω•́ )✧

有对文章相关的问题,或者想要加入交流群,欢迎添加BBuf微信:

https://u.wechat.com/MPWFDnmCPu6zgf5YUtdpT_U (二维码自动识别)

sobel算子_OpenCV图像处理专栏十八 | 手动构造Sobel算子完成边缘检测相关推荐

  1. c++ opencv编程实现暗通道图像去雾算法_OpenCV图像处理专栏十五 |一种基于亮度均衡的图像阈值分割技术...

    前言 对于光照不均匀的图像,用通常的图像分割方法不能取得满意的效果.为了解决这个问题,论文<一种基于亮度均衡的图像阈值分割技术>提出了一种实用而简便的图像分割方法.该方法针对图像中不同亮度 ...

  2. c++ opencv编程实现暗通道图像去雾算法_OpenCV图像处理专栏十三 | 利用多尺度融合提升图像细节...

    前言 今天为大家介绍一个利用多尺度来提升图像细节的算法.这个算法来自于论文<DARK IMAGE ENHANCEMENT BASED ON PAIRWISE TARGET CONTRAST AN ...

  3. opencv 图像雾检测_专栏 | OpenCV图像处理专栏十 | 利用中值滤波进行去雾

    原标题:专栏 | OpenCV图像处理专栏十 | 利用中值滤波进行去雾 前言 这是OpenCV图像处理专栏的第十篇文章,介绍一种利用中值滤波来实现去雾的算法.这个方法发表于国内的一篇论文,链接我放附录 ...

  4. [Python图像处理] 三十八.OpenCV图像增强和图像去雾万字详解(直方图均衡化、局部直方图均衡化、自动色彩均衡化)

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

  5. [Python图像处理] 二十八.OpenCV快速实现人脸检测及视频中的人脸

    该系列文章是讲解Python OpenCV图像处理知识,前期主要讲解图像入门.OpenCV基础用法,中期讲解图像处理的各种算法,包括图像锐化算子.图像增强技术.图像分割等,后期结合深度学习研究图像识别 ...

  6. OpenCV图像处理学习十八,霍夫变换实现交通车道线检测

    一.霍夫变换 经典霍夫变换用来检测图像中的直线,后来霍夫变换经过扩展可以进行任意形状物体的识别,例如圆和椭圆.霍夫变换运用两个坐标空间之间的变换,将在一个空间中具有相同形状的曲线或直线映射到另一个坐标 ...

  7. halcon区域腐蚀膨胀算子_OpenCV 图像处理之膨胀与腐蚀

    1.什么是膨胀与腐蚀 膨胀与腐蚀属于形态学范围,具体的含义根据字面意思来理解即可.但是更形象的话就是"增肥"与"减肥". 它们的用途就是用来处理图形问题上.总结 ...

  8. [Python从零到壹] 五十八.图像增强及运算篇之图像锐化Sobel、Laplacian算子实现边缘检测

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

  9. [Python从零到壹] 三十八.图像处理基础篇之图像几何变换(平移缩放旋转)

    欢迎大家来到"Python从零到壹",在这里我将分享约200篇Python系列文章,带大家一起去学习和玩耍,看看Python这个有趣的世界.所有文章都将结合案例.代码和作者的经验讲 ...

最新文章

  1. P1843 奶牛晒衣服(贪心)
  2. python字典get计数_python字典中的get方法与setdefault方法
  3. Linux云自动化运维第六课
  4. domains where phd is best in business school
  5. innerHTML和value的区别
  6. HTTP请求头,应答头类型相关问题
  7. android 字体点击变色,Android TextView 中实现部分文字变色以及点击事件
  8. virtualenv之python虚拟环境
  9. EJB Remote/Local 绑定和JNDI Lookup
  10. python selenium加速_selenium2.0环境搭建(一)
  11. Oracle DBHelper 第二版
  12. 设计python游戏贪吃蛇_Python 贪吃蛇游戏
  13. ECharts实现数据可视化入门教程(超详细)
  14. 服务器收到syn包不回消息,TCP:SYN请求接收SYN响应代替SYN-ACK
  15. 微信接口昵称在服务器乱码,微信网页开发获取用户昵称乱码 微信昵称包含emoji表情乱码的解决方案...
  16. 2018.10.27 bzoj1984: 月下“毛景树”(树链剖分)
  17. React基础(肆)———状态和循环渲染
  18. R语言绘制生存曲线估计|生存分析|如何R作生存曲线图
  19. C. The Intriguing Obsession[组合数学]
  20. 644.奇怪的打印机(困难)

热门文章

  1. oracle命令解锁用户,在命令行下进行Oracle用户解锁的语句
  2. 【JoJo的摄影笔记】重新来聊聊镜头
  3. mybatis generator 生成数据库注释等问题
  4. Android 通过adb命令操作
  5. 平面向量内积坐标公式推导_平面向量内积的坐标表示.ppt
  6. 酱油详细 酿造工艺、等级划分、国家标准号,和选购食用注意事项
  7. 0. Canal 的安装和使用
  8. excel 调用barTender打印条码 VBA 调用BarTender打印标签BarTender二次开发 VBA 条码打印 VBA二维码打印 Excel条码打印 Excel二维码打印
  9. Python | numpy库 | shape函数与reshape函数
  10. Dubbo:Zookeeper安装+Dubbo管理控制台部署