【问题标题】:Pixel neighbors in 2d array (image) using Python使用 Python 的二维数组(图像)中的像素邻居
【发布时间】:2012-06-15 08:12:10
【问题描述】:

我有一个像这样的 numpy 数组:

x = np.array([[1,2,3],[4,5,6],[7,8,9]])

我需要创建一个函数,我们称之为“邻居”,输入参数如下:

  • x: 一个 numpy 二维数组
  • (i,j):二维数组中元素的索引
  • d:邻域半径

作为输出,我想获得具有给定距离d 的单元格i,j 的邻居。 所以如果我运行

neighbors(im, i, j, d=1) with i = 1 and j = 1 (element value = 5) 

我应该得到以下值的索引:[1,2,3,4,6,7,8,9]。我希望我说清楚。 有没有像 scipy 这样的库来处理这个问题?

我已经做了一些工作,但这是一个粗略的解决方案。

def pixel_neighbours(self, p):

    rows, cols = self.im.shape

    i, j = p[0], p[1]

    rmin = i - 1 if i - 1 >= 0 else 0
    rmax = i + 1 if i + 1 < rows else i

    cmin = j - 1 if j - 1 >= 0 else 0
    cmax = j + 1 if j + 1 < cols else j

    neighbours = []

    for x in xrange(rmin, rmax + 1):
        for y in xrange(cmin, cmax + 1):
            neighbours.append([x, y])
    neighbours.remove([p[0], p[1]])

    return neighbours

我该如何改进?

