Pygame 幻灯片延迟通常很长
Pygame slideshow delay anormally long
我正在设置一个混合图像和视频的幻灯片系统,来自一个目录。
我正在使用 Raspberry Pi B、pygame 和 vlc。
我没有安装 X,所以一切都发生在帧缓冲区中。
我的实际代码可以正常工作,但是:
- 不遵守 4 秒延迟。图像显示 +- 11 秒。
- 其中一张图片 没有什么特别之处,显示时间更长,+- 1m30。 (我真正的问题)
我用 fbi、fim、vlc 尝试了 bash 脚本,但没有得到合适的结果。最接近的是 vlc,但在帧缓冲区中渲染图像需要很长时间。
我对 pygame 很陌生。这是代码:
import pygame
import sys
import time
import vlc
import os
filesdir = '/home/pi/SMBmount/'
pygame.init()
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
black = 0, 0, 0
screen = pygame.display.set_mode(size)
while True:
# For every file in filesdir :
for filename in os.listdir(filesdir):
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
fullname = filesdir + filename
img = pygame.image.load(fullname)
img = pygame.transform.scale(img, size)
imgrect = img.get_rect()
screen.fill(black)
screen.blit(img, imgrect)
pygame.mouse.set_visible(False)
pygame.display.flip()
time.sleep(4)
# Elif video:
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
fullname = filesdir + filename
# Create instane of VLC and create reference to movie.
vlcInstance = vlc.Instance("--aout=adummy")
media = vlcInstance.media_new(fullname)
# Create new instance of vlc player
player = vlcInstance.media_player_new()
# Load movie into vlc player instance
player.set_media(media)
# Start movie playback
player.play()
# Do not continue if video not finished
while player.get_state() != vlc.State.Ended:
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
player.stop()
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
我愿意接受任何能够处理图片和视频的替代方案。
编辑:终于到了 pygame 用 pygame.transform.scale()
调整(下一个)图像大小的时间了。
有什么办法可以优化吗?例如,打印全屏而不调整大图像的大小?
我无法在没有图像和视频的情况下重现该行为,但这里有一些建议应该有助于在显示图像时加快代码速度。
不要使用time.sleep()
。它会在给定的时间内冻结游戏,所以所有的计算都在这个时间之外完成 window,消耗更多的时间。最好使用 pygame time Clock。来自其 tick()
方法的文档:
If you pass the optional framerate argument the function will delay to keep the game running slower than the given ticks per second. This can be used to help limit the runtime speed of a game. By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second.
tick()
方法应该在主循环中每次迭代调用一次,所以最好不要将它放在 if
语句中。
此处:
screen.fill(black)
screen.blit(img, imgrect)
第一行 screen.fill(black)
完全没用:您在第二行中重绘了覆盖所有黑色背景的整个表面,因为图像已重新调整为屏幕大小。您可以安全地 blit
图片而无需用黑色填充背景。
这样会节省时间,因为每次使用blit
或fill
时,后台pygame
都会对Surface做大量的操作来改变像素点的颜色(像素点变的越多,所需时间越长)。
当然,如果您加载的任何图像有 alpha 通道。如果你有带 alpha 通道的图片,你需要先把背景涂黑。为了节省时间,我建议使用其他程序从图像中删除 alpha 通道。
pygame.transform.scale()
需要时间,特别是如果你有非常大的图片。尝试使用另一个程序重新缩放您的图像并加载 pygame 尺寸的图像,使其尽可能接近您的屏幕。
加载图片时,添加.convert()
。这将使 blitting 更快。应该是:img = pygame.image.load(fullname).convert()
.
最后,您的代码应如下所示:
imgexts = ['png', 'jpg', 'jpeg']
videxts = ['mp4', 'mkv']
#filtering out non video and non image files in the directory using regex
#remember to import re module
showlist = [filename for filename in os.listdir(filesdir) if re.search('[' + '|'.join(imgexts + videxts) + ']$', filename.lower())]
clock = pygame.time.Clock()
while True:
# For every file in filesdir :
for filename in showlist:
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
#all your stuff but NOT the time.sleep()
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
#unchanged here
clock.tick(0.25) #framerate = 0.25 means 1 frame each 4 seconds
for event in pygame.event.get():
#unchanged here
在 Valentino 的帮助下,我找出了问题所在。
他帮我优化了代码,提高了每张图片的加载时间,解决了第一个问题。
.
此外,我添加了一段代码:
# If image is not same dimensions
if imgrect.size != size:
img = Image.open(fullname)
img = img.resize(size, Image.ANTIALIAS)
img.save(fullname, optimize=True, quality=95)
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
如果图片不是屏幕分辨率,我使用 Pillow (PIL) 调整大小并将调色板缩小到 8 位(256 色)。
它显着减小了文件大小(尤其是大文件)并允许 pygame 更快地加载图像。
它修复了第二个问题。
对于那些感兴趣的人,完整的代码是:
import pygame
import sys
import vlc
import os
import re
from PIL import Image
filesdir = '/home/pi/SMBmount/'
imgexts = ['png', 'jpg', 'jpeg']
videxts = ['mp4', 'mkv', 'avi']
time = 5 # Time to display every img
#filtering out non video and non image files in the directory using regex
showlist = [filename for filename in os.listdir(filesdir) if re.search('[' + '|'.join(imgexts + videxts) + ']$', filename.lower())]
pygame.init()
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
while True:
# For every file in filesdir :
for filename in showlist:
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
fullname = filesdir + filename
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
# If image is not same dimensions
if imgrect.size != size:
img = Image.open(fullname)
img = img.resize(size, Image.ANTIALIAS)
img.save(fullname, optimize=True, quality=95)
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
screen.blit(img, imgrect)
pygame.mouse.set_visible(False)
pygame.display.flip()
# Elif video:
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
fullname = filesdir + filename
# Create instane of VLC and create reference to movie.
vlcInstance = vlc.Instance("--aout=adummy")
media = vlcInstance.media_new(fullname)
# Create new instance of vlc player
player = vlcInstance.media_player_new()
# Load movie into vlc player instance
player.set_media(media)
# Start movie playback
player.play()
# Do not continue if video not finished
while player.get_state() != vlc.State.Ended:
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
player.stop()
clock.tick(1 / time) # framerate = 0.25 means 1 frame each 4 seconds
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
我正在设置一个混合图像和视频的幻灯片系统,来自一个目录。 我正在使用 Raspberry Pi B、pygame 和 vlc。 我没有安装 X,所以一切都发生在帧缓冲区中。
我的实际代码可以正常工作,但是:
- 不遵守 4 秒延迟。图像显示 +- 11 秒。
- 其中一张图片 没有什么特别之处,显示时间更长,+- 1m30。 (我真正的问题)
我用 fbi、fim、vlc 尝试了 bash 脚本,但没有得到合适的结果。最接近的是 vlc,但在帧缓冲区中渲染图像需要很长时间。
我对 pygame 很陌生。这是代码:
import pygame
import sys
import time
import vlc
import os
filesdir = '/home/pi/SMBmount/'
pygame.init()
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
black = 0, 0, 0
screen = pygame.display.set_mode(size)
while True:
# For every file in filesdir :
for filename in os.listdir(filesdir):
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
fullname = filesdir + filename
img = pygame.image.load(fullname)
img = pygame.transform.scale(img, size)
imgrect = img.get_rect()
screen.fill(black)
screen.blit(img, imgrect)
pygame.mouse.set_visible(False)
pygame.display.flip()
time.sleep(4)
# Elif video:
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
fullname = filesdir + filename
# Create instane of VLC and create reference to movie.
vlcInstance = vlc.Instance("--aout=adummy")
media = vlcInstance.media_new(fullname)
# Create new instance of vlc player
player = vlcInstance.media_player_new()
# Load movie into vlc player instance
player.set_media(media)
# Start movie playback
player.play()
# Do not continue if video not finished
while player.get_state() != vlc.State.Ended:
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
player.stop()
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
我愿意接受任何能够处理图片和视频的替代方案。
编辑:终于到了 pygame 用 pygame.transform.scale()
调整(下一个)图像大小的时间了。
有什么办法可以优化吗?例如,打印全屏而不调整大图像的大小?
我无法在没有图像和视频的情况下重现该行为,但这里有一些建议应该有助于在显示图像时加快代码速度。
不要使用
time.sleep()
。它会在给定的时间内冻结游戏,所以所有的计算都在这个时间之外完成 window,消耗更多的时间。最好使用 pygame time Clock。来自其tick()
方法的文档:If you pass the optional framerate argument the function will delay to keep the game running slower than the given ticks per second. This can be used to help limit the runtime speed of a game. By calling Clock.tick(40) once per frame, the program will never run at more than 40 frames per second.
tick()
方法应该在主循环中每次迭代调用一次,所以最好不要将它放在if
语句中。此处:
screen.fill(black) screen.blit(img, imgrect)
第一行
screen.fill(black)
完全没用:您在第二行中重绘了覆盖所有黑色背景的整个表面,因为图像已重新调整为屏幕大小。您可以安全地blit
图片而无需用黑色填充背景。
这样会节省时间,因为每次使用blit
或fill
时,后台pygame
都会对Surface做大量的操作来改变像素点的颜色(像素点变的越多,所需时间越长)。当然,如果您加载的任何图像有 alpha 通道。如果你有带 alpha 通道的图片,你需要先把背景涂黑。为了节省时间,我建议使用其他程序从图像中删除 alpha 通道。
pygame.transform.scale()
需要时间,特别是如果你有非常大的图片。尝试使用另一个程序重新缩放您的图像并加载 pygame 尺寸的图像,使其尽可能接近您的屏幕。加载图片时,添加
.convert()
。这将使 blitting 更快。应该是:img = pygame.image.load(fullname).convert()
.
最后,您的代码应如下所示:
imgexts = ['png', 'jpg', 'jpeg']
videxts = ['mp4', 'mkv']
#filtering out non video and non image files in the directory using regex
#remember to import re module
showlist = [filename for filename in os.listdir(filesdir) if re.search('[' + '|'.join(imgexts + videxts) + ']$', filename.lower())]
clock = pygame.time.Clock()
while True:
# For every file in filesdir :
for filename in showlist:
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
#all your stuff but NOT the time.sleep()
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
#unchanged here
clock.tick(0.25) #framerate = 0.25 means 1 frame each 4 seconds
for event in pygame.event.get():
#unchanged here
在 Valentino 的帮助下,我找出了问题所在。 他帮我优化了代码,提高了每张图片的加载时间,解决了第一个问题。
此外,我添加了一段代码:
# If image is not same dimensions
if imgrect.size != size:
img = Image.open(fullname)
img = img.resize(size, Image.ANTIALIAS)
img.save(fullname, optimize=True, quality=95)
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
如果图片不是屏幕分辨率,我使用 Pillow (PIL) 调整大小并将调色板缩小到 8 位(256 色)。 它显着减小了文件大小(尤其是大文件)并允许 pygame 更快地加载图像。 它修复了第二个问题。
对于那些感兴趣的人,完整的代码是:
import pygame
import sys
import vlc
import os
import re
from PIL import Image
filesdir = '/home/pi/SMBmount/'
imgexts = ['png', 'jpg', 'jpeg']
videxts = ['mp4', 'mkv', 'avi']
time = 5 # Time to display every img
#filtering out non video and non image files in the directory using regex
showlist = [filename for filename in os.listdir(filesdir) if re.search('[' + '|'.join(imgexts + videxts) + ']$', filename.lower())]
pygame.init()
size = (pygame.display.Info().current_w, pygame.display.Info().current_h)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
while True:
# For every file in filesdir :
for filename in showlist:
filenamelower = filename.lower()
# If image:
if filenamelower.endswith('.png') or filenamelower.endswith('.jpg') or filenamelower.endswith('.jpeg'):
fullname = filesdir + filename
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
# If image is not same dimensions
if imgrect.size != size:
img = Image.open(fullname)
img = img.resize(size, Image.ANTIALIAS)
img.save(fullname, optimize=True, quality=95)
img = pygame.image.load(fullname).convert()
imgrect = img.get_rect()
screen.blit(img, imgrect)
pygame.mouse.set_visible(False)
pygame.display.flip()
# Elif video:
elif filenamelower.endswith('.mp4') or filenamelower.endswith('.mkv') or filenamelower.endswith('.avi'):
fullname = filesdir + filename
# Create instane of VLC and create reference to movie.
vlcInstance = vlc.Instance("--aout=adummy")
media = vlcInstance.media_new(fullname)
# Create new instance of vlc player
player = vlcInstance.media_player_new()
# Load movie into vlc player instance
player.set_media(media)
# Start movie playback
player.play()
# Do not continue if video not finished
while player.get_state() != vlc.State.Ended:
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()
player.stop()
clock.tick(1 / time) # framerate = 0.25 means 1 frame each 4 seconds
# Quit if keyboard pressed during video
for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
pygame.display.quit()
pygame.quit()
sys.exit()