我目前正在研究一种算法来检测台球桌的比赛区域。为此,我拍摄了一张图像,将其转换为灰度图像,并在其上使用了Sobel算子。现在我想将游戏区域检测为一个盒子,其中有四个角位于桌子的四个角落。
检测桌子的边缘非常简单,但事实证明,检测4个角落不是那么容易,因为台球桌上有口袋。现在我只想在每条边线上插入一条线,从这些线条中,我可以计算出相交,这是我桌子的角落。
我被困在这里,因为我还没有想出一个很好的解决方案来在我的图像中找到这些线条。当我使用Sobel算子时,我很容易看到它。但是检测它并计算角落位置的好方法是什么?
编辑:我添加了一些示例图像
答案 0 :(得分:2)
如果颜色分割(由@Dima建议)有效,请使用轮廓跟踪获取blob的轮廓。然后通过Douglas-Peucker算法将轮廓简化为四边形(或几边的多边形)。你应该通过这种方式找到四个表边缘。
为了获得更高的精确度,您可以通过局部搜索其中的过渡来优化边缘位置并执行线拟合。然后与线相交以获得角落。
答案 1 :(得分:2)
对于一般解决方案,会有许多噪音来源:导轨周围的布料,导轨上的木质纹理(或无纹理),不同的光线,阴影,布料上的污渍,导轨上的粉笔以及等等。
当颜色和光线不可靠时,当您想要找到几何对象的边缘时,最好根据边缘像素而不是灰色/彩色像素进行思考。
前段时间我正在考虑制作一个基于手机的应用程序来保存球位以供以后查看,包括在线,所以我对这个问题有点了解。虽然我可以为您当前的问题提供一些指导,但我发现每一步都会遇到新的问题,所以我会尝试提供更完整的答案。
一般说明:
答案 2 :(得分:1)
以下答案假设您已经找到了图像中线条的位置。然而,这可以很容易地完成"通过直接查看像素并查看它们是否在"行"。通常,如果首先对图像进行了校正,则更容易检测到这一点,即旋转,因此矩形(池表)更像是:[]
而不是像/=/
。然后它只是一个扫描像素的情况,如果它们旁边有相似的颜色,假设它们之间有一条线。
代码通过循环遍历图像中找到的线来工作。每当每条线的终点落在x
和y
坐标内的公差范围内时,它就会被标记为一个角。一旦发现了角落,我会取它们之间的平均值来找到角落所在的位置。例如:
如果10, 10
为2或更多,则会发现以12, 12
结尾的水平线和从tolerance
开始的垂直线为角。找到的角落位于:11, 11
注意:这只是为了找到左上角,但可以轻松调整以找到所有这些。这样做的原因是因为在我使用它的应用程序中,首先将每个数组排序为首先找到相关值的顺序更快,参见:Why is processing a sorted array faster than an unsorted array?。
另请注意,我的代码会找到可能不适合您的每一行的第一个角落,这主要是出于性能原因。然而,代码可以很容易地适应所有线条找到所有角落然后选择"更可能"通过它们全部转角或平均值。
另请注意,我的回答是用C#
写的。
private IEnumerable<Point> FindTopLeftCorners(IEnumerable<Line> horizontalLines, IEnumerable<Line> verticalLines)
{
List<Point> TopLeftCorners = new List<Point>();
Line[] laHorizontalLines = horizontalLines.OrderBy(l => l.StartPoint.X).ThenBy(l => l.StartPoint.Y).ToArray();
Line[] laVerticalLines = verticalLines.OrderBy(l => l.StartPoint.X).ThenBy(l => l.StartPoint.Y).ToArray();
foreach (Line verticalLine in laVerticalLines)
{
foreach (Line horizontalLine in laHorizontalLines)
{
if (verticalLine.StartPoint.X <= (horizontalLine.StartPoint.X + _nCornerTolerance) && verticalLine.StartPoint.X >= (horizontalLine.StartPoint.X - _nCornerTolerance))
{
if (horizontalLine.StartPoint.Y <= (verticalLine.StartPoint.Y + _nCornerTolerance) && horizontalLine.StartPoint.Y >= (verticalLine.StartPoint.Y - _nCornerTolerance))
{
int nX = (verticalLine.StartPoint.X + horizontalLine.StartPoint.X) / 2;
int nY = (verticalLine.StartPoint.Y + horizontalLine.StartPoint.Y) / 2;
TopLeftCorners.Add(new Point(nX, nY));
break;
}
}
}
}
return TopLeftCorners;
}
其中Line
是以下class
:
public class Line
{
public Point StartPoint { get; private set; }
public Point EndPoint { get; private set; }
public Line(Point startPoint, Point endPoint)
{
this.StartPoint = startPoint;
this.EndPoint = endPoint;
}
}
_nCornerTolerance
是可配置金额的int
。
答案 3 :(得分:0)
台球桌的游戏区域通常具有独特的颜色,如绿色或蓝色。我会先尝试一种基于颜色的分割方法。 MATLAB中的Color Thresholder应用程序为您提供了一种尝试不同颜色空间和阈值的简便方法。