【问题标题】:Add transparent picture over plot在绘图上添加透明图片
【发布时间】:2019-01-19 09:33:15
【问题描述】:

下面的 Python 脚本在使用 Basemap 模块生成的地图上添加了一张图片(在这个简单示例中生成了一个矩形)和 GPS 轨迹。
现在我想让两个轨道都成为透明的矩形。通过alpha kwarg 的轨道没问题,但我不知道如何为图片做。

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from mpl_toolkits.basemap import Basemap

lats = [ 45, 15  ]
lons = [ 0 , 100 ]

fig = plt.figure( dpi = 300 )
ax  = plt.subplot(111)

myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
myBaseMap.bluemarble()

planeImg = Image.new('RGB', (600, 300), color = 'red')
planeXY  = myBaseMap( lons[-1], lats[-1] )
x,y      = myBaseMap( lons, lats )

plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )

imagebox = OffsetImage( planeImg , zoom=.4 )

ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
ax.add_artist(ab)
plt.show()

此代码生成下面带有透明线的图片。 现在我想让红色矩形以同样的方式透明。

我尝试在注释框和斧头上使用set_alpha 方法,但没有成功。
有任何想法吗 ?

谢谢。

【问题讨论】:

  • imshow 中的extent 选项似乎可以解决问题,请参阅stackoverflow.com/a/34459284/8069403stackoverflow.com/q/15160123/8069403。是你要找的吗?
  • 感谢您的回答,但这不是我想要的。我编辑了这篇文章,希望现在更清楚。如果我没记错extent 工作是设置图像大小,但我在这里的尺寸没有问题。我的问题是我在情节前景上添加了一张图片:如何使这张图片透明?请注意,我以前使用 imshow,但现在我更喜欢 ImageAnnotationBbox,因为我发现它们更灵活。
  • Here 是 matplotlib 注释框的演示。如果我理解您希望注释框中的图像透明?如果示例代码可运行,将会很有帮助
  • 是的,你理解正确,这就是我想要的!感谢演示,我首先使用它来处理注释框,但没有发现任何透明度。在我之前的帖子编辑之后,代码应该可以运行了,因为它只依赖于 python 库。也许你想让我停止使用底图?如果你愿意,我肯定可以用任何 2D 绘图替换它,问题是一样的:使注释框图片透明,这样我们就可以看到透明度后面的绘图。

标签: python image matplotlib matplotlib-basemap


【解决方案1】:

如果您在创建OffsetImage 之前为您的图像设置了一个alpha 值,则结果看起来符合预期。 this answer 中解释了如何设置枕头图像的 alpha 值。注意 alpha 值必须在 0 和 255 之间,而不是 0 和 1。简而言之,您只需在代码中添加一行(注意我更改了图像分辨率):

import matplotlib.pyplot as plt
from PIL import Image
from matplotlib.offsetbox import AnnotationBbox, OffsetImage
from mpl_toolkits.basemap import Basemap

lats = [ 45, 15  ]
lons = [ 0 , 100 ]

fig = plt.figure( dpi = 100 )
ax  = plt.subplot(111)

myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
myBaseMap.bluemarble()

planeImg = Image.new('RGB', (600, 300), color = 'red')
planeImg.putalpha(128)

planeXY  = myBaseMap( lons[-1], lats[-1] )
x,y      = myBaseMap( lons, lats )

plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )

imagebox = OffsetImage( planeImg , zoom=.4 )

ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
ax.add_artist(ab)
plt.show()

得到如下图片:

【讨论】:

    【解决方案2】:

    Thomas Kühn 回答:如果我将他的代码用于我的真实图片(这个带有透明区域的 png 红色平面) 而不是红色矩形:我得到下面的图片。

    正如您所见,png 透明区域被解释为黑色,因此我在地图上没有只有飞机,而是在它周围有一个透明的黑色方块。 在 Thomas 的链接的帮助下,我找到了摆脱这种情况的方法,请参见下面的代码(不要忘记在运行之前更改图片路径)。

    import matplotlib.pyplot as plt
    from PIL import Image
    from matplotlib.offsetbox import AnnotationBbox, OffsetImage
    from mpl_toolkits.basemap import Basemap
    
    lats = [ 45, 15  ]
    lons = [ 0 , 100 ]
    
    fig = plt.figure( dpi = 100 )
    ax  = plt.subplot(111)
    
    myBaseMap = Basemap( projection='ortho', lat_0=lats[-1], lon_0=lons[-1] )
    myBaseMap.bluemarble()
    
    # /!\ /!\ /!\ CHOOSE A PNG OF YOUR OWN TO RUN THE SCRIPT /!\ /!\ /!\
    imgPath  = './avion.png'
    planeImg = Image.open( imgPath )
    data     = planeImg.getdata()
    newData  = []
    myAlpha  = 150
    # loop through pixels in planeImg
    for item in data:
        # item[3] is the current pixel alpha value. When 0: transparent area on png, leave it at 0
        # item[{0, 1, 2}] is pixel {R,G,B} value
        if item[3] == 0:
            newData.append( (item[0], item[1], item[2], 0) )
        # else the current pixel is a part of the plane: set alpha to desired value
        else:
            newData.append( (item[0], item[1], item[2], myAlpha) )
    planeImg.putdata( newData )
    
    planeXY  = myBaseMap( lons[-1], lats[-1] )
    x,y      = myBaseMap( lons, lats )
    
    plt.plot( x, y, color='r', alpha=0.5, linewidth=3  )
    
    imagebox = OffsetImage( planeImg , zoom=.4 )
    
    ab = AnnotationBbox( imagebox, myBaseMap( lons[-1], lats[-1] ), xybox=( 0., 0. ), xycoords='data', boxcoords='offset points', frameon=False )
    ax.add_artist(ab)
    plt.show()
    

    这段代码生成了下面的图片,这正是我想要的。 谢谢托马斯·库恩。

    【讨论】:

    • 我的假设是您的图片根本没有 alpha 通道,因此添加了。如果像在您的图片中一样,已经存在 alpha 通道并且您希望使可见部分更加透明,我认为 alpha 通道与分数的简单乘法可以完成您对数据的 for 循环的工作。无论如何,很好的解决方案:)
    • 这仍然不适合我,我正在尝试在线条图或区域图上绘制图像,并将 alpha 设置为 150 似乎可以使图像变亮,但实际上不允许下面要显示的内容。
    猜你喜欢
    • 2010-11-25
    • 1970-01-01
    • 2023-03-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-11-16
    • 1970-01-01
    • 2014-06-06
    相关资源
    最近更新 更多