【问题标题】:Edge detection on pool table台球桌上的边缘检测
【发布时间】:2015-12-08 13:55:01
【问题描述】:

我目前正在研究一种算法来检测台球桌的游戏区域。为此,我捕获了一张图像,将其转换为灰度,并在其上使用了 Sobel 算子。现在我想将游戏区域检测为一个有 4 个角的盒子,位于桌子的 4 个角上。

检测桌子的边缘非常简单,但事实证明检测 4 个角并不容易,因为台球桌中有口袋。现在我只想为每个侧边设置一条线,然后根据这些线,我可以计算相交,也就是我的桌子的角。

我被困在这里,因为我还没有找到一个好的解决方案来在我的图像中找到这些线条。当我使用 Sobel 算子时,我可以很容易地看到它。但是什么是检测它并计算角位置的好方法呢?

编辑:我添加了一些示例图片

基本图片:

灰度图像

Sobel 过滤器(仅限水平)

【问题讨论】:

  • 尝试霍夫变换
  • 分享一两张有代表性的图片怎么样?
  • @MarkSetchell 我添加了一些图片
  • 不要使用边缘检测。二值化会产生更好的结果。
  • ZerO:看起来你正朝着我曾经开始开发的应用程序的方向前进。 (我从事图像处理工作并打台球。)请让我了解这一点;一旦您接近解决方案,还可以考虑在 AzBilliards 中发布。 (我在那里使用相同的用户名。)

标签: image-processing computer-vision edge-detection


【解决方案1】:

对于一般的解决方案,会有很多噪音来源:栏杆周围的布料问题、栏杆上的木材纹理(或没有纹理)、不同的照明、阴影、布料上的污渍、栏杆上的粉笔以及以此类推。

当颜色和照明不可靠时,并且当您想要找到几何对象的边缘时,最好考虑边缘像素而不是灰色/彩色像素。

不久前,我正在考虑制作一个基于手机的应用程序来保存球的位置以供以后查看,包括在线查看,所以我对这个问题有所了解。虽然我可以为您当前的问题提供一些指导,但我认为您在每一步都会遇到新问题,因此我会尝试提供更完整的答案。

  1. 将图像转换为灰度。如果我们不能让算法在灰度下工作,我们将不可避免地遇到颜色问题。 (见下文)
  2. [TBD] 进行一些预处理以减少噪音。
  3. 使用 Sobel 或(如果必须)Canny 查找边缘点。
  4. 运行霍夫线检测,但有一些注意事项和参数化,如下所述。
  5. 找到描述梯形四边形的线条。 (这可能是两个内部的四边形:一个在床上的栏杆内,另一个稍大的四边形在顶部的布/木栏杆边缘。)
  6. (可选)使用侧袋帮助确定四边形的方向。
  7. 使用仿射变换将透视变形的桌床映射到 [谢天谢地] 已知相对尺寸的矩形。我们提前知道床的尺寸,因此您可以将扭曲的矩形重新映射到合适的矩形。 (我们暂时忽略一些光学效果。)
  8. 将彩色图像重新映射到透视校正矩形。您可能需要调整一些球的位置。

一般说明:

  • 一般意义上的按颜色过滤可能很困难。很容易将布料想象成简单的绿色、蓝色或红色(或其他颜色),但是当您查看实际的 RGB 值并尝试分离颜色时,您会开始体会到颜色的噩梦可以是。
  • 光学失真可能会使某些边缘脱落。
  • 可能很难检测到远短的轨道,但您可以这样做:找到两条长轨道的内侧线,然后在两条轨道之间垂直搜索图像远端的第一个强水平边缘.那将是很短的铁路。
  • 虽然您可能希望使用手机摄像头来方便,但使用 Kinect 摄像头或类似(最好更小)的设备会更容易解决问题。您不仅会同时拥有颜色数据和 3D 数据,而且还可以消除光照方面的一些问题,因为深度数据不依赖于可见光。
  • 对于您的应用程序,请考虑将轨道边缘的搜索区域限制为透视变形的矩形。用户可能能够调整搜索区域。这可以大大简化处理过程,并且可以帮助您解决桌子光线不佳的问题(可能是这种情况)。

【讨论】:

    【解决方案2】:

    如果颜色分割(如@Dima 建议的那样)有效,请使用轮廓跟踪获取 blob 的轮廓。然后通过 Douglas-Peucker 算法将轮廓简化为四边形(或几边的多边形)。你应该这样找到四个桌子边。

    为了更准确,您可以通过局部搜索跨边缘位置的过渡来优化边缘位置并执行线拟合。然后相交线得到角。

    【讨论】:

      【解决方案3】:

      以下答案假设您已经找到图像中线条的位置。然而,这可以通过直接查看像素并查看它们是否在“线”中来“轻松”完成。通常,如果图像也已先进行了校正,即旋转,因此矩形(台球桌)更像这样:[] 而不是/=/,通常更容易检测到这一点。那么这只是扫描像素的情况,如果旁边有类似颜色的像素,假设它们之间有一条线。

      代码通过循环遍历图像中的行来工作。只要每条线的端点落在xy 坐标内的公差范围内,它就会被标记为角。一旦找到拐角,我就取它们之间的平均值来找出拐角所在的位置。例如:

      如果tolerance 为2 或更多,则以10, 10 结束的水平线和以12, 12 开始的垂直线将被发现是角。找到的角落将在: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

      【讨论】:

        【解决方案4】:

        台球桌的游戏区域通常具有独特的颜色,例如绿色或蓝色。我会先尝试基于颜色的分割方法。 MATLAB 中的 Color Thresholder 应用程序为您提供了一种尝试不同色彩空间和阈值的简单方法。

        【讨论】:

        • 对于这个问题,这可能是更简单的方法,但是对于这个问题,请参阅我在C# 中使用 some 示例代码的回答。
        猜你喜欢
        • 2017-04-04
        • 1970-01-01
        • 2019-09-10
        • 1970-01-01
        • 2014-03-30
        • 1970-01-01
        • 2021-03-01
        • 1970-01-01
        • 2016-09-12
        相关资源
        最近更新 更多