【问题标题】:Pygame and Numpy AnimationsPygame 和 Numpy 动画
【发布时间】:2019-01-29 06:38:15
【问题描述】:

假设我有一个数据类型为np.uint8 的Numpy 数组myAnimation 表示形状为(y,x,4,k) 的动画(多帧静止的8 位RGBA 图像),其中y 是高度,x 是宽度, 4 是通道数(红、绿、蓝、alpha),k 是动画中的帧数。

假设我想在 PyGame 中以指定的帧速率(例如,每秒 15 帧)播放这个 NumPy 数组的帧,并有动画循环。

这可能与 Pygame 相关吗?

如果是这样,您将如何实现它?你能举个例子吗?

我在网上找到的所有内容都涉及从磁盘读取文件,但重要的是我能够使用内存中已经存在的值,因为它们会在程序运行时频繁更改。

【问题讨论】:

标签: python python-3.x numpy animation pygame


【解决方案1】:

[...] shape (y,x,4,k) 其中y 是高度,x 是宽度,4 是通道数(红色、绿色、蓝色、alpha),k 是帧数 [...]

是的,只需一行代码即可。以下行将 (y, x, 4, k) numpy 数组 (data) 转换为 pygme.Surface 对象列表 (surf_list):

surf_list = [pygame.image.frombuffer(d[:,:,[2, 1, 0, 3]].flatten(), (data.shape[1::-1]), 'RGBA') for d in data.transpose(3, 0, 1, 2)]

分别

surf_list = []
for d in data.transpose(3, 0, 1, 2):
    bytes = d[:,:,[2, 1, 0, 3]].flatten()
    size = data.shape[1::-1]
    format = 'RGBA'
    surface = pygame.image.frombuffer(bytes, size, format)
    surf_list.append(surface)

解释:

使用numpy.traspose 将第 3 个(框架)轴移动轴 2 带到前面(请参阅Iterating over arbitrary dimension of numpy.array)并遍历框架:

for d in data.transpose(3, 0, 1, 2):

通过pygame.image.frombuffer()从每一帧创建一个pygame.Surface

surface = pygame.image.frombuffer(bytes, size, format)

pygame.image.frombuffer() 有 3 个参数,bytessizeformatbytes 是像素数据的一维字节数组。 numpy.ndarray.flatten 返回折叠成一维数组的副本。颜色通道的顺序很可能是 BGRA 而不是 RGBA。因此,您必须交换红色和蓝色通道 (d[:,:,[2, 1, 0, 3]])。如果颜色通道的顺序是 RGBA,则可以跳过此步骤:

bytes = d[:,:,[2, 1, 0, 3]].flatten() # for BGRA
bytes = d.flatten() # for RGBA

size 是一个包含 2 个元素(xy)的元组,并指定图像的大小。尺寸可以从numpy.ndarray.shape:

size = data.shape[1::-1]

size = (data.shape[1], data.shape[0])

格式指定图片格式,必须为'RGBA''BGRA'不存在):

format = 'RGBA'

查看最小示例,它创建一个 (y, x, 4, k) numpy 数组 (data ) 并将其转换为 pygme.Surface 对象列表 (surf_list) :

import pygame
import numpy as np
pygame.init()
window = pygame.display.set_mode((400, 400))
clock = pygame.time.Clock()

radius = 100
frames = 20
data = np.zeros(shape = (radius*2, radius*2, 4, frames), dtype = "uint8")
for x in range(data.shape[0]): 
    for y in range(data.shape[1]):
        px, py = x - data.shape[0]/2, y - data.shape[1]/2
        for i in range(frames):
            maxY2 = (radius*radius - px*px) * pow(abs(i-frames/2) / frames, 2)
            if px*px + py* py < radius*radius:
                if py * py < maxY2:
                    data[y, x, (0, 3), i] = 255, 255
                    if (px*px + py*py)*4 > radius*radius:
                        data[y, x, (1, 2), i] = 255, 255
                else:
                    data[y, x, (2, 3), i] = 255, 255 
                   
surf_list = [pygame.image.frombuffer(d[:,:,[2, 1, 0, 3]].flatten(), (data.shape[1::-1]), 'RGBA') for d in data.transpose(3, 0, 1, 2)]

count = 0
run = False
while not run:
    clock.tick(20)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = True

    window.fill(0)
    window.blit(surf_list[count], surf_list[0].get_rect(center = window.get_rect().center))
    pygame.display.flip()
    count = (count + 1) %  len(surf_list)

pygame.quit()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 2017-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-19
    相关资源
    最近更新 更多