一、边的提取
在这篇论文中,作者提出了一种新的边缘检测算法,主要优势在于提取出来的线能够保持清晰、连续,在边的提取部分,主要是进行了四步操作:
①滤波
使用高斯滤波器进行处理,过滤噪声并且使图像能够更加平滑。
②梯度的计算
遍历图中的每个像素,计算像素的梯度值,这一部分其实计算的是一个简易的梯度,和真正的梯度计算还是有区别的,这一点会在后面讲到。
③锚的筛选
遍历图中的每个像素,筛选出一部分与相邻元素梯度相差很大的像素,这部分像素称为锚(anchor),这部分像素有很高的可能性是边上的一部分。
④连接锚形成边
这部分主要是从一个锚出发,根据像素的梯度和线的延伸方向,从点开始不断延伸成边。
这张图表示的就是一个边的提取的过程,首先将灰度图作为输入,计算梯度之后也就是完成第二步后,图就变成了图b的形式,之后根据像素的梯度值,提取出锚,也就是图c的样子,在此基础上连接锚,最后形成了图d中的样子,也就是边缘提取的结果。
二、线段的提取
在上一部分中,我们仅仅是完成了边缘的提取,但是这个边缘有可能是连接在一起的,还是上图的例子,边缘提取的结果可能是整个矩形,但是我们要的是四条直线的边,所以就需要对边缘进行分割,得到线段。也就是说,这一步的目标,就是将像素链拆分成一条或者多条的直线段。
主要的方法依然是用遍历,这次是遍历整个边,利用最小二乘法去做筛选,直到错误达到一个阈值。作为函数来说,输入包括一个最短距离、存储边上像素位置的数据结构以及当前的位置,线段的提取函数就会从当前位置,读取最短距离的边,看这个短边是不是符合要求,也就是计算一个合适度,如果符合要求,那么就认为这个短边是一个初始化短边,就在这个的基础上,不断向里面加入新的像素,加入的像素必须与当前的线足够近,从代码来看,这个部分遍历了这条边,对于离线距离较远的点,就记为噪声点,如果连续出现三个噪声点,就停止遍历,直接放弃给当前的初始化短边继续添加,否则就将噪声点记录归零,重新统计。在此基础上,一条边最多进行六次的线段划分。也就是说,论文中所谓的检测角落和方向,本质上就是检测了距离,如果出现了拐角,那么拐角的点到线的距离必然会增加,出现连续三个,就会停止延伸。添加停止之后,就会进行一个检验,如果符合检验就将提取出来的线段存储下来,剩余的线继续进行提取。
三、线段的检测
线段的检测这部分主要还是利用了Helmholtz principle,前面稍微总结过一点:https://blog.csdn.net/weixin_43849505/article/details/122640587?spm=1001.2014.3001.5501
在这里,线段检测的主要方法就是计算NFA值:
其中p表示一个概率值,这个取值与方向的划分有关,在检测时,主要是遍历这条线段,找出与线同向的点,然后用这个公式去计算,结果一般与1进行比较,如果大于1就会被拒绝。
当然,这个计算时很耗费时间的,因为要遍历整个的一条线,论文中也提到了,对于一些长度较长的线,一般并不会在计算NFA的时候被拒绝,被拒绝的一般都是一些短线,所以如果需要节省时间,可以加一个根据长度的判断,如果长度超过一定的值就进行一般的检验,短线则进行NFA的计算。
四、算法参数的设定
这部分论文主要介绍了算法的一些细节,包括参数的设置和计算的内容。
①梯度和方向
前面也提到过,这里的梯度计算实际上是一个简化版,这里就介绍了这里的梯度计算方法:
这里论文使用这种梯度计算,主要是为了减少时间上的开销,从而尽可能多地计算更多像素的信息。
②线检测参数
这个参数指的主要就是方向的划分,一般为了计算的方便,都将180度分为好几份,如果分为8份,那么每份就是22.5°,也就是说只要两个方向的偏差不超过22.5°,我们就认为两个方向是同向的,这个反应到算法里,影响到的主要就是NFA的计算中p的取值,划分为8份,那么p的取值就是八分之一。
③梯度阈值、锚阈值和扫描间隔
梯度阈值主要是在根据梯度图计算锚的时候,一些梯度很小的点由于大概率不会出现在边的上面,所以就不会是锚,所以我们可以直接去掉,从而在检测锚的时候就可以少计算一些点。
锚阈值则更像是为了优中选优,一般来说如果按照的思路去计算梯锚,只要比临近的两个像素的强度大就有可能被筛选为锚,而这里引入锚阈值,要求邻近的像素必须要比当前像素小锚阈值才可以被认为是锚,从而让筛选出来的锚更加具有代表性。
扫描间隔就没什么好说的了,就是在扫描锚的时候,行与行之间的间隔。
④线适应阈值
这个就没什么好说的,本质上就是减少计算的一个快捷方法,主要是利用NFA值要大于1这个条件,对n进行筛选,也就是线段长度,对于一个512×512的图片,如果提取出来的线段长度小于12就根本没有计算的必要,因为一定不会满足NFA的要求。
ELSED: Enhanced line SEgment drawing
这篇文章是一篇很新的对EDLine的改进,发表在2022年的pattern recognition上,这里简单补充一下改进的内容。
这篇论文并没有大改EDLine锚点连线的机制,而是对锚点延伸过程的细节做了改进,一个是减小了边在延伸时探测的点的数量,只选取了更可靠的方向进行延伸。左侧的图a表示的是EDLine里面ED算法的延伸机制,蓝色表示上一个像素,粉色的表示的是现在延伸到的像素,当上一个像素和当前像素的方向不同时,ED算法会根据当前像素的方向,确定6个方向的候选像素,对这六个像素进行检测。而改进的EED算法则进一步考虑了上一个像素方向产生的影响,将延伸方向缩短到两个或者三个,从而进一步减小候选像素的数量。
另外一点就是更改了延伸的策略,EDLine会沿着当前像素的方向移动,如果遇到某个像素的方向突然发生了变化,就会按照变化以后的方向去延伸。而ELSED会优先沿着当前线段的方向继续去提取,同时利用一个堆栈存储拐歪的方向,也就是论文中所说的discontinuity。
参照下面的效果图b,蓝色点为一个锚点,延伸之后沿着序号顺序先提取出①-⑤,在提取过程中我们简单将每个交叉点都认为出现了不连续,转弯后的方向存入单独的堆栈,提取完⑤之后,由于线段再向前已经到图片边缘了,所以取出堆栈中最上面的一个方向,也就是上一个不连续点的拐弯后的方向,所以沿着新的方向提取出⑥-⑨,后面就重复这个操作,直到所有的方向都提取完。
上面的延伸过程中,很重要的一点在于如何保持当前方向继续寻找,ELSED采用了跳跃的方法,不仅实现了继续寻找,还同时解决断裂的问题,该方法每当检测到断裂的位置,也就是论文中的discontinuity,就会尝试沿着当前方向跳跃一段,跳跃的有三种:5、7、9像素,只有符合四个条件的情况才能够进行跳跃:
跳跃之后继续尝试延伸,如果能够达到要求,简单来说就是如果跳了5个像素,那么在继续延伸的过程必须要保证也至少有五个像素能够延伸到,并且继续延伸的像素拟合出的线段应该要和当前线段对齐。满足的情况下就认为这是一条长线段但是中间有几个像素的断裂,最后断线会被整合成一条长线段。