基于canny的亚像素的Devernay Algorithm

Block scheme of the algorithm
The two block schemes below show the differences between our algorithm and a classical Canny edge detector. We can see that the two block schemes are different only by the interpolation and the gradient stage. This shows that a good part of the original algorithm can be maintained, and that the changes to improve the quality of the edge detection aren’t too important.
Block scheme of the interpolating edge detector
在这里插入图片描述
Block scheme of the classical edge detector
在这里插入图片描述
《A Sub-Pixel Edge Detector: an Implementation of the Canny/Devernay Algorithm》Devernay基于canny算法做亚像素级别的优化:将新的边缘点定义为相邻几个梯度模值差值的最大值,通过计算梯度方向上相邻的三点处的梯度模值的二次函数插补。如下图所示:在这里插入图片描述
||g(A,B,C)||为三个垂直于边缘方向上的梯度模值,canny算法会选择模值最大的B点作为边缘点。但也可能在A和C之间存在点η ,在η 点处的梯度模值大于B点及AC之间的其他点,因此η 点能更好地表示边缘。论文[3]给出了估计η 点以及计算η 点偏移量的方法,并给出η 的亚像素位置。为减少计算量,论文中只用了三点来进行二次方程拟合,并求出相对于BC向量的补偿 η :
在这里插入图片描述
Devernay亚像素算法准确性,Devernay算法准确性的四个误差来源:

1.假设梯度满足二次曲线规律带来的误差;
2.使用有限项计算梯度值带来的误差;
3.插补计算时有些点的梯度并没有通过canny运算计算出来所带来的误差;(个人理解这里应该是说在非水平和垂直方向上)
4.数据误差;

以高斯边缘为例,公式:,其中是高斯核函数,Y是阶梯函数,即:
在这里插入图片描述
在这里插入图片描述
α 是阶梯函数的系数,图左是带亚像素偏移 γ 的高斯边缘特性,右图是使用抛物线估计的边缘点位置,例如途中三点abc,:(−1, a), (0, b) 和(1, c) ,边缘估计点的位置为:
在这里插入图片描述
把带偏移 γ 的高斯边缘函数带入,可得:
在这里插入图片描述
带入式中得:
在这里插入图片描述
右图中,高斯梯度与二次方程梯度极大值点偏差为:
在这里插入图片描述
文中给出了该误差的分布图:
在这里插入图片描述
当γ=0时,误差为0,因为此时边缘在网格中间位置;当γ=0.5时,误差也为0,因为此时a=b或b=c,二次曲线插补值可以给出正确的偏移;σ越小,边缘越锐利,而σ越大,边缘越模糊,误差反而越小。

公式说明了第二种误差来源,即有限差分计算带来的误差。

亚像素边缘算法改进
通过简单地使用水平和垂直方向插补可以有效去除第三种误差。Deverary使用三个点中间的插补值作为边缘, 这里进行修正:当点(x,y)处梯度满足以下条件,此时该点为水平方向的边缘点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
垂直方向的边缘点也是可以定义出来的。当x和y方向的梯度相等时,默认为还是水平边缘点,这个影响不大。修正方法的误差分布见下图:
在这里插入图片描述
对比可见修正方法的误差有了明显的减弱。另外,论文还对比了边缘是倾斜角度时的提取结果:
在这里插入图片描述
边缘点链(Edge Point Chaining)

此前检测边缘点是一个独立过程,每个边缘点并不相关。后续需要将属于同一个边缘轮廓的点集归到一起–链,形成轮廓。每个边缘点对应的应是一个像素点,而不是一个5*5的区域。

首先,被归为同一链路的像素点应该具有近似的梯度方向,以像素点A和B为例,它们的夹角应小于90度,数学表示为:g(A).g(B)>0。 另外,图像轮廓可以将亮区域和暗区域分开,所以连续的链路需要将暗区域划分到曲线的同一侧,一个简单的方法是验证从边缘点A到点B的向量与点A两个可能的梯度方向中的一个是否近似正交。有两个概念需要介绍一下:前向链路(forward chaining)和后向链路(back chaining)。当在这里插入图片描述 ,其中在这里插入图片描述表示向量v旋转90度,此时成为A-B的前向链路,记为:A->B,反方向称为反向链路。