【问题讨论】:

    标签: python numpy computer-vision scipy nearest-neighbor


    【解决方案1】:

    看看scipy.ndimage.generic_filter.

    举个例子:

    import numpy as np
    import scipy.ndimage as ndimage
    
    def test_func(values):
        print(values)
        return values.sum()
    
    
    x = np.array([[1,2,3],[4,5,6],[7,8,9]])
    
    footprint = np.array([[1,1,1],
                          [1,0,1],
                          [1,1,1]])
    
    results = ndimage.generic_filter(x, test_func, footprint=footprint)
    

    默认情况下,它将“反映”边界处的值。您可以使用 mode 关键字参数来控制它。

    但是,如果您想做这样的事情,您很有可能可以将您的问题表达为某种卷积。如果是这样,将其分解为卷积步骤并使用更优化的函数(例如大部分scipy.ndimage)会更快。

    【讨论】:

    • 此方法比我使用 for 循环的自定义方法慢
    【解决方案2】:

    编辑:啊,废话,我的回答只是写im[i-d:i+d+1, j-d:j+d+1].flatten(),但写得有点难以理解:)


    古老的滑动窗口技巧在这里可能会有所帮助:

    import numpy as np
    from numpy.lib.stride_tricks import as_strided
    
    def sliding_window(arr, window_size):
        """ Construct a sliding window view of the array"""
        arr = np.asarray(arr)
        window_size = int(window_size)
        if arr.ndim != 2:
            raise ValueError("need 2-D input")
        if not (window_size > 0):
            raise ValueError("need a positive window size")
        shape = (arr.shape[0] - window_size + 1,
                 arr.shape[1] - window_size + 1,
                 window_size, window_size)
        if shape[0] <= 0:
            shape = (1, shape[1], arr.shape[0], shape[3])
        if shape[1] <= 0:
            shape = (shape[0], 1, shape[2], arr.shape[1])
        strides = (arr.shape[1]*arr.itemsize, arr.itemsize,
                   arr.shape[1]*arr.itemsize, arr.itemsize)
        return as_strided(arr, shape=shape, strides=strides)
    
    def cell_neighbors(arr, i, j, d):
        """Return d-th neighbors of cell (i, j)"""
        w = sliding_window(arr, 2*d+1)
    
        ix = np.clip(i - d, 0, w.shape[0]-1)
        jx = np.clip(j - d, 0, w.shape[1]-1)
    
        i0 = max(0, i - d - ix)
        j0 = max(0, j - d - jx)
        i1 = w.shape[2] - max(0, d - i + ix)
        j1 = w.shape[3] - max(0, d - j + jx)
    
        return w[ix, jx][i0:i1,j0:j1].ravel()
    
    x = np.arange(8*8).reshape(8, 8)
    print x
    
    for d in [1, 2]:
        for p in [(0,0), (0,1), (6,6), (8,8)]:
            print "-- d=%d, %r" % (d, p)
            print cell_neighbors(x, p[0], p[1], d=d)
    

    这里没有做任何计时,但这个版本可能有合理的性能。

    有关更多信息,请使用短语“滚动窗口 numpy”或“滑动窗口 numpy”搜索网络。

    【讨论】:

      【解决方案3】:

      我不知道这方面的任何库函数,但是您可以使用 numpy 的强大切片功能轻松地自己编写类似的东西:

      import numpy as np
      def neighbors(im, i, j, d=1):
          n = im[i-d:i+d+1, j-d:j+d+1].flatten()
          # remove the element (i,j)
          n = np.hstack((b[:len(b)//2],b[len(b)//2+1:] ))
          return n
      

      当然,您应该进行一些范围检查以避免越界访问。

      【讨论】:

      • b 在这里指的是什么?
      • b 没有定义,正如詹姆斯所说的
      【解决方案4】:

      通过使用maxmin,您可以处理上下边界的像素:

      im[max(i-1,0):min(i+2,i_end), max(j-1,0):min(j+2,j_end)].flatten()
      

      【讨论】:

        【解决方案5】:

        我同意乔金顿的回应,只是增加了足迹

        import numpy as np
        from scipy.ndimage import generate_binary_structure
        from scipy.ndimage import iterate_structure
        foot = np.array(generate_binary_structure(2, 1),dtype=int)
        

        或者更大/不同的足迹,例如

        np.array(iterate_structure(foot , 2),dtype=int)
        

        【讨论】:

          【解决方案6】:

          可能在SciPy 中使用KDTree 吗?

          【讨论】:

          • 就其价值而言,对于规则网格化的数据,四叉树并不理想。索引数据所在的网格可以让您更快地查找邻居。
          【解决方案7】:

          我们首先使用 numpy 初始化我们感兴趣的矩阵

          import numpy as np
          
          x = np.array([[1,2,3],[4,5,6],[7,8,9]])
          
          print(x)
          
          [[1 2 3]
           [4 5 6]
           [7 8 9]]
          

          我们的邻居是距离的函数,例如我们可能对距离为 2 的邻居感兴趣,这告诉我们应该如何填充矩阵 x。我们选择用零填充,但你可以用任何你喜欢的东西来填充,可能是平均值、模式、行/列的中位数

          d = 2
          
          x_padded = np.pad(x,d,mode='constant')
          
          print(x_padded)
          
          [[0 0 0 0 0 0 0]
           [0 0 0 0 0 0 0]
           [0 0 1 2 3 0 0]
           [0 0 4 5 6 0 0]
           [0 0 7 8 9 0 0]
           [0 0 0 0 0 0 0]
           [0 0 0 0 0 0 0]]
          

          我们使用x_padded 矩阵来获取矩阵x 中任意值的邻居。 让(i,j)(s,t) 分别是xx_padded 的索引。现在我们需要将(i,j) 翻译成(s,t) 以获得(i,j) 的邻居

          i,j = 2,1
          s,t = 2*d+i+1, 2*d+j+1
          
          window = x_padded[i:s, j:t]
          
          print(window)
          
          [[0 1 2 3 0]
           [0 4 5 6 0]
           [0 7 8 9 0]
           [0 0 0 0 0]
           [0 0 0 0 0]]
          

          请注意!!!索引(i,j) 指向您希望在矩阵x 中获取其邻居的任何值

          可能希望遍历矩阵x 中的每个点,获取其邻居 并使用邻居进行计算,例如在图像处理中,与内核的卷积。可以执行以下操作来获取图像中每个像素的邻居x

          for i in range(x.shape[0]):
              for j in range(x.shape[1]):
                  i,j = 2,1
                  s,t = 2*d+i+1, 2*d+j+1
                  window = x_padded[i:s, j:t]
          

          【讨论】:

          • edit您的答案,以便解释它如何回答 OP 的问题。在 Stack Overflow 上,代码转储不被视为有用的答案。
          • 请在您的代码前添加注释,以阐明这是如何解决问题的,将代码与其输出分开,并在结果后添加注释以分析结果中特别有用的内容。跨度>
          • 如果有任何问题或困惑我很乐意解决,我会尝试解释我的思考过程。
          猜你喜欢
          • 2021-05-23
          • 2017-10-04
          • 2013-04-08
          • 1970-01-01
          • 2014-02-26
          • 2010-10-13
          • 1970-01-01
          • 2017-12-23
          相关资源
          最近更新 更多