【问题标题】:Smoothing a 2-D Numpy Array with a Kernel使用内核平滑二维 Numpy 数组
【发布时间】:2020-04-14 06:44:42
【问题描述】:

假设我有一个 (m x n) 二维 numpy 数组,它只有 0 和 1。我想通过在数组上运行例如 3x3 内核并获取该内核中的多数值来“平滑”数组。对于边缘的值,我会忽略“缺失”的值。

例如,假设数组看起来像

import numpy as np

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

从左上角的“1”开始,以第一个左上角元素为中心的 3 x 3 内核将丢失第一行和第一列。我想要处理的方式就是忽略它并考虑剩余的 2 x 2 矩阵:

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 1 1 1 1 0
0 0 1 1 1 1 1 0
0 0 1 1 1 1 1 0
0 0 1 1 1 1 1 0
0 0 1 1 1 1 0 0
0 0 0 0 0 0 0 0

我该如何做到这一点?

【问题讨论】:

  • 你在 scipy 中见过rank_filter 吗?它可能无法解决问题。但它让我想起了这一点。

标签: python numpy convolution


【解决方案1】:

您可以使用skimage.filters.rank.majority 为每个值分配其邻域内出现次数最多的值。可以使用skimage.morphology.square 定义3x3 内核:

from skimage.filters.rank import majority
from skimage.morphology import square

majority(x.astype('uint8'), square(3))

array([[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, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0]], dtype=uint8)

注意:对于majority,您需要scikit-image 的最新稳定版本。更多here

【讨论】:

  • 啊,太好了!我最终为scipy.ndimage.filters.generic_filter 定义了我自己的函数,但我会检查一下。 (我也刚刚发布了我的答案)
  • 另外,这似乎具有我在原始问题中打算的边界行为。看起来在边界处,它忽略了“缺失值”,然后在平局的情况下,它取较低的值?尝试查看文档:scikit-image.org/docs/dev/api/…,但似乎没有明显记录边界处的行为或平局。
  • 不,文档中没有太多内容。我认为您必须查看here。 @文森特
【解决方案2】:

我最终做了这样的事情(基于How do I use scipy.ndimage.filters.gereric_filter?):

import scipy.ndimage.filters
import scipy.stats as scs


def filter_most_common_element(a, w_k=np.ones(shape=(3, 3))):
    """
    Creating a function for scipy.ndimage.generic_filter.

    See https://docs.scipy.org/doc/scipy/reference/generated/scipy.ndimage.generic_filter.html for more information
    on generic filters. 

    This filter takes a kernel of np.ones() to find the most common element in the array.
    Based off of https://stackoverflow.com/questions/61197364/smoothing-a-2-d-numpy-array-with-a-kernel
    """
    a = a.reshape(w_k.shape)
    a = np.multiply(a, w_k)

    # See https://docs.scipy.org/doc/scipy-0.19.0/reference/generated/scipy.stats.mode.html
    most_common_element = scs.mode(a, axis=None)[0][0]
    return most_common_element
x = np.array([[1, 0, 0, 0, 0, 0, 1, 0],
              [0, 0, 0, 0, 0, 0, 0, 0],
              [0, 0, 1, 1, 1, 1, 1, 0],
              [0, 0, 1, 1, 0, 1, 1, 0],
              [0, 0, 1, 0, 1, 1, 1, 0],
              [0, 1, 1, 1, 1, 0, 1, 0],
              [0, 0, 1, 1, 1, 1, 1, 0],
              [0, 0, 0, 0, 0, 0, 0, 0]])

out = scipy.ndimage.filters.generic_filter(x, filter_most_common_element, footprint=np.ones((3,3)),mode='constant',cval=0.0)

out
array([[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, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 1, 0],
       [0, 0, 1, 1, 1, 1, 0, 0],
       [0, 0, 0, 0, 0, 0, 0, 0]])

【讨论】:

  • 啊,刚刚意识到这并没有按照我在原始帖子中指定的方式处理边界。 mode='constant',cval=0.0 所做的是,对于边界处的“缺失值”,它假定一个恒定值 0(而不是完全忽略它们)
猜你喜欢
  • 1970-01-01
  • 2016-05-08
  • 1970-01-01
  • 2019-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-16
  • 1970-01-01
相关资源
最近更新 更多