如果使用颜色映射或RGB数组,matplotlib imshow绘制的图像会有所不同。

17

我遇到了以下问题:我正在使用显微镜保存16位tiff图像,需要对其进行分析。 我想使用numpy和matplotlib来处理,但是当我想要做一些简单的事情,例如在绿色中绘制图像(稍后我还需要叠加其他图像),它就失败了。

这里是一个例子,当我尝试将图像绘制为RGB数组或使用默认的jet色图时。

import numpy as np
import matplotlib.pyplot as plt
import cv2

imageName = 'image.tif'

# image as luminance 
img1 = cv2.imread(imageName,-1)

# image as RGB array
shape = (img1.shape[0], img1.shape[1], 3)
img2 = np.zeros(shape,dtype='uint16')
img2[...,1] += img1

fig = plt.figure(figsize=(20,8))
ax1 = fig.add_subplot(1,2,1)
ax2 = fig.add_subplot(1,2,2)

im1 = ax1.imshow(img1,interpolation='none')
im2 = ax2.imshow(img2,interpolation='none')
fig.show()

对我来说,它呈现出以下的图像:enter image description here

如果这个问题太基础了,我很抱歉,但我不知道右边的图是为什么显示这些伪影。我想使用绿色尺度,得到类似于左图的图形(ImageJ也会生成类似于左图的结果)。

非常感谢您的合作。


你所看到的可能是img2uint16值溢出的结果。print img1.dtype输出什么?print img1.min(), img1.max()呢? - Joe Kington
这两张图片结构上是一样的,只是颜色映射不同,是我看错了吗?这就是问题所在吗? - Brian Cain
2个回答

40

我认为右侧的情节更具艺术性...

matplotlib在解释图像时相当复杂。大致如下:

  • 如果图像是任何类型的NxM数组,则通过颜色映射解释它(如果没有特别指定,则自动缩放)。 (原则上,如果数组是缩放到0..1的float数组,则应将其解释为灰度图像。这是文档中所说的,但实际上并不会发生。)

  • 如果图像是NxMx3的float数组,则RGB分量被解释为介于0..1之间的RGB分量。如果值超出此范围,则采用正模1,即1.2-> 0.2,-1.7-> 0.3等。

  • 如果图像是NxMx3的uint8数组,则将其解释为标准图像(0..255分量)

  • 如果图像是NxMx4,则解释方式与上述相同,但第四个分量是不透明度(alpha)

因此,如果您向matplotlib提供除uint8float之外的整数NxMx3数组,则结果未定义。但是,通过查看源代码,可以理解奇怪的行为:

if A.dtype != np.uint8:
    A = (255*A).astype(np.uint8)

其中A是图像数组。因此,如果您给出uint16值0、1、2、3、4...,您会得到0、255、254、253......是的,它看起来非常奇怪。(在我看来,解释可能需要更直观一些,但这就是实现方式。)


在这种情况下,最简单的解决方案是将数组除以65535,然后图像应该与预期相同。此外,如果您的原始图像确实是线性的,那么您将需要进行反伽马校正:

img1_corr = (img1 / 65535.)**(1/2.2)
否则你的中音将会太暗。

非常好的回答。我总是觉得这些整数类型(uint8、byte等)在任何图像处理方面都非常有限,尽管当你必须保存文件时它们是有意义的。对于matplotlib而言,在我看来最明智的方法是将每个整数类型的图像归一化到0-1范围内,然后才执行数学运算(例如,像这样纠正伽马:im **= gamma [你能相信这个有效吗?])。然后使用所需的色图绘制,并在保存时进行反归一化。 - heltonbiker

0

我通过将图像归一化到给定数据类型的最大值来处理它,如DrV所说,对于uint16来说,最大值是65535。辅助函数可能看起来像这样:

def normalise_bits(img):
    bits = 1.0  # catch all
    try:
        # Test integer value, e.g. np.uint16
        bits = np.iinfo(img.dtype).max
    except ValueError:
        # Try float maximum, e.g. np.float32
        bits = np.finfo(img.dtype).max
    return (img / bits).astype(float)

然后可以将图像处理为 matplotlib 中的浮点数 [0.0,1.0]。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接