【问题标题】:Does numpy.einsum act differently on arrays loaded by cv2?numpy.einsum 对 cv2 加载的数组的作用是否不同?
【发布时间】:2021-05-10 22:19:12
【问题描述】:

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

【问题讨论】:

  • 正如所写,没有人可以复制这个,不知道img_path。实际上,您的第二个代码块中似乎有错字:im/img。如果您可以在您的问题正文中提供一个较小的、可重复的示例来说明这种效果,那就太好了。即使只是打印img 的形状也会提供信息。
  • @NicholasM,谢谢。我做了一些改变。它是可重现的;然而,用户需要在他们的本地机器上安装一个图像。形状取决于加载的图像。如果有帮助,我的是一张 512X512 的图像,它变成了相同形状的二维矩阵。

标签: python cv2 numpy-einsum


【解决方案1】:

使用 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

【讨论】:

  • 有趣。感谢您的详细回答。
猜你喜欢
  • 2014-11-21
  • 1970-01-01
  • 2022-11-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-10-12
相关资源
最近更新 更多