Determine adjacent regions in numpy array

核能气质少年 提交于 2019-12-05 10:47:28

I understand that the task is to return all distinct entries of the array that are adjacent to a given number (such as 2). One way to achieve this with NumPy methods is to use roll to shift the given region by one unit up, down, left, and right. The logical OR of the shifted regions is taken, and all distinct elements that match this condition are returned. It then remains to remove the region itself, since it's not considered its own neighbor.

Since roll re-introduces the values that move beyond array's bounds at the opposite ends (which is not desired here), an additional step is to replace this row or column with False.

import numpy as np

x = np.array([[1, 1, 1], [1, 1, 2], [2, 2, 2], [3, 3, 3]], np.int32)
region = 2   # number of region whose neighbors we want

y = x == region  # convert to Boolean

rolled = np.roll(y, 1, axis=0)          # shift down
rolled[0, :] = False             
z = np.logical_or(y, rolled)

rolled = np.roll(y, -1, axis=0)         # shift up 
rolled[-1, :] = False
z = np.logical_or(z, rolled)

rolled = np.roll(y, 1, axis=1)          # shift right
rolled[:, 0] = False
z = np.logical_or(z, rolled)

rolled = np.roll(y, -1, axis=1)         # shift left
rolled[:, -1] = False
z = np.logical_or(z, rolled)

neighbors = set(np.unique(np.extract(z, x))) - set([region])
print(neighbors)

If the regions are labelled with small integers (from 0 to n ideally), the labels can be used to index into a result array:

n = x.max()
tmp = np.zeros((n+1, n+1), bool)

# check the vertical adjacency
a, b = x[:-1, :], x[1:, :]
tmp[a[a!=b], b[a!=b]] = True

# check the horizontal adjacency
a, b = x[:, :-1], x[:, 1:]
tmp[a[a!=b], b[a!=b]] = True

# register adjacency in both directions (up, down) and (left,right)
result = (tmp | tmp.T)

For the example array in the question:

In [58]: result.astype(int)
Out[58]: 
array([[0, 0, 0, 0],
       [0, 0, 1, 0],
       [0, 1, 0, 1],
       [0, 0, 1, 0]])

In [60]: np.column_stack(np.nonzero(result))
Out[60]: 
array([[1, 2],
       [2, 1],
       [2, 3],
       [3, 2]])

In [361]: # Assuming labels start from `1`
          [np.flatnonzero(row) for row in result[1:]]
Out[361]: [array([2]), array([1, 3]), array([2])]
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!