【问题标题】:numpy blit (copy part of an array to another one with a different size)numpy blit(将数组的一部分复制到另一个具有不同大小的数组)
【发布时间】:2015-02-23 14:36:53
【问题描述】:

我想将一个数组复制到另一个大小不同的数组。 我想要这样的功能:

blit(destimg,src,dstlocation)

例如blit(zeros((7,7)),ones((3,3)),(4,4))

会导致

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

数组src 的左上中心现在位于数组destimg 的位置(4,4)

如果我这样做 blit(zeros((7,7)),ones((3,3)),(5,5)) 我会得到:

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

数组src 不适合destimg,但其左上角仍在正确位置。

【问题讨论】:

  • 您不能通过简单的赋值(即= 运算符)并使用适当的索引来实现您想要的吗?
  • @Jan-PhilipGehrcke 我可以,但是对于 src 数组不适合的情况,我必须进行一些计算才能确定正确的索引。我想知道 numpy 是否已经有一个功能。
  • 为什么你的blit功能不够用?
  • 也就是说,目标数组的全部或仅部分被整个源数组或仅部分源数组替换。所以,问题归结为找到索引,对吧。这是否只需要使用二维数组?还是应该适用于 n 维?

标签: python arrays opencv numpy


【解决方案1】:

您可以只计算适当的切片:

import numpy as np

def blit(dest, src, loc):
    pos = [i if i >= 0 else None for i in loc]
    neg = [-i if i < 0 else None for i in loc]
    target = dest[[slice(i,None) for i in pos]]
    src = src[[slice(i, j) for i,j in zip(neg, target.shape)]]
    target[[slice(None, i) for i in src.shape]] = src
    return dest

print(blit(np.zeros((7,7)), np.ones((3,3)), (5, 5)))

产量

[[ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  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.]
 [ 0.  0.  0.  0.  0.  1.  1.]]

print(blit(np.zeros((7,7)), np.ones((3,3)), (-1, -1)))

产量

[[ 1.  1.  0.  0.  0.  0.  0.]
 [ 1.  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.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]
 [ 0.  0.  0.  0.  0.  0.  0.]]

【讨论】:

    【解决方案2】:

    我能够找到一个解决方案(有点冗长),一定有一个更优雅的方法,但在中期这会做。

    from numpy import *
    
    def blit(dest, src, loc):
        th,tw=dest.shape
        sh,sw=src.shape
        sr = 0 if -loc[0]<0 else -loc[0]
        fr = sh if loc[0]+sh<=th else sh-(loc[0]+sh-th)
        sc = 0 if -loc[1]<0 else -loc[1]
        fc = sw if loc[1]+sw<=tw else sw-(loc[1]+sw-th)
        loc[0] = max(0,loc[0])
        loc[1] = max(0,loc[1])  
        dest[loc[0]:loc[0]+sh-sr,loc[1]:loc[1]+sw-sc] = src[sr:fr,sc:fc]
    
    dest = zeros((7,7))
    src = ones((3,3))
    loc = [5,5]
    blit(dest, src, loc)
    print dest
    

    产量:

    [[ 0.  0.  0.  0.  0.  0.  0.]
     [ 0.  0.  0.  0.  0.  0.  0.]
     [ 0.  0.  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.]
     [ 0.  0.  0.  0.  0.  1.  1.]]
    

    dest = zeros((7,7))
    src = ones((3,3))
    loc = [-1,-1]
    blit(dest, src, loc)
    print dest
    

    产量

    [[ 1.  1.  0.  0.  0.  0.  0.]
     [ 1.  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.  0.  0.]
     [ 0.  0.  0.  0.  0.  0.  0.]
     [ 0.  0.  0.  0.  0.  0.  0.]]
    

    【讨论】:

    • 如您所见,@unutbu 提出了一种更好的方法。您绝对应该利用这样一个事实,即 numpy 数组上的切片索引在超出范围的索引方面表现得与 Python 对内置类型的切片一样。引用 Python 对字符串的介绍:“退化的切片索引被优雅地处理:一个太大的索引被字符串大小替换,一个小于下限的上限返回一个空字符串。”
    【解决方案3】:

    这是我的实现:

    def blit(a, b, offsets=(0,), as_shapes=False):
        """
        Computes the slices of the overlapping regions of arrays <a> and <b>. If offsets are specified, 
        <b> will be shifted by these offsets before computing the overlap.
    
        Example:
              50
           ┌──────┐
           │      │ 
         65│  ┌───┼────┐
           │  │   │    │50
           └──┼───┘    │
              └────────┘
                  55
        <a> is the 65x50 array and <b> is the 50x55 array. The offsets are (32, 18). The returned 
        slices are [32:65, 18:50] for <a> and [0:33, 0:32] for <b>.
    
        Arrays of different dimensions can be used (e.g. 3-dimensional RGB image and 2-dimensional 
        grayscale image) but the slices will only go up to min(a.ndim, b.ndim). An offset with more 
        elements than that will throw a ValueException.
    
        Instead of arrays, shapes can be directly passed to the function by setting as_shapes to True.
    
        :param a: an array object or a tuple is as_shape is True
        :param b: an array object or a tuple is as_shape is True
        :param offsets: a sequence of offsets
        :param as_shapes: if True, <a> and <b> are expected to be array shapes rather than array
        :return: a multidimensional slice for <a> followed by a multidimensional slice for <b>
        """
    
        # Retrieve and check the array shapes and offset
        if not as_shapes:
            a, b = np.array(a, copy=False), np.array(b, copy=False)
            a_shape, b_shape = a.shape, b.shape
        else:
            a_shape, b_shape = a, b
        n = min(len(a_shape), len(b_shape))
        if n == 0:
            raise ValueError("Cannot overlap with an empty array")
        offsets = tuple(offsets) + (0,) * (n - len(offsets))
        if len(offsets) > n:
            raise ValueError("Offset has more elements than either number of dimensions of the arrays")
    
        # Compute the slices
        a_slices, b_slices = [], []
        for i, (a_size, b_size, offset) in enumerate(zip(a_shape, b_shape, offsets)):
            a_min = max(0, offset)
            a_max = min(a_size, max(b_size + offset, 0))
            b_min = max(0, -offset)
            b_max = min(b_size, max(a_size - offset, 0))
            a_slices.append(slice(a_min, a_max))
            b_slices.append(slice(b_min, b_max))
    
        return tuple(a_slices), tuple(b_slices) 
    
    def paste(a, b, offsets=(0,), copy=True):
        """
        Pastes array <b> into array <a> at position <offsets>
    
        :param a: an array object
        :param b: an array object
        :param offsets: the position in <a> at which <b> is to be pasted
        :param copy: whether to paste <b> in <a> or in a copy of <a>
        :return: either <a> or a copy of <a> with <b> pasted on it
        """
    
        out = np.array(a, copy=copy)
        a_slice, b_slice = blit(a, b, offsets)
        out[a_slice] = b[b_slice]
        return out
    

    【讨论】:

      猜你喜欢
      • 2017-04-03
      • 2020-04-14
      • 1970-01-01
      • 1970-01-01
      • 2015-06-17
      • 1970-01-01
      • 1970-01-01
      • 2020-10-22
      • 1970-01-01
      相关资源
      最近更新 更多