一种基于网格点来检测网格线的方法(可用于Camera Calibration)

版权声明:本文为博主原创文章,未经博主允许不得转载。需要转载请留言或发送邮件([email protected]),并注明出处。 https://blog.csdn.net/u013512448/article/details/61209273

声明:该方法由博主原创,希望能互相尊重劳动成果,转载请先征求博主的同意。

联系方式:[email protected]

1、问题

最近解决了一个网格线检测问题:给定一系列网格点坐标,检测出对应的精确的网格线的方法。如下图:


2、想法

说到直线检测,大家可能第一反应就是采用霍夫变换(HT)。但HT在解决这个问题上却不是那么完美。

首先,HT的时间复杂度较高,比较费时。其次,因为图像中的每一个离散点经过HT后对应一条直线,然后经过投票环节,选出直线经过次数最多的某一点(或若干点),将该点变换回原图像即为所求直线(具体请参阅霍夫变换相关文档)。但在检测网格线问题中,格点是比较稀疏的,如果采用HT经过投票环节脱颖而出的直线并不具备明显的得票优势。以此图为例,限制条件严格会导致选不够理想的四条直线,放松限制条件又会导致选出的直线并非理想。

因此,霍夫变换并不适合解决此问题,主要原因在于网格点数量较少。其次是霍夫变换时间复杂度较高,不适用于实时性较高的场景。

3、思路

3.1尽可能得到接近于理想直线的四束直线
出于尝试的目的,我将所有网格点两两连线,得到了如下的结果:



发现其中四束直线比较接近于理想的网格线。于是我尝试性地仿照霍夫变换的思想,将所有直线按照直线方程斜截式(k-b)参数变换到k-b空间,每一条直线对应一个点。得到如下结果(横轴对应斜率k,纵轴对应截距b)


在k-b空间可以看出明显的四个集聚的区域,但可以看到其中还是有许多干扰点,因此需要尽可能排除掉干扰直线。于是在这一步的基础上将每一个格点与其最近的格点连接,得到了如下结果:


得到四束接近于理想网格线的直线,几乎除掉了所有的干扰线。同样地将这四束直线变换到k-b空间。

3.2 参数化

最先想到的方法是用K-means在k-b空间进行分类。但结果不是很理想,主要有两个问题:

1、K-means分类的结果与初始值的选取有关,不同的初始值可能会导致不同的分类结果。

2、k-b空间的量化并不均匀。因为斜率k的取值范围是从[0,∞],例如当直线与X轴夹角接近于90度时,极小的角度变化都会导致斜率k的巨大变化。如下图的情况:



编号1,2的两束直线因为趋向于水平,所以k的绝对值较小,此时角度的变化对k的影响不大,集聚性较好。但编号3,4的两束直线趋向于垂直,所以极小的角度差异都会导致K值的巨大差异,集聚性较差。

因为初始值是随机选取的,所以k-means将编号3和编号4的两束直线错误地归为了一类。


于是我想到了采用直线的法线式方程:x·cosθ+ysinθ-p=0 。过原点向直线做一条的垂线段,该垂线段所在直线的倾斜角为θ,p是该线段的长度。

theta能很均匀的量化角度,因此直线在p-theta空间中的集聚性很好,便于分类。此外,经过实际检验,p并没有采用严格意义上的线段长度,而是引入了截距b的符号,所以p=sign(b)*|p|。

直线变换到p-theta空间如下图,可以看出集聚性很好。




3.2 分类

鉴于k-means不够鲁棒,我想到了一个用无向图来分类的方法。


1、建立邻接矩阵并置0。

2、遍历p-theta空间的每一个点并检测其周围符合条件(|Δtheta|<0.2&&|Δp|<10)的点并在邻接矩阵对应位置置1。

3、在本文的情况下,无向图与无向图之间是非连通的。因此先选取一个符合条件(至少有2个邻接顶点且未被标记类别)的点作为搜索入口进行搜索,所有访问到的点都要标记类别。

4、重复第3步直到遍历完所有点。

5、返回标记结果,并对每个类别的格点进行最小二乘拟合,拟合的直线即为所求网格线。


4、结果

1.即使连线不够完美,也能很好的排除掉干扰线。

2.c++代码的运行时间在0.04ms左右。




猜你喜欢

转载自blog.csdn.net/u013512448/article/details/61209273