当范围(0,255)中的常规RGB图像转换为浮点数,然后由matplotlib显示时,图像显示为负数。如果它被转换为uint8,它会正确显示(当然)。找出发生的事情让我有些麻烦,因为我意外地将其中一张图像投射为浮动图像。
我很清楚,当转换为float时,图像应该在范围(0,1)内,当然,当除以255时,显示的图像是正确的。但是,为什么投射为浮点数的范围(0,255)中的图像显示为负数?我原本期望饱和度(全白)或自动推断输入范围(从而正确显示)?如果发生了其中任何一个预期的事情,我就能更快地调试我的代码。我已经包含了重现行为所需的代码。有没有人知道为什么会这样?
import numpy as np
import matplotlib.pyplot as plt
a = np.random.randint(0,127,(200,400,3))
b = np.random.randint(128,255,(200,400,3))
img=np.concatenate((a,b)) # Top should be dark ; Bottom should be light
plt.imshow(img) # Inverted
plt.figure()
plt.imshow(np.float64(img)) # Still Bad. Added to address sascha's comment
plt.figure()
plt.imshow(255-img) # Displayed Correctly
plt.figure()
plt.imshow(np.uint8(img)) # Displayed Correctly
plt.figure()
plt.imshow(img/255.0) # Displays correctly
答案 0 :(得分:4)
在来源image.py
中,在AxesImage
类(imshow
返回的内容)中,在绘图过程中的某个时刻调用方法_get_unsampled_image
。相关代码在226行开始(matplotlib-1.5.3):
if A.dtype == np.uint8 and A.ndim == 3:
im = _image.frombyte(A[yslice, xslice, :], 0)
im.is_grayscale = False
else:
if self._rgbacache is None:
x = self.to_rgba(A, bytes=False)
# Avoid side effects: to_rgba can return its argument
# unchanged.
if np.may_share_memory(x, A):
x = x.copy()
# premultiply the colors
x[..., 0:3] *= x[..., 3:4]
x = (x * 255).astype(np.uint8)
self._rgbacache = x
因此,检查输入A
的类型和大小:
if A.dtype == np.uint8 and A.ndim == 3:
在这种情况下没有预处理。否则,在不检查输入范围的情况下,您最终会乘以255并转换为uint8
:
x = (x * 255).astype(np.uint8)
如果x
从0到255而不是0到1,我们知道会发生什么:
In [1]: np.uint8(np.array([1,2,128,254,255])*255)
Out[1]: array([255, 254, 128, 2, 1], dtype=uint8)
光线变暗了。这反过来可能不是我认为你假设的计划行为。
您可以比较每个输入案例从_rgbacache
返回的对象中imshow
的值,以观察结果,例如im._rbacache
其中im = plt.imshow(np.float64(img))
。
答案 1 :(得分:1)
我认为你在声称这里的路径错误,np.random.randint()
应该返回一个基于浮点数的数组。 没有!(docs)
这意味着:
你的第一个图是使用 numpy-array of dtype = int64 调用imshow。如here所示,这是不允许的!
维度唯一允许的dtypes描述为:(see docs):
MxNx3 – RGB (float or uint8 array) # there are others
# -> this one applies to your dims!
在你的例子中唯一有效的imshow调用是3号和4号(1和2都是无效的)!
清单:
plt.imshow(img)
不行,如dtype = int64 plt.imshow(255-img)
不行,如dtype = int64 plt.imshow(np.uint8(img))
确定,因为dtype = uint8(和兼容的dims)plt.imshow(img/255.0)
确定,因为dtype = float(和兼容的dims)<强>注:强>
如果这让你感到紧张,你可以查看scikit-image,这在设计上对图像的内部表示更加谨慎(在自定义修改和结果类型期间)。内部数据结构仍然是numpy-arrays!