数组相等但视觉上不一样
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 它得到了上面描述的处理,你几乎得到了你期望的图像的照片底片。
我有一个 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 它得到了上面描述的处理,你几乎得到了你期望的图像的照片底片。