在带有墙壁的二维地图中找到角落

时间:2012-11-17 21:01:25

标签: python arrays algorithm image-processing

我正在为aisandbox.com竞赛开展AI工作。我正在制作AI以获得乐趣,而不是参加比赛(以防万一我会在这里询问是否违反规则。)

我可以使用self.level.blockHeights得到该区域的二维地图,我想找到一些我的机器人可以通过在地图中找到角落并让它们在那里进行防守来隐藏的地方。

所以我的问题是,给定一个2d数组,其中0是自由空间而1是墙,找到角落的最佳方法是什么?

P.S。我正在使用Python

编辑:这是一个地图的例子(墙是黑色的),找到的角是红色的: enter image description here

4 个答案:

答案 0 :(得分:1)

根据您的示例网格,0 可以定义角落,其中至少包含2个 1

你可以先把这个定义写成一个愚蠢的实现(就像我下面故意做的那样),然后通过考虑性能来改进它,例如。

2代表此实现中的一个角落

Python实施示例

g = [[1,1,1,0],
     [1,0,0,0],
     [1,0,0,0],
     [1,0,1,0],
     [1,1,1,1]]

width = len(g[0])
height = len(g)

for i in range(height):
    for j in range(width):
        if g[i][j] != 0:
            continue
        around = [(i-1,j),(i+1,j),(i,j-1),(i,j+1)]
        walls = 0
        for (x,y) in around:
            if x < 0 or x >= height or y < 0 or y >= width:
                #Outside, count as wall
                walls += 1
            elif g[x][y] == 1:
                walls += 1
        if walls in [2,3]: # 4 would be inaccessible  
            g[i][j] = 2

<强>输出:

[1, 1, 1, 2]
[1, 2, 0, 0]
[1, 0, 0, 0]
[1, 2, 1, 2]
[1, 1, 1, 1]

答案 1 :(得分:1)

到目前为止,答案非常缓慢(尽管它们的复杂性是线性的) - 特别是在python中,因为它们涉及广泛的循环。此外,它们对噪音不是很强大(虽然我知道这里不需要)

解决这个问题的一个很好的技巧(如果你愿意使用scipy和numpy)就是将一个带有小内核的gaussian filter应用于图像并从中减去原始图像(注意不要溢)。由于角落“渗透”到背景中,因此在生成的图像中,角落将是具有最高强度的像素。

这是一个实际的例子:

import numpy
import scipy.ndimage
import scipy.misc

image= scipy.ndimage.imread('corners.png').astype(float)
image= numpy.mean( image, axis=2) #squash color channels
filtered=   scipy.ndimage.filters.gaussian_filter(image,1)
subtracted= (256+image)-filtered #take care not to underflow
maximum, minimum=   numpy.max(subtracted), numpy.min(subtracted)
magic= 0.48 #will depend on source image. Fool around and see what works
threshold= (maximum+minimum)/2+(maximum-minimum)*magic 
thresholded= subtracted>=threshold

print list(zip(*numpy.where(thresholded)))

输出[(190, 206), (207, 314)]

corners.png:

corners.png

过滤

filtered

thresolded:

thresolded

答案 2 :(得分:0)

从你的例子中,可以将角定义为自由单元,其中两个相邻的单元被墙占据,两个被占用的单元处于北/东,北/西,南/东和南/西的配置中。

因此,寻找角落只需要扫描您的2D地图并查看每个空闲单元格的相邻单元格。

我假设你不想要有3个围墙的自由牢房(就像走廊尽头一样)。

假设您有一个函数isWall(x,y)

def isCorner(x, y) :
     eastHasWall = isWall(x+1, y)
     westHasWall = isWall(x-1, y)
     northHasWall = isWall(x, y-1)
     southHasWall = isWall(x, y+1)

     wallArray = [eastHasWall, westHasWall, northHasWall, southHasWall]
     wallCount = wallArray.count(true)

     if wallCount == 2 :
         return (eastHasWall and northHasWall) or (eastHasWall and southHasWall) or (westHasWall and northHasWall) or (westHasWall and southHasWall)

     return false # other wall count are not corners

我没有测试过代码,但应该编译。

还应该注意地图的边界。只有您可以说它们在您的设置中被视为墙壁或自由空间。

答案 3 :(得分:0)

伪代码

function isCorner(x, y) {
    wallsFound = 0;
    if (withinBounds(x + 1, y) && grid[x + 1][y] == 1)
        wallsFound++
    if (withinBounds(x - 1, y) && grid[x - 1][y] == 1)
        wallsFound++
    if (withinBounds(x, y + 1) && grid[x][y + 1] == 1)
        wallsFound++
    if (withinBounds(x, y - 1) && grid[x][y - 1] == 1)
        wallsFound++
    return wallsFound  == 2 || wallsFound == 3;
}

function withinBounds(x, y) {
    return x >= 0
        && x < rows.len
        && y >= 0
        && y < cols.len
}

for i = 0 to rows.len
    for j = 0 to cols.len
        if isCorner(x, y)
            // do something

如果您希望地图边缘计为墙,可以将&&更改为isCorner中的||