视频抽帧那点事

视频抽帧

视频文件是多媒体数据中比较常见的一种,也是入门门槛比较高的一个领域。视频数据相关的领域任务包括视频物体检测、视频物体追踪、视频分类、视频检索和视频摘要抽取等。

视频数据与图像数据非常类似,都是由像素点组成的数据。在视频数据在非音频部分基本上可以视为多帧(张)图像数据的拼接,即三维图像的组合。由于视频数据与图像数据的相似性,在上述列举的视频领域任务中大都可以借助图像方法来完成。

文本将讲解视频抽帧的几种方法,具体包括以下几种抽帧方式:

  • 抽取视频关键帧(IPB帧)
  • 抽取视频场景转换帧
  • 按照时间进行均匀抽帧
  • 抽取制定时间的视频帧

在进行讲解具体的抽帧方式之前,我不得不介绍下FFmpeg。FFmpeg是一套可以用来编码、解码、合成和转换音频和视频数据的开源软件,提供了非常全面的音视频处理功能。如果你的工作内容是视频相关,那么ffmpeg是必须要掌握的软件了。FFmpeg提供了常见音视频和编解码方式,能够对众多的音视频格式进行读取,基本上所有的软件都会借助FFmpeg来完成音视频的读取操作。

FFmpeg的学习资料可以参考:

# 查看视频信息
> ffmpeg -i 666051400.mp4
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '666051400.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf57.56.100
  Duration: 00:17:02.00, start: 0.000000, bitrate: 374 kb/s
    Stream #0:0(und): Video: h264 (High) (avc1 / 0x31637661), yuv420p, 
    Metadata:
      handler_name    : VideoHandler
    Stream #0:1(und): Audio: aac (LC) (mp4a / 0x6134706D), 44100 Hz
    Metadata:
      handler_name    : SoundHandler
At least one output file must be specified

抽取视频关键帧(IPB帧)

视频关键帧(Video Keyframes)是用于视频压缩和视频编解码的帧,视频关键帧是包含了完整信息的帧,其他的非关键帧将会使用与关键帧的差值进行压缩。视频帧具体可以分为IPB帧三种:

  • I帧表示关键帧,是最完整的帧画面,一般视频封面都选择I帧;
  • P帧单预测帧,利用之前的I帧或P帧,采用运动预测的方式进行帧间预测编码;
  • B帧双向预测帧,利用双向帧进行预测编码;

一般情况下关键帧`I帧`是信息最多的帧,也是用途最多的帧。在视频检索和视频分类任务中一般都借助`I帧`来完成,在一个时长60s的视频中,可以抽取得到16个I帧、84个P帧和184个B,I帧数量少包含的信息却是最多的。

  • 使用ffprobe提取出IPB帧的时间:
ffprobe -i 666051400.mp4 -v quiet -select_streams v -show_entries frame=pkt_pts_time,pict_type
  • 抽取IPB帧到jpg图片:
# 抽取I帧
ffmpeg -i 666051400.mp4 -vf "select=eq(pict_type\,I)"  -vsync vfr -qscale:v 2 -f image2 ./%08d.jpg

# 抽取P帧
ffmpeg -i 666051400.mp4 -vf "select=eq(pict_type\,P)"  -vsync vfr -qscale:v 2 -f image2 ./%08d.jpg

# 抽取B帧
ffmpeg -i 666051400.mp4 -vf "select=eq(pict_type\,B)"  -vsync vfr -qscale:v 2 -f image2 ./%08d.jpg

由于ffmpeg抽取帧并无法按照时间戳来命名,需要手动将ffprobe提取出来的帧时间与抽取帧的图片进行对应重命名。关键帧具体的定义和用途可以参考:

抽取视频场景转换帧

在视频中可以按照视频的镜头切换可以将视频分为不同的场景(scene boundaries),为了直观感受可以观看下面一个视频。

http://www.scikit-video.org/stable/_static/scene_cuts.mp4​www.scikit-video.org

视频场景抽取算法一般是使用帧间的相似差异程度来衡量,如果视频帧大于某一个阈值则认为是一个新的场景,否则不是一个新的场景。在scikit-video中提供了颜色相似度和边缘相似度两种度量方式,思路非常简单:

但是在我自己试验的过程中发现scikit-video中的场景检测非常慢,一个视频需要几分钟才能计算得到结果。后来在阅读ffmpeg文档过程中发现,ffmpeg早就有场景检测的命令,而且速度飞快。

# https://ffmpeg.org/ffmpeg-filters.html#select_002c-aselect
# 其中0.1表示帧为新场景的概率
ffmpeg -i 666051400.mp4 -filter:v "select='gt(scene,0.1)',showinfo" -f null - 2>&1

scikit-video的场景检测速度慢是以下原因:scikit-video中场景检测的实现方式是读取所有的视频帧,这个步骤非常耗时;而ffmpeg能够根据视频帧的压缩情况来选择性读取帧,速度就非常快了。但是scikit-video库还是很直观的,我也从库源代码学习到了很多。

如果ffmpeg有对应的功能命令,优先使用ffmpeg来完成。

均匀抽帧

# -r 指定抽取的帧率,即从视频中每秒钟抽取图片的数量。1代表每秒抽取一帧。
ffmpeg -i 666051400.mp4 -r 1 -q:v 2 -f image2 ./%08d.000000.jpg

抽取制定时间的帧

# 耗时0.07s
ffmpeg -ss 00:00:30 -i 666051400.mp4 -vframes 1 0.jpg

# 耗时0.68s
ffmpeg -i 666051400.mp4 -ss 00:00:30  -vframes 1 0.jpg

为什么上述两个命令时间差距这么大呢,也就是-i与-ss的位置换了一下。区别就是如果-ss在前面,则会使用关键帧信息来进行索引,则会非常快。

 

文章来自:https://zhuanlan.zhihu.com/p/85895180?utm_source=wechat_session&utm_medium=social&utm_oi=46204255731712

posted @ 2019-10-12 11:34  7411  阅读(7485)  评论(0编辑  收藏  举报