分配给numpy数组的包装切片

2024-05-28 11:16:48 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个大图像A和一个较小的图像B,它们都表示为二维numpy数组。我想用A作为画布,并在上面写下B的翻译副本,以六边形排列。我无法理解的部分是如何处理它,使图像在垂直和水平两个方向上都能包裹,基本上我想要的是将一个(必要时加上填充)子图像的规则细分到一个圆环上。在

我看过numpy.take和{}的讨论 wrapping around slices in Python / numpy这向我展示了如何访问和返回一个数组的包装切片的拷贝,但我想分配给它——即,对于任意整数rowOffset和{},我想做的等效于:

  A = numpy.zeros((5,11), int)
  B = numpy.array([[1,2,3,4,5,6,7]]) * numpy.array([[10,100,1000]]).T
  # OK, we wouldn't be able to fit more than one or two copies of B into A, but they demonstrate the wrapped placement problem

  wrappedRowIndices = ( numpy.arange(B.shape[0]) + rowOffset ) % A.shape[0]
  wrappedColumnIndices = ( numpy.arange(B.shape[1]) + columnOffset ) % A.shape[1]
  A[ wrappedRowIndices,  : ][ :, wrappedColumnIndices ] = B 

我从评论中看到on the question, 从对numpy数组表示方式的反思来看,包装好的切片不可能以这种方式返回为view。在

是否有(Y)一种以这种方式分配给数组的封装切片的方法,或者(X)一种用于执行我试图实现的细分的现有工具?在


Tags: the图像numpy画布方式副本切片数组
3条回答

这是一个函数,它根据hpaulj的答案来解决我的问题Y。然而,这可能不是求解X的最有效方法,因为在numpy.roll中完成了所有繁重的工作。在

import numpy

def place_wrapped(canvas, brush, position):
    mask = numpy.zeros(canvas.shape, bool)
    mask[[slice(extent) for extent in brush.shape]] = True
    for axis, shift in enumerate(position):
        canvas_extent = canvas.shape[axis]
        brush_extent = brush.shape[axis]
        shift %= canvas_extent
        if shift:
            mask = numpy.roll(mask, shift, axis=axis)
            nwrapped = shift + brush_extent - canvas_extent
            if nwrapped > 0: brush = numpy.roll(brush, nwrapped, axis=axis)
    numpy.place(canvas, mask, brush.flat)


A = numpy.zeros((5,11), int)
B = numpy.array([[1,2,3,4,5,6,7]]) * numpy.array([[10,100,1000]]).T
print(B)

rowOffset = 3
columnOffset = 7
place_wrapped(A, B, (rowOffset, columnOffset))
print(A)

Eric纠正的方法也起了作用,我认为它必须更高效,因为它不必复制任何数据:

^{pr2}$

np.put是1d等价于np.take

In [1270]: A=np.arange(10)
In [1271]: np.take(A,[8,9,10,11],mode='wrapped')
Out[1271]: array([8, 9, 0, 1])
In [1272]: np.put(A,[8,9,10,11],[10,11,12,13],mode='wrapped')
In [1273]: A
Out[1273]: array([12, 13,  2,  3,  4,  5,  6,  7, 10, 11])
In [1274]: np.take(A,[8,9,10,11],mode='wrapped')
Out[1274]: array([10, 11, 12, 13])

它的文档建议np.place和{}(和np.copyto)。我没有用过那么多,但是可以构造一个掩码,并重新排列B来完成复制。在

==============

下面是一个关于place的实验:

^{pr2}$

所以我有maskA相同的大小,有一个B大小的孔。在

我可以滚动maskB,以及{}以wrapped的方式滚动A中的值。在

In [1317]: np.place(A, np.roll(mask,-2,0), np.roll(B,1,0).flat)
In [1318]: A
Out[1318]: 
array([[ -8,  -9, -10, -11,   4,   5],
       [  6,   7,   8,   9,  10,  11],
       [  0,  -1,  -2,  -3,  16,  17],
       [ -4,  -5,  -6,  -7,  22,  23]])

还有2d卷

In [1332]: m=np.roll(np.roll(mask,-2,0),-1,1)
In [1333]: m
Out[1333]: 
array([[ True,  True,  True, False, False,  True],
       [False, False, False, False, False, False],
       [ True,  True,  True, False, False,  True],
       [ True,  True,  True, False, False,  True]], dtype=bool)
In [1334]: b=np.roll(np.roll(B,1,0),-1,1)
In [1335]: b
Out[1335]: 
array([[ -9, -10, -11,  -8],
       [ -1,  -2,  -3,   0],
       [ -5,  -6,  -7,  -4]])
In [1336]: A=np.zeros((4,6),int)
In [1337]: np.place(A, m, b.flat)
In [1338]: A
Out[1338]: 
array([[ -9, -10, -11,   0,   0,  -8],
       [  0,   0,   0,   0,   0,   0],
       [ -1,  -2,  -3,   0,   0,   0],
       [ -5,  -6,  -7,   0,   0,  -4]])

当前代码分为__getitem____setitem__。如您所述,__getitem__不返回视图,因此__setitem__只是修改了副本。在

您需要在一个__setitem__(即一组括号)中完成整个操作:

A[wrappedRowIndices[:,np.newaxis], wrappedColumnIndices] = B

由于广播,这相当于:

^{pr2}$

使用多个数组编制索引时,规则如下:

# ... here is NOT the python Ellipsis!
y = x[a, b, c, ...]
y[i, j, ..] = x[a[i,j,...], b[i,j,...], ...]

实际上有一个内置项,^{}

A[np.ix_(wrappedRowIndices, wrappedColumnIndices)] = B

概括到ND,您可以得到:

def place_wrapped(canvas, brush, position):
    assert canvas.ndim == brush.ndim == len(position)
    ind = np.ix_(*(
        (np.arange(b_dim) + shift) % c_dim
        for b_dim, c_dim, shift in zip(brush.shape, canvas.shape, position)
    ))
    canvas[ind] = brush

相关问题 更多 >