Image processing 池表的边缘检测

Image processing 池表的边缘检测,image-processing,computer-vision,edge-detection,Image Processing,Computer Vision,Edge Detection,我目前正在研究一种算法来检测台球桌的游戏区域。为此,我拍摄了一幅图像,将其转换为灰度,并对其使用了Sobel操作符。现在,我想将游戏区域检测为一个长方体,其中4个角位于桌子的4个角中 检测桌子的边缘非常简单,但是,检测4个角却不是那么容易,因为台球桌上有口袋。现在我只想在每个边上拟合一条线,从这些线,我可以计算出相交点,这是我桌子的角 我被困在这里,因为我还不能想出一个好的解决方案,在我的图像中找到这些线条。当我使用Sobel运算符时,我可以很容易地看到它。但是,有什么好方法可以检测它并计算角点

我目前正在研究一种算法来检测台球桌的游戏区域。为此,我拍摄了一幅图像,将其转换为灰度,并对其使用了Sobel操作符。现在,我想将游戏区域检测为一个长方体,其中4个角位于桌子的4个角中

检测桌子的边缘非常简单,但是,检测4个角却不是那么容易,因为台球桌上有口袋。现在我只想在每个边上拟合一条线,从这些线,我可以计算出相交点,这是我桌子的角

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

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

基本图像:

灰度图像

Sobel过滤器(仅水平)

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

以下答案假设您已经找到图像中线条的位置。然而,这可以通过直接观察像素并查看它们是否在一条“线”中“轻松”完成。通常,如果图像也已先进行了倾斜(即旋转),则更容易检测到此问题,因此矩形(池表)更像这样:
[]
,而不是像
/=/
。然后,它只是扫描像素的一种情况,如果旁边有颜色相似的像素,则假设它们之间有一条线

代码通过在图像中找到的行上循环来工作。当每条线的端点位于
x
y
坐标的公差范围内时,它被标记为一个角。一旦找到角点,我取它们之间的平均值来找到角点所在的位置。例如:

如果
公差为2或更多,则在
10,10
处结束的水平线和在
12,12
处开始的垂直线将被发现为一个角。找到的角将位于:
11,11

注意:这仅用于查找左上角,但可以轻松调整以查找所有左上角。之所以这样做,是因为在我使用它的应用程序中,首先将每个数组排序为先找到相关值的顺序更快,请参见:

还要注意,我的代码为每一行查找第一个角点,这可能不适用于您,这主要是出于性能原因。然而,代码可以很容易地进行调整,以找到所有线条的所有角点,然后选择“更有可能”的角点或对它们进行平均

另外请注意,我的答案是用
C.
写的

\u nCornerTolerance
是一个可配置量的
int

如果颜色分割(如@Dima所建议)起作用,请使用轮廓跟踪获得斑点的轮廓。然后使用道格拉斯-佩克算法将轮廓简化为四边形(或少数边的多边形)。你应该这样找到桌子的四条边


为了获得更高的精度,可以通过局部搜索边缘上的过渡来优化边缘位置,并执行直线拟合。然后将线相交以获得角。

对于一般解决方案,会有许多噪声源:钢轨周围的布料问题、钢轨上的木材纹理(或无纹理)、不同的照明、阴影、布料上的污渍、钢轨上的粉笔等

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

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

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

    • 从一般意义上讲,按颜色过滤可能很困难。人们很容易将布料简单地想象为绿色、蓝色或红色(或其他颜色),但当你看到实际的RGB值并尝试分离颜色时,你就会开始意识到使用颜色是多么可怕
    • 光学畸变可能会使某些边缘脱落
    • 较短的轨道可能很难检测,但您可以这样做:找到两条长轨道的内线,然后在两条轨道之间垂直搜索第一条轨道
      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;
      }
      
      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;
          }
      }