一个边缘点至多有一个前向链路,也至多有一个后向链路,而不用有类似 Y 形状的链路。所以在确定AB是否成链前,需要检查A是否已经有前向链路和B是否已经有后向链路。此时可以通过距离来判断,如果新的链路比之前的距离短,那么之前链路就会被斩断,而增加这新的链路,经过这个步骤,边缘点的链接关系就能确定下来了。如:
在这里插入图片描述
A,B,C,D四点的距离关系满足:||A-B||>||B-C||>||C-D||,假定链路搜索顺序为:A-B-C;当A->B存在C->B,且CB距离小于AB,所以A->B会被切断;同样地,由于D的存在在C->B,也会被切断,所以最后的结果只剩下C->D。 再假定链路搜索顺序为C-B-A,经过判断过程,剩A->B下这条链路。 所以最后的链路结果为:A->B和C->D。
算法实现
整体流程
在这里插入图片描述
图像求梯度(在水平和垂直两个方向上求取梯度)
在这里插入图片描述
计算边缘点(求取边缘点及亚像素校正过程)
在这里插入图片描述
边缘点链路编码(是指边缘点的邻域集合,取5*5,括号里的数字2应该是说邻域集中上下左右不超过2个像素,最后的边缘点取其邻域水平或垂直方向上的局部最大值。过程中包含前向链路和后向链路,算是的子集)
在这里插入图片描述
canny双阈值
在这里插入图片描述
在线demo测试
http://ipolcore.ipol.im/demo/clientApp/demo.html?id=216

参考
http://m.chinaaet.com/article/3000015507

http://bigwww.epfl.ch/demo/subpixeledge/start.php

https://blog.csdn.net/piaoxuezhong/article/details/78664656

piaoxuezhong博主重新用opencv包装

  • 2
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
首先,要使用OpenCVSharp进行Canny边缘检测,需要将图像转换为灰度图像。然后,可以使用`Cv2.Canny()`方法进行边缘检测。如果要进行亚像素级别的边缘匹配,可以使用`Cv2.SubPixel()`方法进行亚像素级别的边缘匹配。 在进行并行计算时,可以使用`Parallel.For()`方法来对图像进行分块处理。这可以显著提高处理速度。例如,可以将图像分为多个块,并在每个块上运行Canny边缘检测和亚像素匹配。 以下是一个简单的示例代码,用于在OpenCVSharp中使用Canny边缘检测和亚像素级别的边缘匹配,并使用并行计算进行处理: ``` using System.Threading.Tasks; using OpenCvSharp; public class Program { static void Main() { Mat image = Cv2.ImRead("test.jpg"); Mat gray = new Mat(); Cv2.CvtColor(image, gray, ColorConversionCodes.BGR2GRAY); int blockSize = 100; // 每个块的大小 Parallel.For(0, image.Height / blockSize, y => { for (int x = 0; x < image.Width / blockSize; x++) { int blockX = x * blockSize; int blockY = y * blockSize; Rect blockRect = new Rect(blockX, blockY, blockSize, blockSize); Mat block = new Mat(gray, blockRect); Mat edges = new Mat(); Cv2.Canny(block, edges, 50, 150); Mat subPixelEdges = new Mat(); Cv2.SubPixel(edges, subPixelEdges, new Size(5, 5), new Size(-1, -1), new TermCriteria(CriteriaType.Count | CriteriaType.Eps, 20, 0.03)); subPixelEdges.CopyTo(gray[blockRect]); } }); Cv2.ImWrite("result.jpg", gray); } } ``` 在这个示例中,我们将图像分为100x100像素的块,并使用`Parallel.For()`方法对每个块进行处理。在每个块上,我们运行Canny边缘检测和亚像素匹配,并将结果复制回原始图像中。最后,我们将处理后的图像保存到文件中。 请注意,这只是一个示例代码。在实际应用中,您可能需要根据图像的大小和处理需求来调整块的大小和并行计算的线程数。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值