Bizzare matplotlib在显示投射为浮动的图像时的行为

时间:2016-10-07 20:36:32

标签: python matplotlib

当范围(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

2 个答案:

答案 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!