最好的圆拟合算法

时间:2010-12-08 12:37:23

标签: image-processing geometry computer-vision

我需要一个非常精确的算法来将圆拟合到数据点集(实际上我需要确定中心)。数据在图像的二值化和分割之后出现。 我尝试了简单的质心和加权质心算法以及预制的OpenCv :: fitEllipse函数。我已经从OpenCV函数中获得了最好的结果,但仍然不够准确。当中心锚定在子像素区域时,结果显着受损。 即使在处理模型化数据时,我获得的准确性也是不够的,这是不好的,因为最终,程序将不得不处理由相机捕获的数据。 您有什么建议我应该寻找什么样的算法,或者您有任何现成的解决方案吗?我宁愿不要连接任何外部库。 谢谢你的帮助。 alt text

编辑: 校准目标可以在视野的任何区域中定位。以下是我使用OpenCV程序获得的最佳结果:

169,367 748,345  
167,557 820,788  
165,690 893,158  
164,047 965,197  
162,715 1036,729  
161,575 1108,089  
160,477 1179,552  
233,297 1015,313  
232,076 1086,965  
220,359 1229,578  
268,494 1160,275  
339,544 1162,980  
362,017 1235,669  
433,390 1238,491  
482,754 1168,299  
505,233 1241,039  
554,856 1170,664  
577,302 1243,439  
627,331 1172,795  
649,507 1245,665  
713,572 588,896  
711,995 661,853  
710,440 735,034  
708,722 808,856  
707,018 882,674  
705,377 956,169  
703,609 1029,211  
701,716 1101,950  
699,760 1174,689  
721,895 1247,620  
785,829 614,754  
784,344 687,750  
782,819 761,315  
781,292 835,225  
779,389 908,975  
777,619 982,335  
775,688 1055,275  
773,672 1128,091  
771,603 1200,724  

编辑:数字生成的模型和中心的真实坐标: alt text

51,1    79,8
51,1    179,8
51,1    279,8
51,1    379,8
51,1    479,8
51,1    579,8
51,1    679,8
51,1    779,8
51,1    879,8
51,1    979,8
51,1    1079,8
51,1    1179,8
51,1    1279,8
51,1    1379,8
51,1    1479,8
151,1   79,8
151,1   179,8
151,1   279,8
151,1   379,8
151,1   479,8
151,1   579,8
151,1   679,8
151,1   779,8
151,1   879,8
151,1   979,8
151,1   1079,8
151,1   1179,8
151,1   1279,8
151,1   1379,8
151,1   1479,8
251,1   79,8
251,1   179,8
251,1   279,8
251,1   379,8
251,1   479,8
251,1   579,8
251,1   679,8
251,1   779,8
251,1   879,8
251,1   979,8
251,1   1079,8
251,1   1179,8
251,1   1279,8
251,1   1379,8
251,1   1479,8
351,1   79,8
351,1   179,8
351,1   279,8
351,1   379,8
351,1   479,8
351,1   579,8
351,1   679,8
351,1   779,8
351,1   879,8
351,1   979,8
351,1   1079,8
351,1   1179,8
351,1   1279,8
351,1   1379,8
351,1   1479,8
451,1   79,8
451,1   179,8
451,1   279,8
451,1   379,8
451,1   479,8
451,1   579,8
451,1   679,8
451,1   779,8
451,1   879,8
451,1   979,8
451,1   1079,8
451,1   1179,8
451,1   1279,8
451,1   1379,8
451,1   1479,8
551,1   79,8
551,1   179,8
551,1   279,8
551,1   379,8
551,1   479,8
551,1   579,8
551,1   679,8
551,1   779,8
551,1   879,8
551,1   979,8
551,1   1079,8
551,1   1179,8
551,1   1279,8
551,1   1379,8
551,1   1479,8
651,1   79,8
651,1   179,8
651,1   279,8
651,1   379,8
651,1   479,8
651,1   579,8
651,1   679,8
651,1   779,8
651,1   879,8
651,1   979,8
651,1   1079,8
651,1   1179,8
651,1   1279,8
651,1   1379,8
651,1   1479,8
751,1   79,8
751,1   179,8
751,1   279,8
751,1   379,8
751,1   479,8
751,1   579,8
751,1   679,8
751,1   779,8
751,1   879,8
751,1   979,8
751,1   1079,8
751,1   1179,8
751,1   1279,8
751,1   1379,8
751,1   1479,8
851,1   79,8
851,1   179,8
851,1   279,8
851,1   379,8
851,1   479,8
851,1   579,8
851,1   679,8
851,1   779,8
851,1   879,8
851,1   979,8
851,1   1079,8
851,1   1179,8
851,1   1279,8
851,1   1379,8
851,1   1479,8
951,1   79,8
951,1   179,8
951,1   279,8
951,1   379,8
951,1   479,8
951,1   579,8
951,1   679,8
951,1   779,8
951,1   879,8
951,1   979,8
951,1   1079,8
951,1   1179,8
951,1   1279,8
951,1   1379,8
951,1   1479,8
1051,1  79,8
1051,1  179,8
1051,1  279,8
1051,1  379,8
1051,1  479,8
1051,1  579,8
1051,1  679,8
1051,1  779,8
1051,1  879,8
1051,1  979,8
1051,1  1079,8
1051,1  1179,8
1051,1  1279,8
1051,1  1379,8
1051,1  1479,8
1151,1  79,8
1151,1  179,8
1151,1  279,8
1151,1  379,8
1151,1  479,8
1151,1  579,8
1151,1  679,8
1151,1  779,8
1151,1  879,8
1151,1  979,8
1151,1  1079,8
1151,1  1179,8
1151,1  1279,8
1151,1  1379,8
1151,1  1479,8

