首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >台面边缘检测

台面边缘检测
EN

Stack Overflow用户
提问于 2015-12-08 13:55:01
回答 4查看 1.1K关注 0票数 4

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

检测表的边缘是相当简单的,然而,它的结果是,检测四个角落不是那么容易,因为在台球桌上有口袋。现在我只想在每条边沿上放一条线,从这些线上,我可以计算出相交,这是我的表的角。

我被困在这里,因为我还没有找到一个好的解决方案,以找到这些线在我的形象。当我使用Sobel操作符时,我可以很容易地看到它。但是,什么是检测它和计算拐角位置的好方法呢?

编辑:我添加了一些图片样本

基本图像:

灰度图像

Sobel滤波器(水平滤波器)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2015-12-13 06:08:08

对于一般的解决方案,会有很多噪音来源:栏杆周围的布的问题,铁轨上的木头纹理(或没有纹理),不同的灯光,阴影,布上的污渍,铁轨上的粉笔等等。

当颜色和光线不可靠时,当你想要找到几何物体的边缘时,最好用边缘像素而不是灰色/彩色像素来考虑。

一段时间前,我在考虑制作一个基于手机的应用程序来保存球的位置,供以后的复习,包括在线,所以我考虑了一下这个问题。虽然我可以为你当前的问题提供一些指导,但我意识到你会遇到新的问题,所以我会尝试提供一个更完整的答案。

  1. 将图像转换为灰度。如果我们不能使算法在灰度上工作,我们将不可避免地遇到颜色问题。(见下文)
  2. 为了降低噪声,TBD做了一些预处理。
  3. 使用Sobel或(如果必须的话) Canny查找边缘点。
  4. 运行Hough线检测,但附带一些警告和参数化,如下所述。
  5. 找到描述为基座状四边形的线条。(这很可能是两个四边形的内部:一个在床上的栏杆内,另一个稍大的四边形在布/木轨边缘的顶部。)
  6. (可选)使用侧面口袋来帮助确定四边形的方向。
  7. 使用仿射变换将透视扭曲的工作台映射到一个值得庆幸的相对尺寸的矩形上。我们预先知道床的大小,所以你可以把扭曲的矩形重新映射成一个合适的矩形。(目前我们将忽略一些光学效应。)
  8. 将彩色图像重新映射到经透视校正的矩形。你可能需要调整一些球的位置。

一般性说明:

  • 一般意义上的颜色过滤是很困难的。人们很容易认为布料仅仅是绿色、蓝色或红色(或其他颜色),但当你看到实际的RGB值并尝试分离颜色时,你就会开始体会到在颜色上的噩梦会是什么样子。
  • 光学畸变可能会使一些边缘脱落。
  • 远短轨可能很难检测,但您可以这样做:为两条长轨查找内线,然后在两条铁轨之间垂直搜索图像远端的第一条较强的水平边缘。那将是一条很短的铁路。
  • 虽然您可能想使用您的手机相机方便,使用Kinect相机或类似的(最好更小)设备将使问题更容易。不仅你有颜色数据和3D数据,而且你可以消除照明的一些问题,因为深度数据将不依赖于可见光。
  • 对于您的应用程序,考虑限制搜索区域的铁路边缘透视扭曲矩形。用户可能能够调整搜索区域。这可以极大地简化处理过程,如果表亮得不好的话,它可以帮助您解决问题(就像情况一样)。
票数 2
EN

Stack Overflow用户

发布于 2015-12-08 15:11:27

如果颜色分割(如@Dima所建议的那样)有效,则使用等高线下面的轮廓获取blob的轮廓。然后用Douglas-Peucker算法将轮廓简化为四边形(或几个边的多边形)。你应该这样找四张桌子的边。

为了获得更高的精度,您可以通过局部搜索跨越边缘的过渡并执行直线拟合来细化边缘位置。然后把线相交得到拐角。

票数 2
EN

Stack Overflow用户

发布于 2015-12-08 14:32:26

下面的答案假设您已经在图像中找到了行的位置。然而,通过直接查看像素并查看它们是否处于“直线”,可以“很容易”地做到这一点。通常,如果图像是先被分解的,那么更容易检测到这一点,即旋转,这样矩形(池表)更像这样:[]而不是/=/。然后,它只是扫描像素的情况,如果有相似的颜色在它旁边,假设它们之间有一条线。

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

10, 10结尾的水平线和从12, 12开始的垂直线将被发现为一个角,如果tolerance为2或更多。找到的拐角处在:11, 11

注意:--这只是为了找到左上角,但是很容易就能找到它们。之所以这样做,是因为在我使用它的应用程序中,首先将每个数组排序为先找到相关值的顺序更快,参见:为什么处理排序数组比未排序数组更快?

还请注意,我的代码为每一行找到了可能不适用于您的第一个角,这主要是出于性能原因。然而,代码可以很容易地找到所有的角,所有的行,然后选择“更可能的”角或平均通过他们的所有。

还请注意,我的答案是用C#写的。

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34157710

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档