python - 将 pygame 转换为 cv2 到 pygame 时,Surface alpha 丢失
问题描述
我正在制作一个绽放系统作为pygame中的一个项目。bloom 的代码有效,但是它是如何从pygame.Surface转换为np.array的,它失去了它的 alpha 层。
这是代码:
def Bloom(canvas: pygame.Surface):
size = canvas.get_size()
canvas_zero = canvas
canvas = pygame.surfarray.array3d(canvas)
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
newCanvas.set_colorkey((0,0,0))
cv2.GaussianBlur(canvas, ksize=(9, 9), sigmaX=10, sigmaY=10, dst=canvas)
cv2.blur(canvas, ksize=(9, 9), dst=canvas)
newCanvas.blit(pygame.surfarray.make_surface(canvas), (0,0))
newCanvas.blit(canvas_zero, (0,0))
return newCanvas
这就是系统的外观
如您所见,粒子上有这个黑色轮廓,由 set_colorkey 创建。
我想要的是从白色到完全透明的渐变,我得到的是从白色到黑色的渐变。
我该如何解决这个问题?
(我尝试过 PIL 而不是 cv2,但速度太慢(15 fps))
解决方案
pygame.surfarray.array3d()
只返回表面的 RGB 通道。
您必须连接 RGB 颜色通道和 Alpha 通道。Alpha 通道可以通过以下方式获得pygame.surfarray.array_alpha()
:
canvas_rgb = pygame.surfarray.array3d(canvas)
canvas_alpha = pygame.surfarray.array_alpha(canvas).reshape((*canvas_rgb.shape[0:2], 1))
canvas_rgba = numpy.concatenate((canvas_rgb, canvas_alpha), 2)
通过获取颜色值pygame.surfarray.array2d()
并使用以下命令创建数组的新视图,可能可以获得更好的性能numpy.ndarray.view
:
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=numpy.uint8).reshape((*canvas_rgb.shape[0:2], 4))
Bloom
功能选项1:
def Bloom(canvas: pygame.Surface):
size = canvas.get_size()
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
newCanvas.set_colorkey((0,0,0))
canvas_rgb = pygame.surfarray.array3d(canvas)
canvas_alpha = pygame.surfarray.array_alpha(canvas).reshape((*canvas_rgb.shape[0:2], 1))
canvas_rgba = numpy.concatenate((canvas_rgb, canvas_alpha), 2)
cv2.GaussianBlur(canvas_rgba, ksize=(9, 9), sigmaX=10, sigmaY=10, dst=canvas_rgba)
cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)
newCanvas.blit(pygame.image.frombuffer(canvas_rgba.transpose((1, 0, 2)).copy(order='C'), size, 'RGBA'), (0,0))
newCanvas.blit(canvas, (0,0))
return newCanvas
Bloom
功能选项2:
def Bloom(canvas: pygame.Surface):
size = canvas.get_size()
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
newCanvas.set_colorkey((0,0,0))
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=numpy.uint8).reshape((*canvas_color.shape, 4))
cv2.GaussianBlur(canvas_rgba, ksize=(9, 9), sigmaX=10, sigmaY=10, dst=canvas_rgba)
cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)
pygame.surfarray.blit_array(newCanvas, canvas_color)
newCanvas.blit(canvas, (0,0))
return newCanvas
最小的例子:
import pygame, cv2, numpy
def Bloom1(canvas: pygame.Surface):
size = canvas.get_size()
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
newCanvas.set_colorkey((0,0,0))
canvas_rgb = pygame.surfarray.array3d(canvas)
canvas_alpha = pygame.surfarray.array_alpha(canvas).reshape((*canvas_rgb.shape[0:2], 1))
canvas_rgba = numpy.concatenate((canvas_rgb, canvas_alpha), 2)
cv2.GaussianBlur(canvas_rgba, ksize=(9, 9), sigmaX=10, sigmaY=10, dst=canvas_rgba)
cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)
newCanvas.blit(pygame.image.frombuffer(canvas_rgba.transpose((1, 0, 2)).copy(order='C'), size, 'RGBA'), (0,0))
return newCanvas
def Bloom2(canvas: pygame.Surface):
size = canvas.get_size()
newCanvas = pygame.Surface(size, pygame.SRCALPHA)
newCanvas.set_colorkey((0,0,0))
canvas_color = pygame.surfarray.array2d(canvas)
canvas_rgba = canvas_color.view(dtype=numpy.uint8).reshape((*canvas_color.shape, 4))
cv2.GaussianBlur(canvas_rgba, ksize=(9, 9), sigmaX=10, sigmaY=10, dst=canvas_rgba)
cv2.blur(canvas_rgba, ksize=(9, 9), dst=canvas_rgba)
pygame.surfarray.blit_array(newCanvas, canvas_color)
return newCanvas
pygame.init()
window = pygame.display.set_mode((550, 300))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 90)
text = font.render("Bloom", True, 0)
surface = pygame.Surface((250, 250))
surface.fill(0)
pygame.draw.circle(surface, (255, 255, 255), surface.get_rect().center, 100)
surface.blit(text, text.get_rect(center = surface.get_rect().center))
surface.set_colorkey(0)
surface = surface.convert_alpha()
surface1 = Bloom1(surface)
surface2 = Bloom1(surface)
run = True
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.fill((64, 64, 64))
window.blit(surface1, surface1.get_rect(center = (150, 150)), special_flags = pygame.BLEND_PREMULTIPLIED)
window.blit(surface2, surface2.get_rect(center = (400, 150)), special_flags = pygame.BLEND_PREMULTIPLIED)
pygame.display.flip()
clock.tick(60)
pygame.quit()
exit()
推荐阅读
- keycloak - “会话没有必需的客户端”是什么意思?
- python - 加深对 Python 3 函数调用和变量的理解
- c# - 从数据库中检索 Entity Framework Core 列表中每个 id 的最后一个结果
- spring-boot - 无法找到请求目标的有效证书路径 - Keycloak - Springboot - 自签名证书 - 测试
- flutter - 当用户在颤动中向下滚动 tab1 时,如何防止在 tab2 上自动向下滚动?
- android - IONIC 3:启用设备飞行模式后如何获取地理位置坐标?
- python - 使用 Linux 执行时未出现 Xlsxwriter 标头格式
- google-cloud-platform - Google Cloud 内部 Https 负载均衡器
- python - 如何定义将返回已编辑的全局变量的方法
- c# - 使用 TikaOnDotNet 从巨大文件中提取数据