【问题标题】:Subregions of boolean 2d array布尔二维数组的子区域
【发布时间】:2020-04-28 00:28:44
【问题描述】:

假设我有一个二维布尔数组。我想获得一个切片/或类似的列表,其中每个切片代表包含 True 值的数组的最小(大小)子区域,而其边界包含所有 False。

我可以为每一行和每一列循环并在满足这种条件时存储索引,但我想知道你是否知道另一种方法或一个库可以有效地做到这一点?您可以假设原始布尔数组的边界始终为 False/0。

示例 1

示例 2

编辑!添加了具有正确解决方案的新示例。很抱歉造成混乱。

【问题讨论】:

  • 不确定你的例子是否符合逻辑。考虑到它们共享一列,为什么不应该将下面方框的第一个包含在较大的方框中?
  • 我犯了一些错误,我添加了相同的数组。它们代表 2 个不同的示例,红色标记的区域是我想要获取切片的子区域。
  • 在第一个例子中,不应该有3个区域吗?编辑:我想这取决于您是否想要最大尺寸或最小尺寸的区域
  • 子区域的定义相当混乱,因为我认为您可以通过多种方式来定义子区域,或者您可以使用代码产生所有可能的结果
  • 不,定义是有效的并且具有独特的解决方案。我只是不知道我今天的想法在哪里,甚至无法为我的示例提供正确的解决方案.. 一秒钟内更新

标签: python python-3.x numpy numpy-ndarray


【解决方案1】:

那是连通分量分析,一直是asked and answered before。根据您的需要调整接受的答案,一个可能的解决方案很短:

import numpy as np
from scipy.ndimage.measurements import label


def analysis(array):
    labeled, _ = label(array, np.ones((3, 3), dtype=np.int))
    for i in np.arange(1, np.max(labeled)+1):
        pixels = np.array(np.where(labeled == i))
        x1 = np.min(pixels[1, :])
        x2 = np.max(pixels[1, :])
        y1 = np.min(pixels[0, :])
        y2 = np.max(pixels[0, :])
        print(str(i) + ' | slice: array[' + str(y1) + ':' + str(y2) + ', ' + str(x1) + ':' + str(x2) + ']')


example1 = np.array([
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 1, 0, 1, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 1, 1, 0],
    [0, 0, 0, 0, 0, 0, 1, 1, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]).astype(bool)

example2 = np.array([
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
    [0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
    [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
    [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
    [0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
    [0, 0, 0, 0, 1, 1, 0, 0, 1, 0],
    [0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
    [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
    [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
]).astype(bool)

for a in [example1, example2]:
    print(a, '\n')
    analysis(a)
    print('\n')

这是输出(没有示例):

[[...]] 

1 | slice: array[1:2, 3:5]
2 | slice: array[4:6, 6:8]
3 | slice: array[8:8, 2:2]

[[...]] 

1 | slice: array[1:3, 5:8]
2 | slice: array[2:2, 3:3]
3 | slice: array[4:5, 1:1]
4 | slice: array[5:8, 3:6]
5 | slice: array[6:6, 8:8]
6 | slice: array[8:8, 8:8]

希望有帮助!

------------------
System information
------------------
Python:  3.8.1
SciPy:   1.4.1
------------------

【讨论】:

    【解决方案2】:

    您可以从图形的角度来解决问题,其中的坐标是图形元素,8 路连接 - 然后您只需要在图形中找到连接的组件。如果数据稀疏,这应该比遍历可能的正方形大小要快得多。这是它如何工作的示例:

    from itertools import combinations
    
    def find_squares(a):
        # Find ones
        ones = [(i, j) for i, row in enumerate(a) for j, val in enumerate(row) if val]
        # Make graph of connected ones
        graph = {a: [] for a in ones}
        for a, b in combinations(ones, 2):
            if abs(a[0] - b[0]) <= 1 and abs(a[1] - b[1]) <= 1:
                graph[a].append(b)
                graph[b].append(a)
        # Find connected components in graph
        components = []
        for a, a_neigh in graph.items():
            if any(a in c for c in components):
                continue
            component = {a, *a_neigh}
            pending = [*a_neigh]
            visited = {a}
            while pending:
                b = pending.pop()
                if b in visited:
                    continue
                visited.add(b)
                component.add(b)
                b_neigh = graph[b]
                component.update(b_neigh)
                pending.extend(c for c in b_neigh if c not in visited)
            components.append(component)
        # Find bounds for each component
        bounds = [((min(a[0] for a in c), min(a[1] for a in c)),
                   (max(a[0] for a in c), max(a[1] for a in c)))
                  for c in components]
        return bounds
    
    a = [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 0, 1, 0, 1, 0, 0],
         [0, 0, 0, 1, 0, 0, 1, 0, 1, 0],
         [0, 0, 0, 0, 0, 0, 0, 1, 0, 0],
         [0, 1, 0, 0, 0, 0, 0, 0, 0, 0],
         [0, 1, 0, 0, 1, 0, 0, 0, 0, 0],
         [0, 0, 0, 0, 1, 1, 0, 0, 1, 0],
         [0, 0, 0, 0, 1, 0, 1, 0, 0, 0],
         [0, 0, 0, 1, 0, 0, 0, 0, 1, 0],
         [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]]
    square_bounds = find_squares(a)
    print(*square_bounds, sep='\n')
    # ((1, 5), (3, 8))
    # ((2, 3), (2, 3))
    # ((4, 1), (5, 1))
    # ((5, 3), (8, 6))
    # ((6, 8), (6, 8))
    # ((8, 8), (8, 8))
    

    【讨论】:

      猜你喜欢
      • 2021-11-10
      • 2022-01-23
      • 2015-04-17
      • 2021-02-04
      • 2018-02-10
      • 2016-12-25
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      相关资源
      最近更新 更多