scipy 使用Python的2D数组(图像)中的像素邻域

ozxc1zmp  于 2022-11-10  发布在  Python
关注(0)|答案(7)|浏览(157)

我有一个numpy数组,如下所示:

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

我需要创建一个函数,我们将其命名为“neighbors”,输入参数如下:

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

作为输出,我想得到像元i,j在给定距离d下的邻居。

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

我该如何改进这一点?

bybem2ql

bybem2ql1#

请查看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)。

wlp8pajw

wlp8pajw2#

EDIT:啊废话,我的答案只是写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”。

xxls0lw8

xxls0lw83#

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

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

qni6mghb4#

我不知道有什么库函数可以实现这一点,但是您可以使用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((n[:len(n)//2], n[len(n)//2+1:] ))
    return n

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

ws51t4hk

ws51t4hk5#

我同意乔·金顿的回答,只是增加了脚印

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)
xmjla07d

xmjla07d6#

是否可能在SciPy中使用KDTree

nqwrtyyt

nqwrtyyt7#

我们首先使用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中的每个点进行迭代,获得其邻居,并使用邻居进行计算,例如在图像处理中,与核进行卷积。

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]

相关问题