加入numpy的数组时避免溢出

问题描述 投票:14回答:7

我想补充的数据类型UINT8 numpy的阵列。我知道,在这些阵列中的值可以足够大的溢出发生。所以我得到的是这样的:

a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
a += b

现在,是[150 250 44]。然而,作为替代溢出我想这是太大UINT8是允许UINT8的最大值。所以,我期望的结果将是[150 250 255]

我能得到这个结果与下面的代码:

a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
c = np.zeros((1,3), dtype=np.uint16)
c += a
c += b
c[c>255] = 255
a = np.array(c, dtype=np.uint8)

问题是,我的数组是非常大的,因此创建具有较大的数据类型的第三组可能是内存问题。是否有一个快速和更多的内存高效的方式来实现所描述的结果?

python numpy image-processing integer-overflow numpy-ndarray
7个回答
8
投票

您可以通过创建D型UINT8的第三组,加上一个bool数组实现这一目标 (其一起是更高效的存储器的一个阵列UINT16) 。

np.putmask是用于避免温度阵列有用的。

a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
c = 255 - b  # a temp uint8 array here
np.putmask(a, c < a, c)  # a temp bool array here
a += b

然而,如@moarningsun正确地指出,一个bool阵列需要的存储器中,作为UINT8阵列相同的量,所以这并不一定是有帮助的。因此能够通过避免具有在任何给定时间多于一个的温度阵列来解决这个:

a = np.array([100, 200, 250], dtype=np.uint8)
b = np.array([50, 50, 50], dtype=np.uint8)
b = 255 - b  # old b is gone shortly after new array is created
np.putmask(a, b < a, b)  # a temp bool array here, then it's gone
a += 255 - b  # a temp array here, then it's gone

这种方法换内存消耗CPU。


另一种方法是预先计算所有可能的结果,这是O(1)额外的内存(即独立的数组的大小的):

c = np.clip(np.arange(256) + np.arange(256)[..., np.newaxis], 0, 255).astype(np.uint8)
c
=> array([[  0,   1,   2, ..., 253, 254, 255],
          [  1,   2,   3, ..., 254, 255, 255],
          [  2,   3,   4, ..., 255, 255, 255],
          ..., 
          [253, 254, 255, ..., 255, 255, 255],
          [254, 255, 255, ..., 255, 255, 255],
          [255, 255, 255, ..., 255, 255, 255]], dtype=uint8)

c[a,b]
=> array([150, 250, 255], dtype=uint8)

这种方法是最节省内存,如果你的阵列是非常大的。再次,这是在处理时间昂贵的,因为它替换为较慢2dim阵列索引超快速整数加法。

说明它如何WORKS

上述c阵列的建设使用了一个numpy的广播绝招。添加形状(N,)和形状的阵列的阵列(1,N)广播既要(N,N)状,因此其结果是所有可能的和的一个NxN阵列。然后,我们将它夹。我们得到一个2dim阵列,其满足c[i,j]=min(i+j,255)每个I,J。

那有什么用花哨的索引抓取正确的价值观离开了。根据您提供的输入工作,我们访问:

c[( [100, 200, 250] , [50, 50, 50] )]

第一索引阵列指的是第一暗淡,和第二到第二暗淡。因此,结果是相同的形状索引阵列((N,))的阵列,由值[ c[100,50] , c[200,50] , c[250,50] ]的。


3
投票

这里有一个方法:

>>> a = np.array([100, 200, 250], dtype=np.uint8)
>>> b = np.array([50, 50, 50], dtype=np.uint8)
>>> a+=b; a[a<b]=255
>>> a
array([150, 250, 255], dtype=uint8)

1
投票

如何做

>>> a + np.minimum(255 - a, b)
array([150, 250, 255], dtype=uint8)

一般获得与您的数据类型的最大值

np.iinfo(np.uint8).max

1
投票

你可以用Numba做到真正就位,例如:

import numba

@numba.jit('void(u1[:],u1[:])', locals={'temp': numba.uint16})
def add_uint8_inplace_clip(a, b):
    for i in range(a.shape[0]):
        temp = a[i] + b[i]
        a[i] = temp if temp<256 else 255

add_uint8_inplace_clip(a, b)

或用Numexpr,例如:

import numexpr

numexpr.evaluate('where((a+b)>255, 255, a+b)', out=a, casting='unsafe')

Numexpr upcasts uint8在内部int32,把它放回uint8阵列之前。


1
投票
def non_overflowing_sum(a, b)
    c = np.uint16(a)+b
    c[np.where(c>255)] = 255
    return np.uint8( c )

it行业内存太多,但我发现了更多的优雅和临时UINT16是在回报转换后获释


1
投票

OpenCV的具有这样的功能:cv2.addWeighted


0
投票

a function in numpy此:

numpy.nan_to_num(x)[source]

零替换楠和有限数量INF。

返回一个数组或标量代替不是数字(NaN)与零个,(正)无穷大一个非常大的数量和负无穷大与非常小的(或负)号。

新阵列具有相同的形状,在X具有最大精度的元素的x和D型。

如果x是不精确的,则NaN被由零替换,无穷大(-infinity)由最大(最小或最负)浮点符合该输出D型值所替代。如果x不是不精确,则返回x的拷贝。

我不知道这是否会与UINT8工作,因为浮点输出的提及,但对于其他的读者,这可能是有用的

© www.soinside.com 2019 - 2024. All rights reserved.