首页 > 解决方案 > numpy.einsum 对 cv2 加载的数组的作用是否不同?

问题描述

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

经验 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])

经验 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值所示)?

标签: pythoncv2numpy-einsum

解决方案


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

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

np.arange默认情况下创建一个 type 数组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

推荐阅读