numpy.einsum 对 cv2 加载的数组的行为是否不同?

问题描述

einsumexample in numpy's documentation 表示 np.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,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 值所示)?

解决方法

加载了 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

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...