【问题标题】:Algorithm for finding intersections of straight lines寻找直线交点的算法
【发布时间】:2011-11-29 14:16:39
【问题描述】:

我在某处看到并试图解决这个问题。

有一个 8 位像素的 64x64 网格,上面有一堆 1 像素宽的不同颜色的垂直和水平线。所有平行线之间至少有一个间距。问题是找出每组彩色线的交叉线数(例如,所有绿色线交叉都计入一个总和)。并找出哪一组线的交叉次数最少。此外,一种颜色的所有垂直线大小相同,相同颜色的所有水平线大小相同。

我有一些想法,但它们似乎都很低效。这将涉及遍历网格中的每个像素,如果遇到颜色确定它是垂直线还是水平线,然后一直沿线的方向移动,同时检查相邻边是否有不同的颜色。

我正在尝试确定是否首先计算每种颜色的水平线和垂直线的长度会加快处理速度。对于如何做到这一点,你们有什么绝妙的想法吗?

这里有两个例子。请注意,平行线之间总是有一个空格。

【问题讨论】:

  • 不确定我是否理解,但在我看来,对于每种颜色,您需要水平线数乘以垂直线数。然后对其进行排序以查看哪种颜色的值最大?那么问题是如何通过检查图像像素来计算每种颜色的线数/类型?
  • 我想要的是一条线被它自己以外的任何颜色交叉的次数。您对每条线执行此操作,然后对每种颜色的所有交叉点求和。此外,由于线可能在下方或不在下方,因此不明确,如果线在 T(或侧向 T)交叉口处相交,则不计算该交叉口。例如,第一张图片中绿色的交叉点总数为 7。
  • 啊,好的。值得把它放在问题中,谢谢。

标签: algorithm line


【解决方案1】:

在带有线条的网格上寻找 2 种 3x3 正方形:

1).a.  2).a.
  bab    bbb
  .a.    .a.

“。”代表背景(总是黑色?),“a”和“b”代表2种不同的颜色(也不同于背景颜色)。如果找到,将 a 色线交叉点和 b 色线交叉点的计数增加 1。

【讨论】:

  • 这听起来像是赢家。但是,T 路口呢?他们不会被忽视吗?此外,在边缘你不能比较整个正方形,因为你会索引出来。我会开始处理这个。
  • @BobBusby:如果您检查所有 9 个单元格是否完全形成上述两种模式之一,您将忽略 t 交叉点。这不是你想要的吗,你提到有歧义?如果你愿意,你也可以计算 t 交点,你需要使用这个算法再寻找 8 个模式。
  • Bob Busby 在评论中写道,“因为它是模棱两可的,因为线可能在下方或不在,如果线在 T(或侧向 T)交叉口相遇,则不计算交叉口。”如果我们认为这意味着 T 个交叉点不计为交叉点,那么 @Alex 方法就完成了。然而,并不是所有的 T 都是模棱两可的。例如,在第二个示例中,两条水平亮黄色线 T 的右侧末端带有一条红线。可以毫不含糊地推断,红线下方有黄色方块,因为顶部的黄线以包含红线的列结束。
  • 我从未说过相同颜色的平行线必须具有相同的长度,但事实就是如此。这确实增加了复杂性。所以我想这意味着在遍历线时应该比较每条线的长度。
  • 我同意您没有说“相同颜色的平行线必须具有相同的长度”,但是在问题陈述的第二段中您写道“颜色的所有垂直线都是大小相同且所有相同颜色的水平线大小相同”,这意味着相同颜色的平行线必须具有相同的长度。
【解决方案2】:

扫描像素网格实际上非常快速且高效。这是计算机视觉系统做这种事情的标准。很多这样的扫描会生成经过 FIR 过滤的图像版本,强调正在搜索的各种细节。

