【问题标题】:Finding median of masked ndarrays representing images查找表示图像的掩码 ndarray 的中值
【发布时间】:2013-09-12 13:37:22
【问题描述】:

我有 5 张灰度图像,格式为 288x288 ndarrays。每个ndarray 中的值只是numpy.float32 范围从0.0 到255.0 的数字。对于每个ndarray,我创建了一个numpy.ma.MaskedArray 对象,如下所示:

def bool_row(row):
    return [value == 183. for value in row]

mask = [bool_row(row) for row in nd_array_1]
masked_array_1 = ma.masked_array(nd_array_1, mask=mask)

183. 代表图像中的“垃圾”。所有 5 幅图像中都有一些“垃圾”。我想取蒙面图像的中值,其中每个点的中值应忽略任何蒙面值。结果将是没有垃圾的正确图像。

当我尝试时:

ma.median([masked_array_1, masked_array_2, masked_array_3, masked_array_4, masked_array_5], axis=0)

我得到的似乎是中位数,但它没有忽略掩码值,而是将它们视为183.,因此结果只是所有图片中叠加的垃圾。当我只取两个蒙版图像的中位数时:

ma.median([masked_array_1, masked_array_2], axis=0)

看起来它开始做正确的事情,但随后放置了 183. 的值,即使两个掩码数组都包含 MaskedConstant

我可以执行以下操作,但我觉得可能有一种方法可以使 ma.median 的行为符合预期:

unmasked_array_12 = ma.median([masked_array_1, masked_array_2], axis=0)
mask = [bool_row(row) for row in unmasked_array_12]
masked_array_12 = ma.masked_array(unmasked_array_12, mask=mask)

unmasked_array_123 = ma.median([masked_array_12, masked_array_3], axis=0)
mask = [bool_row(row) for row in unmasked_array_123]
masked_array_123 = ma.masked_array(unmasked_array_123, mask=mask)

...

如何让ma.median 按预期工作而不诉诸上述不愉快?

【问题讨论】:

  • 为什么不用mask = nd_array_1 == 183. 来制作你的面具?
  • @BiRico,是的,这是制作面具的更好方法,谢谢!

标签: python image numpy scipy


【解决方案1】:

我怀疑问题在于ma.median 如何处理非数组参数。它可能会将列表转换为普通的 numpy 数组,而不检查列表元素的类型。

考虑下面的一维数组示例:

In [64]: a = ma.array([1, 2, -10, 3, -10, -10], mask=[0,0,1,0,1,1])

In [65]: b = ma.array([1, 2, -10, -10, 4, -10], mask=[0,0,1,1,0,1])

In [66]: a
Out[66]: 
masked_array(data = [1 2 -- 3 -- --],
             mask = [False False  True False  True  True],
       fill_value = 999999)


In [67]: b
Out[67]: 
masked_array(data = [1 2 -- -- 4 --],
             mask = [False False  True  True False  True],
       fill_value = 999999)

以下内容不正确——它似乎忽略了掩码:

In [68]: ma.median([a, b])
Out[68]: -4.5

In [69]: ma.median([a, b], axis=0)
Out[69]: 
masked_array(data = [  1.    2.  -10.   -3.5  -3.  -10. ],
             mask = False,
       fill_value = 1e+20)

但是,如果我首先使用 ma.array 创建一个新的掩码数组,ma.median 会正确处理它:

In [70]: c = ma.array([a, b])

In [71]: c
Out[71]: 
masked_array(data =
 [[1 2 -- 3 -- --]
 [1 2 -- -- 4 --]],
             mask =
 [[False False  True False  True  True]
 [False False  True  True False  True]],
       fill_value = 999999)


In [72]: ma.median(c)
Out[72]: 2.0

In [73]: ma.median(c, axis=0)
Out[73]: 
masked_array(data = [1.0 2.0 -- 3.0 4.0 --],
             mask = [False False  True False False  True],
   fill_value = 1e+20)

所以要解决你的问题,它可能就像替换这个一样简单:

ma.median([masked_array_1, masked_array_2, masked_array_3, masked_array_4, masked_array_5], axis=0)

用这个:

stacked = ma.array([masked_array_1, masked_array_2, masked_array_3, masked_array_4, masked_array_5])
ma.median(stacked, axis=0)

【讨论】:

    【解决方案2】:

    您可以在计算中位数时使用以下方法去除所有 183 个值:

    masked_arrays=[masked_array_1, masked_array_2, masked_array_3]
    no_junk_arrays=[[x for x in masked_array if x is not 183] for masked_array in masked_arrays]
    
    ma.median(no_junk_arrays)
    

    例如

    >>> masked_array_1 = [1,183,4]
    >>> masked_array_2 = [1,183,2]
    >>> masked_array_3 = [2,183,2]
    >>> masked_arrays=[masked_array_1,masked_array_2,masked_array_3]
    >>> no_junk_arrays=[[x for x in masked_array if x is not 183] for masked_array in masked_arrays]
    >>> no_junk_arrays
    [[1, 4], [1, 2], [2, 2]]
    

    【讨论】:

    • 数组在不同的地方有 183 个。一个稍微现实一点的例子是:ma1 = [1, 183, 2]ma2 = [1, 183, 183]ma4 = [183, 4, 2]。所需的中位数为[1, 4, 2]。请注意,如果两个数组在特定索引处没有垃圾,那么它们将在那里具有相同的值,因为它们都表示相同的图像,只是垃圾覆盖了图像的不同部分。
    【解决方案3】:

    如果您发现要调用的 numpy 函数的巧妙序列,我相信它可以完成。但也可以天真地做:

    def merge(a1, a2):
        result = []
        for x, y in zip(a1, a2):
            if x == 183:
                x = y
            result.append(x)
        return result
    
    array_1 = [1, 183, 2]
    array_2 = [1, 183, 183]
    array_3 = [183, 4, 2]
    
    print merge(merge(array_1, array_2), array_3)
    

    如果结果运行得太慢,您可以在 PyPy 而不是 CPython 上尝试相同的代码。

    【讨论】:

      【解决方案4】:

      如果您要获取每个像素的非 nan 值,您可以执行以下操作:

      stacked_imgs = np.dstack((img1, img2, img3))
      mask = stacked_imgs == 183
      # Find the first False, i.e. non-183 entry, along stack axis
      index = np.argmin(mask, axis=-1)
      correct_image = stacked_image[..., index]
      

      如果给定像素的所有非 183 条目始终相同,这将为您提供所需的结果。

      【讨论】:

        猜你喜欢
        • 2021-04-17
        • 2021-05-20
        • 1970-01-01
        • 2021-12-15
        • 2010-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-21
        相关资源
        最近更新 更多