在四处搜索之后,我看到有人拥有提出这个,想要一个动态的webp到webm。但这似乎很麻烦。所以我做这个是为了把一个动画的webp转换成mp4或者webm,这是我的live。它需要一些逻辑来将gif转换为视频并加以应用。问题是,这需要一点时间。
我想知道是否有人对如何提高速度有建议?
import os
import moviepy.video.io.ImageSequenceClip
def analyseImage(path):
'''
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
'''
im = PIL.Image.open(path)
results = {
'size': im.size,
'mode': 'full',
}
try:
while True:
if im.tile:
tile = im.tile[0]
update_region = tile[1]
update_region_dimensions = update_region[2:]
if update_region_dimensions != im.size:
results['mode'] = 'partial'
break
im.seek(im.tell() + 1)
except EOFError:
pass
return results
def processImage(path):
'''
Iterate the animated image extracting each frame.
'''
images = []
mode = analyseImage(path)['mode']
im = PIL.Image.open(path)
i = 0
p = im.getpalette()
last_frame = im.convert('RGBA')
try:
while True:
print("saving %s (%s) frame %d, %s %s" % (path, mode, i, im.size, im.tile))
'''
If the GIF uses local colour tables, each frame will have its own palette.
If not, we need to apply the global palette to the new frame.
'''
if '.gif' in path:
if not im.getpalette():
im.putpalette(p)
new_frame = PIL.Image.new('RGBA', im.size)
'''
Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
If so, we need to construct the new frame by pasting it on top of the preceding frames.
'''
if mode == 'partial':
new_frame.paste(last_frame)
new_frame.paste(im, (0, 0), im.convert('RGBA'))
nameoffile = path.split('/')[-1]
output_folder = path.replace(nameoffile, '')
name = '%s%s-%d.png' % (output_folder, ''.join(os.path.basename(path).split('.')[:-1]), i)
print(name)
new_frame.save(name, 'PNG')
images.append(name)
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
pass
return images
def webp_mp4(filename, outfile):
images = processImage("%s" % filename)
fps = 30
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(images, fps=fps)
clip.write_videofile(outfile)
return [outfile]
webp_mp4(filename, outfile)
它目前的工作方式是,当您运行webp_mp4(filename, outfile)
时,它调用调用analyseImage
的processImage
。最后,这一切都很好。只是想快点。
发布于 2022-01-17 20:00:37
视频转码通常是一项“令人尴尬的并行”任务,而processImage
则是在一个大的序列中完成任务。如果processImage
是慢的部分,您可以使用multiprocessing.Pool并为每个工作人员(可以在单独的CPU核心上运行)分配自己的帧范围来处理。PIL对象是不可挑选的。,所以您必须编写临时文件,这似乎已经在进行中了。
我对PIL不太了解,所以如果有更好的方法来使用lib,我就不会看到它。也许将每个帧保存为PNG很慢;值得尝试TIF或JPEG。(我会亲自尝试,但是我的Python安装不是在这台笔记本上安装的。)
发布于 2022-02-17 21:24:44
查看代码时的一些优化提示:
analyseImage
和processImage
中从磁盘读取图像。这不是一件大事,因为它只发生一次每个映像,但读取磁盘仍然是一个相对缓慢的操作,所以最好不要做太多的必要。相反,您可以在processImage
中打开并将打开的图像传递给analyseImage
。imageio
是moviepy
内部使用的库,它提供了一种实现此功能的方法。您只需使用imageio.get_writer(path)
创建一个视频编写器,然后使用writer.append_data(frame_data)
依次向其添加帧。
我自己试过了,但是最后我把颜色搞混了,所以我没有工作代码可以提供。不过,作为提示,您可以将PIL
图像转换为imageio
所期望的原始框架数据,比如numpy.array(im)
。发布于 2022-02-17 02:36:06
threads
Number of threads to use for ffmpeg. Can speed up the writing of
the video on multicore computers.
* clip.write_videofile(outfile, threads=4)
您可以设置线程数以提高写入速度。
https://stackoverflow.com/questions/70745944
复制相似问题