求直线交点的算法

时间:2011-10-02 22:52:40

标签: algorithm line

有关于我在某处看到的线路交叉口的问题并且正在尝试解决这个问题。

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

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

我正在尝试决定首先计算每种颜色的水平和垂直线的长度是否会加快这个过程。你们对如何做到这一点有什么好主意吗?

以下是两个例子。请注意,平行线之间总是有空格。

enter image description here enter image description here

4 个答案:

答案 0 :(得分:1)

扫描像素网格实际上非常快速有效。这是计算机视觉系统做这种事情的标准。很多这些扫描产生FIR滤波版本的图像,强调要搜索的细节类型。

主要技术术语是“卷积”(见http://en.wikipedia.org/wiki/Convolution)。我认为它是一种加权移动平均线,但权重可能是负的。维基百科上的动画使用一个相当无聊的脉冲(它可能是一个更有趣的形状)和一维信号(如声音)而不是2D(图像)信号来显示卷积,但这是一个非常普遍的概念。 / p>

通过避免事先计算过滤后的版本,可以认为可以更有效地完成更高效的操作,但通常的效果是因为您没有预先计算所有这些像素,所以最终会多次计算每个像素。换句话说,将过滤后的图像视为基于查找表的优化,或者dynamic programming

为什么这么快的一些特殊原因是......

  1. 它非常适合缓存,因此可以有效地访问内存。
  2. 这正是向量指令(MMX,SIMD等)旨在支持的东西。
  3. 现在,您甚至可以将工作卸载到显卡上。
  4. 另一个优点是您只需要编写一个图像过滤卷积功能。特定于应用程序的部分是如何定义过滤器内核,它只是一个权重值网格。事实上,您可能根本不应该自己编写此函数 - 各种数字代码库可以提供高度优化的版本。

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

    • 第二个想法,我可能已经理解了这个要求。从黑色和颜色生成黑白图像,过滤器以及从中找到所有交叉点可能更有意义。获得交叉点后,请返回原始的黑色和彩色图像,对其进行分类以进行计数。滤波和交叉寻找对于每个像素仍然非常有效。每个像素的分类效率不高,但只能在几个点完成。

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

    .*.
    ***
    .*.
    

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

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

答案 1 :(得分:1)

在网格上,您的线条会查找2种类型的3x3正方形:

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

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

答案 2 :(得分:0)

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

如果

,网格单元格具有grid [i,j]为绿色交点的属性
(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。那会为你节省一些工作。

根据您的体系结构,您可能有一种快速方法将整个网格与其自身的偏移副本进行对比,这将是计算上述交集公式的一种很酷的方法。但是你仍然必须遍历整个事物以找到剩余的填充单元格(这是交叉点)。

即使你没有像图形处理器这样的东西可以让你和整个网格,你可以使用这个想法,如果颜色的数量少于你的单词大小的一半。例如,如果您有8种颜色和64位机器,则可以将8个像素填充到单个无符号整数中。所以现在你可以一次对8个网格单元进行外循环比较操作。这可能会为你节省很多工作,值得做两次传递,一次用于水平外环,一次用于垂直外环。

答案 3 :(得分:0)

找到直线交点的简单方法

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)