numpy.einsum 对 cv2 加载的数组有不同的作用吗?

Does numpy.einsum act differently on arrays loaded by cv2?

einsumexample in numpy's documentation表示np.einsum('ij->i', a)的功能类似于np.sum(a, axis=1)。下面的示例 1 证实了这一点,而示例 2 则与之矛盾。知道我在做什么(预期)错了吗?

Exp 1.

import numpy as np

a = np.arange(25).reshape(5,5)
b1 = np.einsum('ij->i', a)   # array([ 10,  35,  60,  85, 110])
b2 = np.sum(a, axis=1)       # array([ 10,  35,  60,  85, 110])

Exp 2.

import numpy as np
import cv2

img_path = "path/to/an/image.png"
im = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE)    # type: numpy.ndarray
n1 = np.einsum('ij->i', im)
n2 = np.sum(img, axis=1)
# to show that they are different.
print(np.max(n1), np.max(n2))  # out: 255 119630

为什么 n1n2 不相同(如它们的 max 值所示)?

使用 cv2(和 PIL)加载的图像将属于 uint8 类型。与其他类型相比,同一类型内的计算结果可能不同。

>>> np.uint8(255) + np.uint8(1)
0
>>> np.int32(255) + np.int32(1)
256

np.arange 默认创建一个 int32 类型的数组,所以没有问题。但是

a = np.arange(64, dtype=np.uint8).reshape(8, 8)
b1 = np.einsum('ij->i', a)
b2 = np.sum(a, axis=1)
print(b1 == b2)

打印

[ True  True  True  True False False False False]

请注意,np.sum 会在后台转换类型,因此它可以容纳不受较短类型限制的添加。这并不是说 uint32 如果必须处理超出其支持范围的值就不会出现问题,但这种可能性较小。

>>> np.sum(np.uint8([1, 2])).dtype
dtype('uint32')

只要确保您使用的数据类型不会 运行 解决您的特定问题。

img = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE).astype(np.uint32)  # or np.int32
print(np.all(n1 == n2))   # this should now be true