我有点情况。我需要的是一个黑色背景的情节,在黑色背景上绘制了几个白色圆圈。
我设法使用以下代码执行此操作:
import numpy
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax.add_artist(plt.Circle((0., 0., .5), color = "white"))
plt.xlim(-5, 5)
plt.ylim(-5, 5)
fig.savefig("test.png", dpi = 300)
plt.show()
这会产生以下结果:
现在,我想做的是让这张图片透明化。所以这意味着只有白圈应该变得透明。您可能已经能够看到问题,因为如果我设置transparent = True
。黑色背景自动变得透明,我失去了黑色的颜色。
我尝试的另一件事是不在transparent = True
中设置savefig
,而是在alpha = 0.
中实际设置选项plt.Circle
。这使得白色圆圈实际上是透明的,这是最终目标。但是,因为它是透明的,所以我留下了整个黑色背景。有什么想法可以解决这个问题吗?
总结一下我的目标:
我想保存图中的透明版本,其中白色圆圈是透明的,而黑色部分则不是。
我知道我可以使用inkscape
和gimp
之类的不同程序来创建我想要的内容。但是,由于我需要执行其他操作,我确实需要在python中执行此操作。
谢谢!
答案 0 :(得分:5)
编辑3:
已经澄清了基本问题是:
如何把黑&&透明'在imshow
生成的matplotlib图像前掩码?
掩模应由先前绘制的黑色和暗色的matplotlib产生。白人。
以下代码通过访问和混合图形rgba位图来演示此功能:
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.cm as cm
import matplotlib.mlab as mlab
def get_rgba_bitmap(fig):
fig.canvas.draw()
tab = fig.canvas.copy_from_bbox(fig.bbox).to_string_argb()
ncols, nrows = fig.canvas.get_width_height()
return np.fromstring(tab, dtype=np.uint8).reshape(nrows, ncols, 4)
def black_white_to_black_transpa(rgba):
rgba[:, :, 3] = 255 - rgba[:, :, 0]
rgba[:, :, 0:3] = 0
def over(rgba1, rgba2):
if rgba1.shape != rgba2.shape:
raise ValueError("rgba1 and rgba2 shall have same size")
alpha = np.expand_dims(rgba1[:, :, 3] / 255., 3)
rgba = np.array(rgba1 * alpha + rgba2 * (1.-alpha), dtype = np.uint8)
return rgba[:, :, 0:3]
# fig 1)
fig1 = plt.figure(facecolor = "white")
fig1.set_dpi(300)
ax1 = fig1.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax1.add_artist(plt.Circle((0., 0., .5), color = "white"))
ax1.set_xlim(-5, 5)
ax1.set_ylim(-5, 5)
bitmap_rgba1 = get_rgba_bitmap(fig1)
black_white_to_black_transpa(bitmap_rgba1)
# fig 2
fig2 = plt.figure(facecolor = "white")
fig2.set_dpi(300)
delta = 0.025
ax2 = fig2.add_subplot(1, 1, 1, aspect = "equal", axisbg = "black")
ax2.set_xlim(-5, 5)
ax2.set_ylim(-5, 5)
x = y = np.arange(-3.0, 3.0, delta)
X, Y = np.meshgrid(x, y)
Z1 = mlab.bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
Z2 = mlab.bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
Z = Z2-Z1 # difference of Gaussians
im = ax2.imshow(Z, interpolation='bilinear', cmap=cm.jet,
origin='lower', extent=[-5, 5, -5, 5],
vmax=abs(Z).max(), vmin=-abs(Z).max())
bitmap_rgba2 = get_rgba_bitmap(fig2)
# now saving the composed figure
fig = plt.figure()
fig.patch.set_alpha(0.0)
ax = fig.add_axes([0., 0., 1., 1.])
ax.patch.set_alpha(0.0)
ax.imshow(over(bitmap_rgba1, bitmap_rgba2))
plt.axis('off')
fig.savefig("test_transpa.png", dpi=300)
plt.show()
,并提供:
我测试了你的初始光子测试用例,图片质量似乎没问题
现在,如果你想让数字背景透明:
fig1 = plt.figure(facecolor='white')
,因为白色在传递给black_white_to_black_transpa
fig2.patch.set_alpha(0.0)
,因为它将被存储而不会修改为bitmap_rgba2
bitmap_rgba1
函数内混合bitmap_rgba2
和over
时,请注意alpha通道(参见下面的可能修改)def over(rgba1, rgba2): if rgba1.shape != rgba2.shape: raise ValueError("rgba1 and rgba2 shall have same size") alpha1 = np.expand_dims(rgba1[:, :, 3] / 255., axis=3) alpha2 = np.expand_dims(rgba2[:, :, 3] / 255., axis=3) alpha = 1. - (1.-alpha1) * (1.-alpha2) C1 = rgba1[:, :, 0:3] C2 = rgba2[:, :, 0:3] C = (alpha1 * C1 + (1-alpha1) * alpha2 * C2) / alpha rgba = np.empty_like(rgba1, dtype = np.uint8) rgba[:, :, 0:3] = C rgba[:, :, 3] = 255 * alpha[:, :, 0] return rgba
最后(?)编辑:
似乎to_string_argb
返回的数组与imshow
预期的数组(rgb通道的顺序)之间存在不一致。一种可能的解决方案是将ax.imshow(over(bitmap_rgba1, bitmap_rgba2))
更改为:
over_tab = over(bitmap_rgba1, bitmap_rgba2)
over_tab[:, :, 0:3] = over_tab[:, :, ::-1][:, :, 1:4]
ax.imshow(over_tab)
答案 1 :(得分:1)
色彩映射可以有一个alpha通道,因此如果您的数据位于显示为圆形与非圆形的高值和低值的网格上,则这些值中的一组可以是透明的。
这仅适用于使用transparent
关键字以编程方式保存图形时;不是来自Python图像窗口。
从其中一个matplotlib画廊示例开始(在gimp中,我可以剪切和粘贴片段,透明度是正确的):
# plot transparent circles with a black background
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.colors import LinearSegmentedColormap
from matplotlib.cm import Greys
dark_low = ((0., 1., 1.),
(.3, 1., 0.),
(1., 0., 0.))
cdict = {'red': dark_low,
'green': dark_low,
'blue': dark_low}
cdict3 = {'red': dark_low,
'green': dark_low,
'blue': dark_low,
'alpha': ((0.0, 0.0, 0.0),
(0.3, 0.0, 1.0),
(1.0, 1.0, 1.0))
}
greys = LinearSegmentedColormap('Greys', cdict)
plt.register_cmap(cmap=greys)
dropout_high = LinearSegmentedColormap('Dropout', cdict3)
plt.register_cmap(cmap = dropout_high)
# Make some illustrative fake data:
x = np.arange(0, np.pi, 0.1)
y = np.arange(0, 2*np.pi, 0.1)
X, Y = np.meshgrid(x,y)
Z = np.cos(X) * np.sin(Y) * 10
# Make the figure:
plt.figure()
plt.subplot(1,3,1)
plt.imshow(Z, cmap=Greys)
plt.title('Smooth\ncolorbar')
plt.colorbar()
plt.subplot(1,3,2)
plt.imshow(Z, cmap=greys)
plt.title('Linear\ncolorbar')
plt.colorbar()
plt.subplot(1,3,3)
plt.imshow(Z, cmap = dropout_high)
plt.title('Alpha crops\n colorbar')
plt.colorbar()
plt.savefig('dropout_cmap', transparent=True)
作为另一个图像的图层。有趣的是,带alpha通道的颜色条没有透明度。这似乎是一个错误。
答案 2 :(得分:0)
这可能不是您正在寻找的答案,但它可以提供您想要的图片!我想你想要填充圆圈外的区域!(s)黑色并保持背景透明,而不是相反。计算单个圆的边界并使用fill_between
是微不足道的。为多个圈子做这件事可能会比较棘手!
import numpy as np
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1, aspect = "equal", )
# A Circle
xy=(1,1); r=3
# more points is smoother
xdata=np.linspace(-5,5,1001)
ydata=np.linspace(-5,5,1001)
# circle edges (top and bottom)
c1=np.sqrt((xy[0]**2-xdata**2)+r**2)+xy[1]
c2=-np.sqrt((xy[0]**2-xdata**2)+r**2)+xy[1]
c1=np.where(np.isnan(c1),xy[0],c1)
c2=np.where(np.isnan(c2),xy[0],c2)
ax.fill_between(xdata,5,c1,color='black')
ax.fill_between(xdata,-5,c2,color='black')
plt.xlim(-5, 5)
plt.ylim(-5, 5)
fig.savefig("test.png", dpi = 300, transparent=True)