Numpy:在不丢失精度/溢出的情况下乘以数组

时间:2017-04-12 23:07:57

标签: python arrays numpy

我正在使用Numpy对图片文件进行一些基本操作。我想执行以下操作:

in1, in2, out # some numpy arrays of dtype uint8
out = in1 * in2 / 256

但是,由于uint8的大小和模运算的规则,会发生溢出,结果不正确。

(例如,在C ++中不会出现同样的问题,其中中间结果可以存储在更大尺寸的临时空间中。)

另一种方法是执行两次乘法:out = in1/16 * in2/16。但是,这会导致输出的真空值。

一个有效的解决方案是手动设置每个像素:

out = numpy.empty(in1.shape, dtype="uint8")
for i in range(out.shape[0]):
    out[i] = int(in1[i])*in2[i]/256

然而,这需要您知道数组中维度的确切数量,并且通常不够优雅(并且由于显式循环,可能会更慢)。

另一种方法是将其中一个源矩阵转换为更高精度的类型,例如:

out = in1.astype("uint16")*in2/256

然而,这个可能是内存密集型的,因为它复制整个数组,而不是只保留一个带有中间结果的变量。

修改

这是一个小例子:

in1 = numpy.array([2, 4, 6], dtype="uint8")
in2 = numpy.array([128, 128, 128], dtype="uint8")

out = numpy.empty((3,), dtype="uint8")

# what I want to get: array([1, 2, 3], dtype=uint8)

out[:] = in1 * in2 / 256 # array([0, 0, 0], dtype=uint8)

所以,这是我的问题:我还有另一种方法吗?是否有一种首选的(或只是有效的)方式来做我想做的事情,或者我只需要重构我的程序?

1 个答案:

答案 0 :(得分:1)

在numpy中,您可以使用dtype参数在另一个dtype中计算临时数组,而无需显式复制数组:

>>> out = np.multiply(in1, in2, dtype=np.uint16)  # overflow safe multiplication
>>> np.floor_divide(out, 256, out=out)            # in-place division
>>> out
array([1, 2, 3], dtype=uint16)

然而,out将是一个uint16数组(因为人们不能用numpy连接ufunc)。但它尽可能避免使用临时数组。