5 个答案:

答案 0 :(得分:20)

使用图像变换和聚类的算法


我使用图像转换和一些统计来制作一个小算法来检测你的圈子。让我们看看它是否符合您的错误预期 任何好的图像和统计库都可以,我使用Mathematica实现它。

运行如下:

1.导入图像并运行Bottom Hat Transform

我们开始尝试隔离圈子。带有Box Matrix内核的Bottom Hat Transform会有所帮助。几乎所有图像库都附带已经实现的算法。

a = Import@"http://i.stack.imgur.com/hiSjj.png";   
b = BottomHatTransform[Binarize@a, BoxMatrix[30]]  

结果是

alt text

2.运行Hit Miss Transform以隔离圆圈

The Hit Miss Transform擅长查找定义良好的几何对象。它也很容易编程,几乎总是出现在图像库中。

c = Binarize@HitMissTransform[b, DiskMatrix[20]]

结果是:

alt text

我们的圈子已经被孤立并缩减为核心。

3.仅获取图像中的白色像素

这是一个依赖于实现的步骤,因此我不会对此进行评论。

ttflat = Flatten[Table[{i, j, ImageData[c][[i, j]]}, {i, 1232}, {j, 1624}], 1];  
ttfilter = Select[ttflat, #[[3]] == 1 &];  

让我们看看剩下多少像素

Dimensions@ttfilter  
{3684, 3}   

剩下3684像素,每圈几乎82像素。足够做一些统计。

3.使用Cluster Analysis选择每个圆

群集分析在这里可能有点过分,但是我已经实现了它,比使用新的程序更容易使用它:)。您可以自己动手或使用统计库。

ttc = FindClusters[ttfilter, 45, Method -> {"Agglomerate", "Linkage" -> "Complete"}];

通过找到我们的聚类,让我们找到每个聚类中x和y的均值。这些是圈子的中心:

means = N[Mean /@ ttc, 5]  

结果是45个坐标的列表,如:

