Pygame,在使用 convert_alpha() 导入的图像上设置透明度

Pygame, set transparency on an image imported using convert_alpha()

在我的 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() 来玩一般透明度。任何其他调整透明度的想法(我们从图像中看到多少)?

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

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

%在您的例子中,对于 png 图像,它是每像素 alpha。因此,您必须管理 alpha "per pixel"。例如,您可以这样做(不是最好的代码,但很容易理解。使用仅具有 no/yes 透明度的 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))

小心,它是 "slow",因为您管理每个不为 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")

Alpha 为 60 的 Blit:

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

现在,我希望它很快

好的,我有答案给你。 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 之前制作图像的副本,而不会有图像受到以前使用的 "spillover" 影响的风险。

最快的解决方案可能是使用 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