imshow如何处理M x N x 4输入的alpha通道?

10 投票
2 回答
8091 浏览
提问于 2025-04-18 15:42

这是一个关于GH问题的讨论,链接是#3343


我在使用matplotlib的imshow函数来可视化一些数据。我有两个数组,AB,它们的大小是一样的。我想用一个颜色映射来显示A中的数值,同时用透明度来显示B中的数值。换句话说,如果AB在某个坐标点的值都很大,那么图中的像素会是亮绿色并且不透明。如果A的值大而B的值小,那么像素会是亮绿色但大部分透明。如果B的值大而A的值小,那么像素会是不透明的白色。

然而,生成的图像并不是我所期待的。我输入的数据叫d,它是通过将A数组用matplotlib的颜色映射(比如mpl.cm.BuGn(A))和B数组结合得到的RGB值。

在这里,我将绘制完整的图像(我实际想用的),RGB图像(A,用BuGn映射)和提供透明度的数组(B,用灰度颜色映射)。

f, (ax0, ax1, ax2) = plt.subplots(1, 3, figsize=(5, 2.5))

ax0.imshow(d)
ax1.imshow(d[..., :-1])
ax2.imshow(d[..., -1])

enter image description here

我对完整图像中那些斑驳的灰色区域感到困惑,因为在颜色映射中并没有这些颜色的值。为了更明显地展示这个效果,我可以改变颜色映射的范围,让它远离数据的极值,然后重新绘制:

enter image description here

我不明白为什么那些白色且透明度很大的像素会显示为灰色。不透明的白色应该还是白色啊。

需要注意的是,这种行为和我绘制RGB组件数组并用alpha参数降低透明度的情况是不同的,比如ax2.imshow(d[..., :-1], alpha=.3)

enter image description here

2 个回答

4

来自尊敬的ballsdotballs的修订答案看起来很有道理。从那篇邮件列表的帖子来看,处理透明度(alpha值)似乎没有仔细考虑。此外,从原帖中的例子来看,我觉得在imshow中的alpha参数的合成方式与RGBA数据中提供的透明度数字是不同的。

为了绕过Agg所做的混合处理,可以不使用透明度,而是手动进行合成。

A = np.tile(np.linspace(0, 1, num=100), (100, 1))  # gradient
B = A.T
d = plt.cm.BuGn(A)
d[..., -1] = B

composite = (d[..., :-1] * d[..., -1].reshape(100, 100, 1) +
    (1 - d[..., -1]).reshape(100, 100, 1))

fig, axes = plt.subplots(1, 2)
axes[0].imshow(d)
axes[1].imshow(composite)

在这里输入图片描述

我相信还有更好的方法来进行重塑,但这不是这里讨论的重点。

2

我之前的回答完全错了,所以这是我新的尝试。

DaveAllen 上面的评论准确地描述了这个问题。

import numpy as np
import matplotlib.pyplot as plt

d = np.ones((100, 100, 4), dtype=np.uint8)*255
d[:, :, 3] = np.linspace(0, 255, num=100)
plt.imshow(d, interpolation='none')
plt.show()

结果是:

enter image description here

你可能会期待在白色背景上,带有可变透明度的白色图像应该是完全白色的。 这在使用“直通”透明度时确实是这样。

看起来,matplotlib 的图形后端在显示图像时假设使用的是“预乘”透明度,这意味着透明度会影响图像的颜色。 这就解释了上面的图像。

http://en.wikipedia.org/wiki/Alpha_compositing http://blogs.msdn.com/b/shawnhar/archive/2009/11/06/premultiplied-alpha.aspx https://www.mail-archive.com/matplotlib-users@lists.sourceforge.net/msg22377.html

像素 (1.0,1.0,1.0,0.5) 在显示时,颜色会先乘以它们的透明度通道,所以它们看起来是 (0.5,0.5,0.5,0.5),也就是灰色。

右边的像素是不透明的白色,所以它们看起来是白色的。 左边的像素是黑色和透明的,所以它们看起来和背景色一样,都是白色。

中间的像素是灰色,因为它们既不是白色也不是透明的。

撰写回答