【问题标题】:Scipy label erosionScipy标签侵蚀
【发布时间】:2011-12-20 18:57:57
【问题描述】:

如何在 numpy 数组中的标记区域周围保留一圈像素?

在一个简单的情况下,我会减去侵蚀。当标签接触时,这种方法不起作用。如何从A 获取B

A = array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

B = array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])

我正在处理具有许多标签的大型数组,因此每个标签上的单独侵蚀不是一种选择。

【问题讨论】:

    标签: python numpy scipy


    【解决方案1】:

    新答案

    其实我只是想到了一个更好的办法:

    B = A * (np.abs(scipy.ndimage.laplace(A)) > 0)
    

    作为一个完整的例子:

    import numpy as np
    import scipy.ndimage
    
    A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    
    B = A * (np.abs(scipy.ndimage.laplace(A)) > 0)
    

    我认为这应该适用于所有情况(“标记”数组,例如A,无论如何......)。

    如果您担心性能,可以将其拆分为几部分以减少内存开销:

    B = scipy.ndimage.laplace(A)
    B = np.abs(B, B) # Preform abs in-place
    B /= B  # This will produce a divide by zero warning that you can safely ignore
    B *= A  
    

    这个版本更冗长,但应该使用更少的内存。

    旧答案

    我想不出用通常的 scipy.ndimage 函数一步完成的好方法。 (我觉得 tophat 过滤器应该可以满足您的需求,但我无法弄清楚。)

    但是,正如您所提到的,可以选择进行几次单独的腐蚀。

    如果您使用find_objects 提取每个标签的子区域,然后只对子区域进行侵蚀,即使在非常大的数组上也应该获得合理的性能。

    例如:

    import numpy as np
    import scipy.ndimage
    
    A = np.array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
                  [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
                  [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    
    regions = scipy.ndimage.find_objects(A)
    
    mask = np.zeros_like(A).astype(np.bool)
    
    for val, region in enumerate(regions, start=1):
        if region is not None:
            subregion = A[region]
            mask[region] = scipy.ndimage.binary_erosion(subregion == val)
    
    B = A.copy()
    B[mask] = 0
    

    这会产生:

    array([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 0, 0, 0, 2, 0, 0, 0],
           [0, 0, 2, 0, 0, 2, 2, 2, 2, 0, 0, 0],
           [0, 0, 2, 2, 2, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0],
           [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
    

    对于大型数组,性能应该是合理的,但这在很大程度上取决于不同标记对象跨越的区域有多大以及您拥有的标记对象的数量......

    【讨论】:

    • 标签数组是稀疏的,所以应该可以正常工作。我今天早上上班的路上其实也有同样的想法……
    • 其实我只是想到了一个更好的方法。 (尽管在某些情况下原始答案可能会更快......)查看编辑。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多