我需要一个非常精确的算法来将圆拟合到数据点集(实际上我需要确定中心)。数据在图像的二值化和分割之后出现。 我尝试了简单的质心和加权质心算法以及预制的OpenCv :: fitEllipse函数。我已经从OpenCV函数中获得了最好的结果,但仍然不够准确。当中心锚定在子像素区域时,结果显着受损。 即使在处理模型化数据时,我获得的准确性也是不够的,这是不好的,因为最终,程序将不得不处理由相机捕获的数据。 您有什么建议我应该寻找什么样的算法,或者您有任何现成的解决方案吗?我宁愿不要连接任何外部库。 谢谢你的帮助。
编辑: 校准目标可以在视野的任何区域中定位。以下是我使用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
编辑:数字生成的模型和中心的真实坐标:
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
答案 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]]
结果是
2.运行Hit Miss Transform以隔离圆圈
The Hit Miss Transform擅长查找定义良好的几何对象。它也很容易编程,几乎总是出现在图像库中。
c = Binarize@HitMissTransform[b, DiskMatrix[20]]
结果是:
我们的圈子已经被孤立并缩减为核心。
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} .....
我们差不多完成了。
让我们检查一下我们的结果。我们叠加了两个图像,在检测到的中心周围绘制了十字和圆圈。
Click to enlarge,这样您就可以了解所涉及的错误。
HTH!
修改
我将您的表格中的结果与我的结果进行了比较。
假设圆是直线的,我使用最小二乘拟合来追踪一条线并计算残差。
从下面的图表中可以看出,“M”y线比我们的“Y”更合适。但这是假设圆圈对齐......
编辑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}}
这是图像:
答案 1 :(得分:3)
“最佳”取决于输入数据中的噪声类型。如果源数据点中没有噪声,则问题很简单:只需选择3个点并计算圆圈。
如果您期望每个数据点的正态分布式独立转换,那么最小均方算法应该是最优的。数据点应符合以下等式:
(x - xm)^2 + (y - ym)^2 = r^2
其中xm
,ym
,r
未知,所以:
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)
如果圆的半径已知(且常数),要找到子像素精度的圆心,我使用这种方法:
否则,如果已知圆上的点具有足够的精度,则最小均方拟合应解决找到中心的问题(参见@ nikie的答案)。
答案 3 :(得分:3)
看看Hough transform。它可以用于detect circles。
答案 4 :(得分:0)
OpenCV 2.4.6.0具有findCirclesGrid
功能,可以在网格中找到圆心。