Pyglet动画转视频:np.frombuffer尺寸不符致reshape失败
解决Pyglet帧捕获转视频时的reshape失败问题
问题根源
你遇到的核心问题是np.frombuffer的默认解析类型不对:
buffer是字节流,每个RGBA通道占1字节,总字节数应为width * height * 4- 但
np.frombuffer(buffer)默认会把字节解析成float64类型(每个元素占8字节),导致数组长度变成总字节数 / 8,和预期的像素通道数完全不匹配,reshape步骤直接报错。
另外你的代码还有两个隐藏问题:
writer初始化在on_draw之后,第一次调用writer.append_data时writer还未定义,会触发NameErrorimage_data.pitch(每行实际字节数)可能不等于width*4(GPU内存对齐要求),直接用窗口宽度reshape会导致画面变形
修正后的代码
import numpy as np import pyglet import imageio.v2 as iio # 初始化窗口 window = pyglet.window.Window(480, 480) label = pyglet.text.Label('Hello, world', font_name='Times New Roman', font_size=36, x=window.width//2, y=window.height//2, anchor_x='center', anchor_y='center') # 提前初始化视频写入器,必须放在on_draw之前 writer = iio.get_writer("out.mp4", fps=30) # 指定帧率,避免视频播放速度异常 @window.event def on_draw(): window.clear() label.draw() # 捕获帧 color_buffer = pyglet.image.get_buffer_manager().get_color_buffer() image_data = color_buffer.get_image_data() buffer = image_data.get_data("RGBA", image_data.pitch) # 关键:指定dtype=np.uint8,按1字节解析每个通道数据 frame = np.frombuffer(buffer, dtype=np.uint8) # 按pitch计算每行像素数,再裁剪到窗口实际宽度,解决内存对齐问题 frame = frame.reshape((image_data.height, image_data.pitch//4, 4))[:, :image_data.width, :] # 去掉Alpha通道(MP4大多不支持RGBA格式),转成RGB frame_rgb = frame[..., :3] # 写入视频帧 writer.append_data(frame_rgb) # 程序退出时关闭写入器,保证视频文件完整 def on_close(): writer.close() window.push_handlers(on_close) pyglet.app.run()
关键修改说明
- 指定dtype=np.uint8:让numpy按1字节解析每个通道,数组长度与实际像素通道数匹配
- 处理pitch对齐:用
image_data.pitch计算每行实际像素数,再裁剪到窗口宽度,避免画面变形 - 提前初始化writer:解决第一次调用
append_data时的未定义错误 - 添加关闭回调:程序退出时关闭写入器,防止视频文件损坏
- 转RGB格式:适配MP4等主流视频容器的格式要求
内容的提问来源于stack exchange,提问作者user16451053
相关产品推荐
相关产品推荐