主要的技术术语是“卷积”(参见http://en.wikipedia.org/wiki/Convolution)。我认为它是一种加权移动平均线,尽管权重可以是负数。 Wikipedia 上的动画显示卷积使用相当无聊的脉冲(它可能是一个更有趣的形状),以及 1D 信号(如声音)而不是 2D(图像)信号,但这是一个非常笼统的概念。

人们很容易认为可以通过避免提前计算过滤后的版本来做一些更有效的事情,但这样做的通常效果是,由于您没有预先计算所有这些像素,因此您最终会多次计算每个像素。换句话说,将过滤后的图像视为基于查找表的优化,或一种dynamic programming。

速度如此之快的一些特殊原因是......

  1. 它对缓存非常友好,因此可以有效地访问内存。
  2. 这正是矢量指令(MMX、SIMD 等)旨在支持的类型。
  3. 如今,您甚至可以将工作卸载到显卡上。

另一个优点是您只需要编写一个图像过滤卷积函数。特定于应用程序的部分是您如何定义过滤器内核,它只是一个权重值网格。事实上,你可能根本不应该自己编写这个函数——各种数字代码库都可以提供高度优化的版本。

为了处理不同颜色的线条,我只需先为每种颜色生成一个灰度图像,然后分别过滤和检查每种颜色。同样,将此视为优化 - 尝试避免生成单独的图像可能会导致更多的工作,而不是更少。

  • 再想一想,我可能已经理解了这个要求。从黑白图像中生成黑白图像,过滤它,然后从中找到 all 交叉点可能更有意义。一旦你有了交点,然后参考原始的黑白图像对它们进行分类以进行计数。每个像素的过滤和交叉点查找仍然非常有效。对每个像素的分类效率不高,但只在几个点上完成。

您可以根据以下 FIR 滤波器内核进行卷积...

.*.
***
.*.

点是零(与像素无关)或者可能是负值(更喜欢黑色)。星号是正值(首选白色)。也就是说,在十字路口寻找三乘三的十字架。

然后您扫描过滤后的结果,寻找比某个阈值更亮的灰度像素 - 与您的图案最匹配。如果您真的只想要精确的交叉点,您可能只接受完美匹配的颜色,但您可能需要考虑 T 型连接等。

【讨论】:

  • 感谢您的帮助!我还不够先进,无法做那些花哨的事情,但是像你这样的人让我想要变得更好。我见过的唯一卷积是一维的,所以我不确定如何将它应用于矩阵。
【解决方案3】:

您唯一的输入是 64x64 网格吗?如果是这样,那么您正在查看具有 64x64 风格的内容,因为没有其他方法可以确保您已发现所有行。因此,我假设您是在讨论操作级别的优化,而不是渐进式的。我似乎记得旧的“图形宝石”系列有很多这样的例子,重点是减少指令数。我自己更擅长渐近问题,但这里有一些小想法:

如果

(grid[i,j] == green)
&&
(grid[i+1,j]==green || grid[i-1,j]==green)
&&
(grid[i,j+1]==green || grid[i, j-1]==green)

因此,您可以只扫描一次数组,而不必担心显式检测水平和垂直线......只需使用这种关系遍历它并在找到交叉点时计算它们。所以至少你只是使用了一个逻辑相当简单的 64x64 循环。

由于没有两条平行线直接相邻,因此您知道,当您通过一个填充单元格时,您可以将内部循环计数器增加 2。这将为您节省一些工作。

根据您的架构,您可能有一种快速的方法来 AND 整个网格及其自身的偏移副本,这将是计算上述交集公式的一种很酷的方法。但是你仍然需要遍历整个事情来找到剩余的填充单元格(它们是交叉点)。

即使您没有图形处理器之类的东西可以让您和整个网格,如果颜色的数量小于您字长的一半,您也可以使用这个想法。例如,如果您有 8 种颜色和 64 位机器,那么您可以将 8 个像素塞进一个无符号整数。所以现在您可以一次对 8 个网格单元进行外循环比较操作。这可能会为您节省大量工作,因此值得进行两次遍历,一次用于水平外循环,一次用于垂直外循环。

【讨论】:

  • 我想我的解释很糟糕。我正在寻找一种颜色的线条与除自身之外的所有其他颜色的交点。他们也不必从各个方向相交。它可以只是一条线越过另一条线。不过感谢您的建议!
  • 这不会检查所有方向的交叉点——再次查看 OR。适配非绿线相交,可以调整为:left or right不为空,top or down不为空,left or right or top or down不为绿色。跨度>
【解决方案4】:

寻找直线路口的简单方法

def straight_intersection(straight1, straight2):
    p1x = straight1[0][0]
    p1y = straight1[0][1]
    p2x = straight1[1][0]
    p2y = straight1[1][1]
    p3x = straight2[0][0]
    p3y = straight2[0][1]
    p4x = straight2[1][0]
    p4y = straight2[1][1]
    x = p1y * p2x * p3x - p1y * p2x * p4x - p1x * p2y * p4x + p1x * p2y * p3x - p2x * p3x * p4y + p2x * p3y * p4x + p1x * p3x * p4y - p1x * p3y * p4x
    x = x / (p2x * p3y - p2x * p4y - p1x * p3y + p1x * p4y + p4x * p2y - p4x * p1y - p3x * p2y + p3x * p1y)
    y = ((p2y - p1y) * x + p1y * p2x - p1x * p2y) / (p2x - p1x)
    return (x, y)

【讨论】:

    猜你喜欢
    • 2015-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-04-09
    • 1970-01-01
    • 2012-05-26
    • 2011-05-04
    • 1970-01-01
    相关资源
    最近更新 更多