视频数据处理方法!关于开源软件FFmpeg视频抽帧的学习
点击上方“Datawhale”,选择“星标”公众号
第一时间获取价值内容

视频文件是多媒体数据中比较常见的一种,也是入门门槛比较高的一个领域。视频数据相关的领域任务包括视频物体检测、视频物体追踪、视频分类、视频检索和视频摘要抽取等。
视频数据与图像数据非常类似,都是由像素点组成的数据。在视频数据在非音频部分基本上可以视为多帧(张)图像数据的拼接,即三维图像的组合。由于视频数据与图像数据的相似性,在上述列举的视频领域任务中大都可以借助图像方法来完成。
文本将讲解视频抽帧的几种方法,具体包括以下几种抽帧方式:
抽取视频关键帧(IPB帧)
抽取视频场景转换帧
按照时间进行均匀抽帧
抽取制定时间的视频帧
在进行讲解具体的抽帧方式之前,我不得不介绍下FFmpeg。FFmpeg是一套可以用来编码、解码、合成和转换音频和视频数据的开源软件,提供了非常全面的音视频处理功能。如果你的工作内容是视频相关,那么ffmpeg是必须要掌握的软件了。FFmpeg提供了常见音视频和编解码方式,能够对众多的音视频格式进行读取,基本上所有的软件都会借助FFmpeg来完成音视频的读取操作。
FFmpeg的学习资料可以参考:
http://ffmpeg.org/documentation.html
https://blog.csdn.net/leixiaohua1020/article/details/15811977
1. 抽取视频关键帧(IPB帧)
视频关键帧(Video Keyframes)是用于视频压缩和视频编解码的帧,视频关键帧是包含了完整信息的帧,其他的非关键帧将会使用与关键帧的差值进行压缩。视频帧具体可以分为IPB帧三种:
I帧表示关键帧,是最完整的帧画面,一般视频封面都选择I帧;
P帧单预测帧,利用之前的I帧或P帧,采用运动预测的方式进行帧间预测编码;
B帧双向预测帧,利用双向帧进行预测编码;
一般情况下关键帧`I帧`是信息最多的帧,也是用途最多的帧。在视频检索和视频分类任务中一般都借助`I帧`来完成,在一个时长60s的视频中,可以抽取得到16个I帧、84个P帧和184个B,I帧数量少包含的信息却是最多的。
使用ffprobe提取出IPB帧的时间:
抽取IPB帧到jpg图片:
由于ffmpeg抽取帧并无法按照时间戳来命名,需要手动将ffprobe提取出来的帧时间与抽取帧的图片进行对应重命名。关键帧具体的定义和用途可以参考:https://link.zhihu.com/?target=https%3A//en.wikipedia.org/wiki/Key_frame
2. 抽取视频场景转换帧
在视频中可以按照视频的镜头切换可以将视频分为不同的场景(scene boundaries),为了直观感受可以观看下面一个视频。
http://www.scikit-video.org/stable/_static/scene_cuts.mp4
视频场景抽取算法一般是使用帧间的相似差异程度来衡量,如果视频帧大于某一个阈值则认为是一个新的场景,否则不是一个新的场景。在scikit-video中提供了颜色相似度和边缘相似度两种度量方式,思路非常简单:
https://github.com/scikit-video/scikit-video/blob/master/skvideo/measure/scene.py
但是在我自己试验的过程中发现scikit-video中的场景检测非常慢,一个视频需要几分钟才能计算得到结果。后来在阅读ffmpeg文档过程中发现,ffmpeg早就有场景检测的命令,而且速度飞快。
scikit-video的场景检测速度慢是以下原因:scikit-video中场景检测的实现方式是读取所有的视频帧,这个步骤非常耗时;而ffmpeg能够根据视频帧的压缩情况来选择性读取帧,速度就非常快了。但是scikit-video库还是很直观的,我也从库源代码学习到了很多。
如果ffmpeg有对应的功能命令,优先使用ffmpeg来完成。
3. 均匀抽帧
4. 抽取制定时间的帧
为什么上述两个命令时间差距这么大呢,也就是-i与-ss的位置换了一下。区别就是如果-ss在前面,则会使用关键帧信息来进行索引,则会非常快。
具体说明参考:https://trac.ffmpeg.org/wiki/Seeking
智能推荐
Ubuntu中安装最新FFmpeg及使用FFmpeg进行视频图片数据帧的提取
Ubuntu中安装最新FFmpeg及视频图片数据帧的提取 如题所述本文是关于在Ubuntu中安装FFmpeg,如何之为最新版,那是因为是直接从FFmpeg 源码download官网 下载的源码进行编译安装的。本文中安装FFmpeg的方法援引这位博主分享的博文 https://blog.csdn.net/qq_38863413/article/details/105017775 依赖库的安装 &em...
Layui parent.layui.open弹框之Iframe 传值处理
Layui open弹框获取值的方法 介绍:Layui 弹框之Iframe传值处理 我的想法 解决 子页面 获取 父页面方法以及元素。 上代码,看图片 原创作品,欢迎来讨论! 介绍:Layui 弹框之Iframe传值处理 本人在使用到layui的iframe版 ,里面使用到了弹框 。 普通弹框:layui.open(); 像这种传递值都没什么问题 , 子页面获取父页面值 或者父页面获取子页面值 全...
外置Tomcat无法使用devtools实现热部署
练手的项目每次有源码或者页面更新都需要重新启动,不能忍,热部署走一波 这个项目是用外置Tomcat启动的 项目层级目录 模块依赖关系:service 依赖于 model 依赖于 api (启动类在service模块中) 引入devTools依赖,确定相关idea配置无误后,发现热部署没有生效 得出结论: devTools无法对使用对外置的tomcat运行的项目生效 于是在网上搜索外置tomcat项...
C++跨平台库QT学习7 使用UnitTest单元测试入门
C++跨平台库QT学习7 使用UnitTest单元测试入门 一、新建子目录项目 二、新建控制台项目 三、新建测试用例子目录项目 mycalctest.pro文件内容: 测试用例文件test_mycalctesttest.cpp 在子项目`mycalctest`点右键、运行 一、新建子目录项目 在QT点击菜单 文件-新建文件或项目-其他项目-子目录项目: 二、新建控制台项目 然后继续建一个子项目: ...
Python实用模块(二十五)loguru
软硬件环境 windows 10 64bits anaconda with python 3.7 loguru 0.5.3 前言 Python实用模块(十四)logging https://xugaoxiang.com/2019/12/04/python-module-logging 已 经介绍过了python内置日志模块logging。我们要使用logging,一般来讲,都是需要进行一...
猜你喜欢
Glide图片加载框架的使用简介与功能介绍
Glide图片加载框架的使用简介 . 1. 在app/build.gradle文件当中添加如下依赖: 2. 在AndroidManifest.xml中声明一下网络权限才行: 3. 开始使用Glide加载图片 with()方法的介绍 作用: 用于创建一个加载图片的实例;with()方法可以接收Context、Activity或者Fragment类型的参数 注意: with()方法中传入的实例会决定G...
编写过滤器解决全局乱码问题
过滤器编写步骤 编写一个类实现javax.servlet.Filter接口 重写接口中所有的方法,其中doFilter方法执行过滤的功能 配置过滤器 在web.xml中配置 使用注解@WebFilter 解决乱码需要添加这句代码:req.setCharacterEncoding(“utf-8”); 字符集与网页的编码要一致 EncodingFilter.java: 过滤器的...
HTML+CSS+JS做一个简易音乐播放器
先给大家看下效果: 实现功能:音乐播放,歌词跟随进度滚动,中间随着音乐播放图片360度旋转 文件目录: 做一个播放器,音乐和歌词事先要下载好,搜一些自己喜欢的封面,让图片360度旋转的样式,通过按钮增删样式达到跟音乐同步进行: 其中歌词匹配才是让我头疼的,所有JS代码部分: 需要所有源码,可以去github上自行下载: https://github.com/lzs1996/MusicPlayer....
Ecplise(jsp文件)导入css文件路径没错,但是没有样式(不生效/无效)
一、检查css文件的【路径】是否正确 1、:将页面在【浏览器】打开,按【Ctrl+u】,查看【页面源代码】(也可右键点击) 若页面进行【跳转】------>说明css路径没错 二、若路径有问题 参考链接: 1、Jsp中引入css等外部文件路径问题 https://blog.csdn.net/prospective0821/article/details/79775626?utm_medium...
自定义View——仿支付宝支付弹窗界面
上面这个是采用自定view方式实现的一个仿支付宝支付弹窗的效果; 1、自定义view并初始化自定义属性 继承自EditText的话可以用使用EditText中的一些属性和方法,在初始化完自定义属性后要记得调用recycle()方法进行回收; 2、初始化画笔 在第三个构造函数中调用就可以了, 3、在onDraw()方法中进行绘制 在绘制的时候先要计算出一个密码所占的宽度 获取到一个密码的宽度后就可以...
