【问题标题】:Pygame, set transparency on an image imported using convert_alpha()Pygame,在使用 convert_alpha() 导入的图像上设置透明度
【发布时间】:2016-02-11 07:15:40
【问题描述】:

在我的 pygame 游戏中,要导入 jpeg 图像,我使用 convert() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert

然后,为了调整图像透明度(我们可以通过图像看到多少),我使用set_alpha() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.set_alpha

但是,要导入具有透明背景的 png 图像,我使用 convert_alpha() http://www.pygame.org/docs/ref/surface.html#pygame.Surface.convert_alpha

但是通过这种导入方式,我无法使用set_alpha() 来处理一般透明度。调整透明度的任何其他想法(我们通过图像看到多少)?

【问题讨论】:

    标签: python image pygame png transparency


    【解决方案1】:

    当您阅读 set_alpha 的文档时,您可以阅读以下内容: 如果 Surface 格式包含每个像素的 alpha,则此 alpha 值将被忽略。

    %在您的情况下,使用 png 图像,它是每像素 alpha。因此,您必须管理“每个像素”的 alpha。例如,您可以这样做(不是最好的代码,但易于理解。仅使用没有/是透明度的 png):

    def change_alpha(img,alpha=255):
      width,height=img.get_size()
      for x in range(0,width):
        for y in range(0,height):
          r,g,b,old_alpha=img.get_at((x,y))
          if old_alpha>0:
            img.set_at((x,y),(r,g,b,alpha))
    

    小心,它“慢”,因为您管理每个不为 0 的像素(从您的 png 透明)。 如果您的 png 具有多级透明度,则应使用更好的公式管理透明度,如下所示:

          r,g,b,old_alpha=img.get_at((x,y))
          img.set_at((x,y),(r,g,b,(alpha*old_alpha)/255))
    

    在这种情况下,永远不要修改原始图像,而是在副本上工作以永远不会丢失原始 alpha。

    希望对你有帮助

    ======================编辑=================== 添加一些优化,因为在评论中询问

    使用一些缓存方法:

    class image_with_alpha(object):
        def __init__(self,name=None):
            self.img=None
            self.alpha={}
            if name:
                self.load_image(name)
    
        def load_image(self,name):
            self.img=pygame.image.load(name)
            self.alpha[255]=self.img
            #self.pre_compute_alpha()
    
        def pre_compute_alpha(self):
            for alpha in range(0,10):
                self.alpha[alpha]=change_alpha(self.img,alpha)
    
        def get_img(self,a=255):
            try:
                return self.alpha[a]
            except:
                self.alpha[a]=change_alpha(self.img,a)
            return self.alpha[a]
    

    并像这样使用它: 加载图片:

        image=image_with_alpha("test.png")
    

    使用 60 表示 alpha:

        screen.blit(image.get_img(60),(0,0))
    

    现在,我希望它很快

    【讨论】:

    • 第一个公式出现黑框,但第二个运行良好 :),但是速度很慢,我的游戏降到 25 fps...
    • 有什么想法让它更优化吗?
    • 我不知道你的游戏是如何工作的,并且对此类代码的优化取决于它的使用方式。多少次alpha变化?图片有多大?如果没有低级编程,您可以对数据使用“缓存”:您将使用更多内存,但图像的预计算 alpha 将显示出很大的改进,而无需大量工作。
    • 其实我是用它来让我的游戏中的物体平滑幻影(物体是逐渐出现的),所以,当物体出现时,每帧都会调用这个函数
    • 所以你可以取消注释 self.pre_compute_alpha() 。没有简单的解决方案,因为您使用 python 和 pygame 以及多个 alpha。我看到了另外两种选择:使用掩码进行 blit,或使用 numpy 处理您的数据。也许,使用也支持透明度级别的 pygame 替代方案。祝你好运;)。
    【解决方案2】:

    最快的解决方案可能是使用numpy 数组操作,它应该足够快以避免需要缓存。逐像素计算 alpha 值的真正缓慢之处在于 Python 中的迭代,而 numpy 则在 C 中完成。

    首先将图像的 Alpha 通道引用到 numpy 数组中。这将在图像表面上创建一个锁;让我们记住这一点。然后取原始 alpha 的最小值(以像素为单位)和一个全为 1 的数组(这将使您得到一个只有 1 和 0 的数组),将其(以像素为单位)乘以所需的 alpha 并将结果复制回来到图像的 alpha 通道(仍然由该数组引用表示)。在将图像blit 到屏幕之前,必须清除对alpha 数组的数组引用,从而释放图像表面上的锁定。

    def change_alpha(img, alpha=255):
        chan = pygame.surfarray.pixels_alpha(img)
        chan2 = numpy.minimum(chan, numpy.ones(chan.shape, dtype=chan.dtype)) * alpha
        numpy.copyto(chan, chan2)
        del chan
    

    【讨论】:

      【解决方案3】:

      好的,我有答案。 Pygame 的“convert_alpha()”函数不支持每像素 alpha。根据文档设置 alpha 将无效。但是,您可以通过执行以下操作来绕过此限制。如果您使用“convert()”加载图像,然后设置 alpha,您可以使图像变得透明。然后你所要做的就是使用“set_colorkey(background color)”来消除背景图像。小心使用colorkey,因为图像中设置为colorkey的任何颜色都会变得透明。 colorkey 不关心每个像素的 alpha,因此您可以更改图像的 alpha 并同时使用 colorkey。

      这里是代码...

      #Loading Image
      image = pygame.image.load("test.png").convert()
      
      #Setting Alpha
      image.set_alpha(some desired alpha)
      
      #Set colorkey To Eliminate Background Color
      image.set_colorkey(some background color)
      

      我把这张测试图放在一起测试代码。图像的边缘确实具有透明度。

      This is what it looks like blitted onto a green background without the added alpha. The white part was transparent until loaded with ".convert()"

      This is the finished look of the image with the whole code applied. The alpha has been stripped and reset, and the colorkey has been set to white because it was the background

      我希望这是您正在寻找的内容,并希望我的回答对您有所帮助。

      注意* 您可能希望在像这样更改其 alpha 之前制作图像的副本,而不会有图像因以前的使用而产生“溢出”影响的风险。

      【讨论】:

        【解决方案4】:

        使用 set_colorkey(color) 设置透明颜色。例如,如果你有一个苹果的图像,除了苹果之外的所有东西都是黑色的,你会使用 apple.set_colorkey(black),除了苹果之外的所有东西都是透明的。另外,如果您在使用 jpg 图像时遇到问题,我建议将其更改为 png,然后执行 .convert()。

        【讨论】:

        • 你还没有理解我的问题。我已经在使用 png 文件。 convert() 在我的 png 上做黑框,所以我改用 convert_alpha。关键问题是我也想配置一般透明度(我们在整个图像中看到多少)。通常,我使用set_alpha() 来实现这个目标。但是,当您像我一样使用convert_alpha() 导入图像时,set_alpha() 不起作用。我正在搜索set_alpha() 替代方案
        猜你喜欢
        • 2021-09-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-09-05
        • 1970-01-01
        • 2013-07-14
        • 1970-01-01
        • 2017-03-21
        相关资源
        最近更新 更多