{{161.67, 1180.1}, {162.75, 1108.9}, 
 {164.11, 1037.6}, {165.47, 966.19} .....  

我们差不多完成了。

让我们检查一下我们的结果。我们叠加了两个图像,在检测到的中心周围绘制了十字和圆圈。

alt text

Click to enlarge,这样您就可以了解所涉及的错误。

HTH!

修改

我将您的表格中的结果与我的结果进行了比较。

假设圆是直线的,我使用最小二乘拟合来追踪一条线并计算残差。

从下面的图表中可以看出,“M”y线比我们的“Y”更合适。但这是假设圆圈对齐......

alt text

编辑2

这些是第二张图片中前45个圆圈的计算坐标。我有1像素的系统偏移。可能是由于我做了一些图像操作,但很容易纠正:) ...只是在X和Y上减去一个像素...

{{51.135, 79.692}, {51.135, 179.69}, {51.135, 279.69},{51.135, 379.69}, {51.135, 479.69},
 {51.135, 579.69}, {51.135, 679.69}, {51.135, 779.69},{51.135, 879.69}, {51.135, 979.69}, 
 {51.135, 1079.7}, {51.135, 1179.7}, {51.135, 1279.7},{51.135, 1379.7}, {51.135, 1479.7}, 
 {151.13, 79.692}, {151.13, 179.69}, {151.13, 279.69},{151.13, 379.69}, {151.13, 479.69},
 {151.13, 579.69}, {151.13, 679.69}, {151.13, 779.69},{151.13, 879.69}, {151.13, 979.69}, 
 {151.13, 1079.7}, {151.13, 1179.7}, {151.13, 1279.7},{151.13, 1379.7}, {151.13, 1479.7}, 
 {251.13, 79.692}, {251.13, 179.69}, {251.13, 279.69},{251.13, 379.69}, {251.13, 479.69}, 
 {251.13, 579.69}, {251.13, 679.69}, {251.13, 779.69},{251.13, 879.69}, {251.13, 979.69}, 
 {251.13, 1079.7}, {251.13, 1179.7}, {251.13, 1279.7},{251.13, 1379.7}, {251.13, 1479.7}}

这是图像:

alt text

答案 1 :(得分:3)

“最佳”取决于输入数据中的噪声类型。如果源数据点中没有噪声,则问题很简单:只需选择3个点并计算圆圈。

如果您期望每个数据点的正态分布式独立转换,那么最小均方算法应该是最优的。数据点应符合以下等式:

(x - xm)^2 + (y - ym)^2 = r^2

其中xmymr未知,所以:

x^2 - 2*x*xm + xm^2 + y^2 - 2*y*ym + ym^2 = r^2

c替换为r^2-xm^2-ym^2,你有一个超定的线性方程组:

2*x*xm + 2*y*ym = c - x^2 - y^2

任何好的线性代数库(例如IPP)都可以为你解决这个问题。

如果你期望数据中存在异常值,我建议使用RANSAC策略来找到非离群点的集合,然后使用上面的算法找到该集合的确切中心。

答案 2 :(得分:3)

如果圆的半径已知(且常数),要找到子像素精度的圆心,我使用这种方法:

  1. 使用单个圆圈拍摄图像(在下面将其作为标记)。它的半径应该与你想要找到的圆的半径相同。
  2. 在测试图像和翻转标记图像中检测边缘(Sobel梯度的大小,然后是一些阈值以去除低强度边缘)。我不会在此阶段应用边缘细化,也不会识别边缘上的确切点。
  3. 将测试图像的边缘与翻转标记的边缘相互关联。你会得到一些中心所在的山峰。
  4. 以亚像素精度查找峰值中心。质量中心或拟合2D高斯钟可能效果很好。
  5. 添加与标记中圆心的已知位置相对应的移位。
  6. 否则,如果已知圆上的点具有足够的精度,则最小均方拟合应解决找到中心的问题(参见@ nikie的答案)。

答案 3 :(得分:3)

看看Hough transform。它可以用于detect circles

答案 4 :(得分:0)

OpenCV 2.4.6.0具有findCirclesGrid功能,可以在网格中找到圆心。