数组相等但视觉上不一样

Equal arrays but not the same visually

我有一个 32x32x3 的图像,例如 keras 中的 cifar10 图像之一。 现在,假设我想做一些操作。首先,为了确保我做的事情是正确的,我试图复制图像(这不是我想做的,所以请不要告诉我如何在不做三个循环的情况下复制图像,我需要三个循环来操纵一些值)。

from keras.datasets import cifar10
import matplotlib.pyplot as plt

(X_train, Y_train), (X_test, Y_test) = cifar10.load_data()
im = numpy.reshape(X_train[0], (3, 32, 32))
im = im.transpose(1,2,0)
imC = numpy.zeros((32,32,3))

for k in range(3):
  for row in range(0,32):
    for col in range(0,32):
      imC[row][col][k] = im[row][col][k]

现在,如果我测试它们是否相同,实际上我看到 "cool" 打印出来了

if (im==imC).all():
  print "cool"

但是当我尝试想象它们时,它们是不同的:

plt.imshow( imC )
plt.show()

plt.imshow( im )
plt.show()

这是怎么回事?

Python CIFAR10 数据集中的图像具有 numpy.uint8 类型的像素值。 (大概它们是从 PNG 文件或类似文件中读取的。)所以 X_train.dtype == numpy.uint8 因此 im.dtype == numpy.uint8.

您创建的数组的默认元素类型为 numpy.float64。换句话说,imC.dtype == numpy.uint8.

碰巧 matplotlib.pyplot.imshow 会根据其元素类型对其输入进行不同的处理。特别是,如果你给它一个 m-by-n-by-3 元素类型 uint8 的数组,它将需要 0如您所料,对于三个颜色通道中的每一个,表示最暗,255 表示最亮;但是,如果你给它一个 m-by-n-by-3 元素类型 float64 的数组,它需要所有值在 0(最暗)到 1(最亮)范围内,文档没有说明超出该范围的值会发生什么。

我会冒险猜测超出该范围的值会发生什么:我认为代码可能会做类似的事情:乘以 255,四舍五入为整数,视为 uint8。这意味着 0 变为 0,1 变为 255。

但是如果最后一步意味着丢掉除低 8 位之外的所有位,这也意味着 2 变成 254,3 变成 253,...,255 变成 1!换句话说,如果您犯了一个非常容易理解的错误,即给 imshow 一个像素值在 0..255 范围内浮动的图像,这些值将被有效地取反,因此 0->0、1->255 , 2->254,...,255->1。 (这与将范围完全颠倒并不完全相同,因为 0 被保留了。)

这就是您遇到的情况:imC 的每个元素在数值上等于 im 的对应元素,但是因为 imC 是浮点数组而不是无符号数组-small-integer array 它得到了上面描述的处理,你几乎得到了你期望的图像的照片底片。