Handling Video Files

Handling Video Files

有时需要从标准视频文件(例如.avi和.mov文件)中读取一系列图像。

在科学环境中,通常避免使用这些格式有利于简单的图像目录或多维TIF。视频格式比较难以零碎读取,通常不支持随机帧访问或研究型元数据,如果不仔细配置,则使用有损压缩。但是视频文件被广泛使用,并且它们很容易分享,所以在必要时配备读取和写入它们是很方便的。

阅读视频文件的工具在安装和使用方便性,磁盘和内存使用以及跨平台兼容性方面各不相同。这是一本实用指南。

解决方法:将视频转换为图像序列

对于一次性解决方案,最简单,最可靠的方法是将视频转换为一系列顺序编号的图像文件,通常称为图像序列。然后将图像文件可以被读入ImageCollectionskimage.io.imread_collection。将视频转换为帧可以在生物成像社区的基于GUI的跨平台程序ImageJ或用于处理视频文件的强大命令行实用程序FFmpeg轻松完成。

在FFmpeg中,以下命令从视频中的每个帧生成一个图像文件。这些文件用五位数字编号,左边用零填充。

ffmpeg -i "video.mov" -f image2 "video-frame%05d.png"

有关图像序列FFmpeg教程中提供了更多信息。

生成图像序列有缺点:它们可能很大且笨重,生成它们可能需要一些时间。通常最好直接使用原始视频文件。对于更直接的解决方案,我们需要从Python执行FFmpeg或LibAV以从视频中读取帧。FFmpeg和LibAV是两个大型的开源项目,可以解码野外广泛使用的各种格式的视频。有几种方法可以从Python中使用它们。不幸的是,每种方法都有一些缺点。

PyAV

PyAV使用FFmpeg(或LibAV)库直接从视频文件读取图像数据。它使用Cython绑定调用它们,因此速度非常快。

import av v = av.open('path/to/video.mov')

PyAV的API反映了帧存储在视频文件中的方式。

for packet in container.demux(): for frame in packet.decode(): if frame.type == 'video': img = frame.to_image() # PIL/Pillow image arr = np.asarray(img) # numpy array # Do something!

最近,conda软件包(用于PyAV及其相关的公共配方可用于OSX和Linux。

conda install -c danielballan pyav

Wheels也适用于OSX:

.. code-block:: bash

pip install -f http://wheels.scipy.org of

PyAV也被证明可以在Windows上成功构建,但在编写本文时,方便的二进制包不会公开发布。

PyAV pip install av在Linux和OSX上是pip-installable(),但正确设置FFmpeg库的链接是微妙的。建议使用二进制安装程序。

添加对PyAV的随机访问

PIMS中的Video类调用PyAV,并添加额外的功能来解决科学应用中的常见问题,按帧号访问视频。视频文件格式被设计为以近似的方式按时间搜索,并且它们不支持寻求特定帧号的有效手段。PIMS通过解码(但不读取)整个视频并产生支持逐帧索引的内容目录来添加此缺失功能。

import pims v = pims.Video('path/to/video.mov') v[-1] # a 2D numpy array representing the last frame

PIMS可通过soft-matter渠道上的conda进行安装

conda install -c soft-matter pims

和pip

pip install pims

MoviePy

Moviepy通过子进程调用FFmpeg,将解码后的视频从FFmpeg 传输到RAM中,并将其读出。这种方法很简单,但可能很脆弱,对于超过可用RAM的大视频无法使用。如果安装了FFmpeg,它适用于所有平台。

由于它没有链接到FFmpeg的底层库,所以安装起来更容易,但速度只有它的一半

from moviepy.editor import VideoFileClip myclip = VideoFileClip("some_video.avi")

MoviePy可以使用pip进行安装。

pip install moviepy

Imageio

Imageio采用与MoviePy相同的方法。它也支持多种其他图像文件格式。

import imageio filename = '/tmp/file.mp4' vid = imageio.get_reader(filename, 'ffmpeg') for num, image in vid.iter_data(): print(image.mean()) metadata = vid.get_meta_data()

Imageio可以使用pip进行安装。

pip install imageio

OpenCV

最后,另一个解决方案是OpenCV中的VideoReader类,它具有绑定到FFmpeg的功能。如果您因为其他原因需要OpenCV,那么这可能是最好的方法。但是,OpenCV很难安装,尤其是因为它必须链接到FFmpeg才能支持从文件中读取视频。此外,已知某些视频编解码器的元数据是错误的。(请参阅此问题。)