簡體   English   中英

如何加載動畫 GIF 並獲取 Pygame 中的所有單個幀?

[英]How can I load an animated GIF and get all of the individual frames in Pygame?

首先,對不起,如果這是重復的。 我找到的答案似乎無關緊要,但也許我正在使用錯誤的關鍵字進行搜索。 我想做的是獲取動畫 GIF 並將其拆分為幀列表。 基本上,是這樣的:

frames = []
for frame in split_animated_gif("some_animated_gif.gif"):
    frames.append(frame)

其中 split_animated_gif 返回一個按順序排列的表面列表,每個表面都是 GIF 的一個幀。 感謝您的幫助。

編輯:經過更多的窺探,我找到了一段代碼,它成功地為我在 pygame 中顯示了動畫 GIF。 它可以在https://github.com/piantado/kelpy/blob/master/kelpy/GIFImage.py找到。 不過,非常感謝您的幫助。

Pygame 本身不支持 gif 動畫,這在文檔中有所說明。 所以你必須

1) 在加載精靈或圖像時,使用其他一些代碼/庫來分割 gif。 那些你可以通過谷歌搜索“python split gif”或其他東西找到的。 例如Python:將 GIF 幀轉換為 PNG

2) 如果您自己創建了 gif,只需逐幀再次導出您的精靈

無論哪種方式,您都必須手動完成動畫部分。 您可以通過谷歌搜索“pygame 動畫”找到大量教程。 例如來自少數圖像的動畫精靈

這段代碼使用 PIL/枕頭庫來完成。

from PIL import Image

def split_animated_gif(gif_file_path):
    ret = []
    gif = Image.open(gif_file_path)
    for frame_index in range(gif.n_frames):
        gif.seek(frame_index)
        frame_rgba = gif.convert("RGBA")
        pygame_image = pygame.image.fromstring(
            frame_rgba.tobytes(), frame_rgba.size, frame_rgba.mode
        )
        ret.append(pygame_image)
    return ret

PyGame分別是pygame.image模塊只能處理非動畫GIF
但是在PyGame主頁上引入了GIFImage庫:

這個庫為 pygame 添加了 GIF 動畫播放。


另一種選擇是使用庫將 GIF 逐幀加載到列表中。

例如使用Pillow庫( pip install Pillow )。

編寫一個函數,可以將 PIL 圖像轉換為pygame.Surface並使用 PIL 庫逐幀加載 GIF:
(另請參閱使用 PillowPIL 以及 pygame.image 提取動畫 GIF 的幀

from PIL import Image, ImageSequence
def pilImageToSurface(pilImage):
    mode, size, data = pilImage.mode, pilImage.size, pilImage.tobytes()
    return pygame.image.fromstring(data, size, mode).convert_alpha()

def loadGIF(filename):
    pilImage = Image.open(filename)
    frames = []
    if pilImage.format == 'GIF' and pilImage.is_animated:
        for frame in ImageSequence.Iterator(pilImage):
            pygameImage = pilImageToSurface(frame.convert('RGBA'))
            frames.append(pygameImage)
    else:
        frames.append(pilImageToSurface(pilImage))
    return frames

或者使用OpenCV / opencv-python庫和VideoCapture

寫的功能,能夠在轉換CV2 pygame.image圖像向pygame.Surface一個第二使用該庫由幀加載一個GIF幀:
(另請參閱在 Python 中讀取 GIF 文件如何將 OpenCV (cv2) 圖像(BGR 和 BGRA)轉換為 pygame.Surface 對象

import cv2
def cv2ImageToSurface(cv2Image):
    size = cv2Image.shape[1::-1]
    format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
    cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

def loadGIF(filename):
    gif = cv2.VideoCapture(filename)
    frames = []
    while True:
        ret, cv2Image = gif.read()
        if not ret:
            break
        pygameImage = cv2ImageToSurface(cv2Image)
        frames.append(pygameImage)
    return frames

另請參閱加載動畫 GIF和一個簡單的動畫 gif 查看器示例:

import pygame
import cv2

def cv2ImageToSurface(cv2Image):
    size = cv2Image.shape[1::-1]
    format = 'RGBA' if cv2Image.shape[2] == 4 else 'RGB'
    cv2Image[:, :, [0, 2]] = cv2Image[:, :, [2, 0]]
    surface = pygame.image.frombuffer(cv2Image.flatten(), size, format)
    return surface.convert_alpha() if format == 'RGBA' else surface.convert()

def loadGIF(filename):
    gif = cv2.VideoCapture(filename)
    frames = []
    while True:
        ret, cv2Image = gif.read()
        if not ret:
            break
        pygameImage = cv2ImageToSurface(cv2Image)
        frames.append(pygameImage)
    return frames

pygame.init()
window = pygame.display.set_mode((500, 500))
clock = pygame.time.Clock()

gifFrameList = loadGIF(r"rubber_ball.gif")
currentFrame = 0

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

    window.fill(0)

    rect = gifFrameList[currentFrame].get_rect(center = (250, 250))
    window.blit(gifFrameList[currentFrame], rect)
    currentFrame = (currentFrame + 1) % len(gifFrameList)

    pygame.display.flip()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM