Algorithm 求直线交点的算法

Algorithm 求直线交点的算法,algorithm,line,Algorithm,Line,我在某处看到了一个关于穿越线路的问题,并试图解决这个问题 有一个8位像素的64x64网格,上面有一组1像素宽的不同颜色的垂直和水平线。所有平行线之间至少有一个空间。问题在于找出每组彩色线的交叉线数量(例如,所有绿色交叉线都朝一个和计数)。并找出哪一组线路的交叉次数最少。此外,一种颜色的所有垂直线的大小都相同,而相同颜色的所有水平线的大小都相同 我有一些想法,但它们似乎都很低效。它需要遍历网格中的每个像素,如果遇到一种颜色,请确定它是垂直线还是水平线,然后一直沿着线的方向走,同时检查相邻的边是否有

我在某处看到了一个关于穿越线路的问题,并试图解决这个问题

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

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

我试图确定,首先计算每种颜色的水平线和垂直线的长度是否会加快这一过程。你们有什么好主意吗

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


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

主要的技术术语是“卷积”(参见)。我认为它是一种加权移动平均数,虽然权重可以是负数。维基百科上的动画显示卷积使用了一个相当无聊的脉冲(它可能是一个更有趣的形状),以及一个一维信号(如声音)而不是二维(图像)信号,但这是一个非常普遍的概念

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

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

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

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

    • 再想一想,我可能已经理解了这个要求。从黑色和颜色中生成黑白图像,对其进行过滤,然后从中查找所有交点,这可能更有意义。一旦你有了交叉点,然后参考原始的黑色和彩色图像,对它们进行分类,以便计数。每像素的过滤和求交仍然非常有效。每像素的分类效率不是很高,但只能在几个点进行分类
    你可以做一个基于以下FIR滤波器内核的卷积运算

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


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

    您是否只需要输入64x64网格?如果是这样的话,那么您正在寻找具有64x64风格的产品,因为没有其他方法可以确保您找到了所有的产品线。所以我假设你说的是操作层面的优化,而不是渐进的。我似乎记得旧的“Graphics Gems”系列有很多这样的例子,重点是减少指令数量。我自己更擅长渐进式问题,但这里有一些小想法:

    格线单元的属性是格线[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个网格单元执行外循环比较操作。这可能是一个
    1).a.  2).a.
      bab    bbb
      .a.    .a.
    
    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)