numpy 根据面积阈值删除4个连接孤岛

fhg3lkii  于 2023-05-29  发布在  其他
关注(0)|答案(2)|浏览(127)

我想移除面积小于阈值的孤岛。岛定义为4个连接。
例如,当输入数组为

import matplotlib.pyplot as plt
import numpy as np

array = np.array(
    [[1, 1, 1, 1, 0, 1, 1, 0, 0, 0],
     [0, 1, 0, 1, 0, 0, 1, 1, 0, 1],
     [0, 1, 1, 1, 0, 0, 0, 0, 1, 1],
     [1, 1, 0, 1, 0, 1, 1, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1],
     [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
     [1, 1, 1, 1, 0, 1, 1, 0, 1, 1],
     [1, 0, 1, 0, 0, 0, 0, 1, 1, 1],
     [1, 1, 1, 0, 0, 1, 0, 1, 0, 1]])

plt.matshow(array)

并且阈值为5,将岛小于5的单元值设置为0。预期的数组如下所示。

expected = np.array(
    [[1, 1, 1, 1, 0, 0, 0, 0, 0, 0],
     [0, 1, 0, 1, 0, 0, 0, 0, 0, 0],
     [0, 1, 1, 1, 0, 0, 0, 0, 0, 0],
     [1, 1, 0, 1, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 1, 1, 1],
     [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
     [1, 1, 1, 1, 0, 1, 1, 0, 1, 1],
     [1, 0, 1, 0, 0, 0, 0, 1, 1, 1],
     [1, 1, 1, 0, 0, 0, 0, 1, 0, 1]])
plt.matshow(expected)

0h4hbjxa

0h4hbjxa1#

我可以实现这个功能。

def remove_islands(array, threshold):
    islands = np.arange(
        1, array.size + 1)[::-1].reshape(array.shape)
    islands *= array
    # add one pixel buffers
    islands_buffered = np.zeros(
        shape=(islands.shape[0] + 2, islands.shape[1] + 2),
        dtype=islands.dtype
    )
    islands_buffered[1:-1, 1:-1] = islands
    kernel = np.array([
        [0, 1, 0],
        [1, 1, 1],
        [0, 1, 0],
    ])
    while True:
        islands_buffered_old = islands_buffered.copy()
        # ascending
        for i in range(1, array.shape[0]+1):
            for j in range(1, array.shape[1]+1):
                if islands_buffered[i, j] == 0:
                    continue
                islands_buffered[i, j] = np.max(
                    islands_buffered[i-1:i+2, j-1:j+2] * kernel)
        if np.array_equal(islands_buffered, islands_buffered_old):
            break
        # descending
        for i in range(array.shape[0]+1, 0, -1):
            for j in range(array.shape[1]+1, 0, -1):
                if islands_buffered[i, j] == 0:
                    continue
                islands_buffered[i, j] = np.max(
                    islands_buffered[i-1:i+2, j-1:j+2] * kernel)
        if np.array_equal(islands_buffered, islands_buffered_old):
            break

    islands = islands_buffered[1:-1, 1:-1]
    unique, counts = np.unique(islands, return_counts=True)
    small_islands = unique[counts < threshold]
    islands[np.isin(islands, small_islands)] = 0
    islands[islands != 0] = 1
    return islands

out = remove_islands(array, threshold=5)
print(out)
plt.matshow(out)
[[1 1 1 1 0 0 0 0 0 0]
 [0 1 0 1 0 0 0 0 0 0]
 [0 1 1 1 0 0 0 0 0 0]
 [1 1 0 1 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 0 0 0]
 [0 0 0 0 0 0 0 1 1 1]
 [0 0 0 0 0 0 1 1 1 0]
 [1 1 1 1 0 1 1 0 1 1]
 [1 0 1 0 0 0 0 1 1 1]
 [1 1 1 0 0 0 0 1 0 1]]

cyej8jka

cyej8jka2#

可以使用scipy.ndimage.label生成标签要素数组。然后计算特征的数量,如果它小于阈值,将值更改为0:

import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import label

array = np.array(
    [[1, 1, 1, 1, 0, 1, 1, 0, 0, 0],
     [0, 1, 0, 1, 0, 0, 1, 1, 0, 1],
     [0, 1, 1, 1, 0, 0, 0, 0, 1, 1],
     [1, 1, 0, 1, 0, 1, 1, 0, 0, 0],
     [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
     [1, 1, 0, 1, 0, 1, 0, 1, 1, 1],
     [0, 0, 0, 0, 0, 0, 1, 1, 1, 0],
     [1, 1, 1, 1, 0, 1, 1, 0, 1, 1],
     [1, 0, 1, 0, 0, 0, 0, 1, 1, 1],
     [1, 1, 1, 0, 0, 1, 0, 1, 0, 1]])

expected = array
threshold  = 5

labeled_array, num_features = label(array)

for feature in range(1, num_features+1):
    index = np.where(labeled_array==feature)
    num = len(index[0])
    if num < threshold:
        expected[index] = 0
        
plt.matshow(expected)

结果:

相关问题