Algorithm 如何在同一像素组中找到距离另一像素最远的像素

Algorithm 如何在同一像素组中找到距离另一像素最远的像素,algorithm,pixel,distance,point,Algorithm,Pixel,Distance,Point,所谓“组”,我指的是一组像素,使得每个像素在同一组中至少有一个相邻像素,图中显示了一个组的示例 我想找到与指定像素(例如,绿色像素)之间直线距离最大的像素。连接两个像素的直线(红线)不得离开组 我的解决方案是在度数之间循环,模拟从绿色像素开始的线的进程,并查看哪条线走得最远 longestDist = 0 bestDegree = -1 farthestX = -1 farthestY = -1 FOR EACH degree from 0 to 360 dx=longestDist

所谓“组”,我指的是一组像素,使得每个像素在同一组中至少有一个相邻像素,图中显示了一个组的示例

我想找到与指定像素(例如,绿色像素)之间直线距离最大的像素。连接两个像素的直线(红线)不得离开组

我的解决方案是在度数之间循环,模拟从绿色像素开始的线的进程,并查看哪条线走得最远

longestDist = 0
bestDegree = -1
farthestX = -1
farthestY = -1
FOR EACH degree from 0 to 360
    dx=longestDist * cos(degree);
    dy=longestDist * sin(degree);
    IF Point(x+dx , y+dy) does not belong to the group
        Continue with next degree
        //Because it must not be the longest line, so skip it
    END IF
    (farthestX , farthestY) = simulate(x,y,degree)
    d = findDistance(x , y , farthestX , farthestY)
    IF d > longestDist
        longestDist = d
        bestDegree = degree
    END IF
END FOR
这显然不是最好的算法。因此,我在这里请求帮助


谢谢,对不起,我的英语很差。

首先,请注意,算法中的角度离散化可能取决于网格的大小。如果步长太大,您可能会错过某些单元格,如果步长太小,您将一次又一次地访问同一单元格

我建议您枚举该区域中的单元格,然后逐个测试每个单元格的条件。枚举可以使用广度优先或深度优先搜索完成(我认为后者更可取,因为它将允许快速建立下限并进行一些修剪)

可以保留到目前为止发现的最远点X,对于区域中的每个新点,检查(a)该点是否比到目前为止发现的点更远,以及(b)它是否仅通过穿过区域单元的直线连接到原点。如果两个条件都满足,则更新X,否则继续搜索。如果不满足条件(a),则不必检查条件(b)


此解决方案的复杂性为
O(N*M)
,其中
N
是区域中的单元数,
M
是区域的较大尺寸(
max(宽度、高度)
)。如果性能至关重要,则可以应用更复杂的启发式算法,但对于大小合理的网格,这应该可以很好地工作

搜索像素,而不是坡度。伪代码

bestLength = 0
for each pixel in pixels
  currentLength = findDistance(x, y, pixel.x, pixel.y)
  if currentLength > bestLength
    if goodLine(x, y, pixel.x, pixel.y)
      bestLength = currentLength
      bestX = pixel.x
      bestY = pixel.y
    end
  end
end

在此之前,您可能希望按| dx |+| dy |对像素进行降序排序。

我不会使用角度。但我很确定最大距离总是在集合边缘的两个像素之间,因此我会跟踪轮廓:从集合中的任何像素到任何方向,直到到达集合边缘。然后沿边缘顺时针移动(couter)。以任何像素为起点进行此操作,您将能够找到最大距离。它仍然很贪婪,但我认为它可能会给你一个改进的替代起点

编辑:我刚刚想到的是:当你有一个开始像素
s
和结束像素
e
时。在使用
s
的第一次迭代中,相应的
e
将相邻(下一次沿顺时针方向的边缘)。当您沿着边缘迭代时,可能会出现这样的情况,即
s
e
之间的集合中没有直线。在这种情况下,线条将触及设定边缘的另一部分(像素
p
)。您可以在该像素处继续迭代边缘(
e=p

编辑2:如果你点击一个
p
,你就会知道
s
e
之间不再有距离,因此在
s
的下一次迭代中,你可以跳过整个边缘部分(在
s
p
之间),再次从
p
开始

Edit3:使用上述方法查找第一个
p
。将该
p
作为下一个
s
并继续。重复此步骤,直到再次到达第一个
p
。最大距离将在两个
p
之间,除非集合的边是凸的,在这种情况下,您将找不到
p


免责声明:这是未经测试的,只是我头脑中的想法,没有任何图纸来证实我的主张,一切都可能是错误的(即,在实施之前自己考虑一下;D)

使用双重数据结构:

  • 包含按角度排序的像素的一种
  • 第二个按距离排序(为了快速访问,还应该包含第一个数据结构的“指针”)

遍历角度排序的区域,检查每个像素的线条是否在区域内。某些像素将具有相同的角度,因此您可以沿着直线从原点开始行走,直到从区域中退出。可以消除超出该点的所有像素。此外,如果最大距离增加,请删除距离较短的所有像素。

将区域视为多边形,而不是像素集合。从中可以获得线段列表(多边形的边)

longestDist = 0
bestDegree = -1
farthestX = -1
farthestY = -1
FOR EACH degree from 0 to 360
    dx=longestDist * cos(degree);
    dy=longestDist * sin(degree);
    IF Point(x+dx , y+dy) does not belong to the group
        Continue with next degree
        //Because it must not be the longest line, so skip it
    END IF
    (farthestX , farthestY) = simulate(x,y,degree)
    d = findDistance(x , y , farthestX , farthestY)
    IF d > longestDist
        longestDist = d
        bestDegree = degree
    END IF
END FOR
从开始像素到要检查的每个像素绘制一条线。不与多边形的任何线段相交的最长直线表示可以通过像素的直线到达的最远像素

有各种各样的优化,你可以做这个和一些边缘的情况下检查,但让我知道,如果你理解的想法之前,我张贴这些。。。特别是,你明白我说的多边形而不是像素集合是什么意思吗

此外,这种方法将比任何基于角度的方法或需要对所有像素集合(最小像素集合除外)进行“行走”的方法快得多。您可以进一步优化,因为您的问题相当于找到多边形边的最远端点,该端点可以从起点通过未分割的直线到达。这可以在O(N^2)中完成,其中N是边的数目。请注意,N将远小于像素数,而使用角度和/或像素迭代的许多算法将被替换