使用OpenCV编写一个可以定时抽帧的脚本

一、概述

  在计算机视觉数据预处理阶段,一个常用的工序是要将原始的视频数据抽帧,得到图像数据集。有时候视频很长,而我们感兴趣的场景可能只在某些较短的时段内出现。这种情况下如果对整个视频抽帧再进行人工筛选,不仅会占用不必要的空间,而且增大了筛选的工作量。

  本文记录了一个抽帧脚本的编写过程。涉及的主要知识点:

  1. OpenCV中和视频处理相关的接口函数
    • cap.get(cv2.CAP_PROP_POS_MSEC) 获取当前帧信息
  2. 在循环中同时迭代两个元素
    • zip和yield的用法
  3. 一个处理区间的库——pyinter
    • 主要用到Interval和IntervalSet两个类

二、关键组件介绍

2.1 OpenCV相关接口

  首先分享一个非常适合python-opencv快速上手的教程(也涉及一些简单的分类,用的keras API)。注意如果github上一些较大的ipynb文件打不开,可以直接去jupyter官网粘贴链接。

  OpenCV这部分代码比较常规,注意几个地方就行:

  1. cv2.waitkey可以控制视频播放速度,一般如果只是播放的话,可选cv2.waitkey(25)。不过通常用这个都是要处理数据或者做inference的,记得把数字改成0..要不然会浪费不必要的时间。

  2. cap.get()函数用于获取当前帧的信息。其中可以访问的信息很多,这里用到的是cv2.CAP_PROP_POS_MSEC,即当前帧在整个视频中处于第几毫秒的位置(注意,返回的精度为浮点型)。获取到这个时刻信息,只需判断该时刻是否落在感兴趣的时刻区间内,再对区间内的帧进行保存即可。

2.2 同时迭代一个列表中的两个元素

  为了将未知数量的时刻对组合成区间,首先一个问题是,对于用户输入的一长串时刻,对其两两配对,每两个时刻组成一个区间。这里涉及到一个问题:即如何迭代同一个列表中的多个元素。

  首先区分一下,从多个列表中迭代多个元素和该问题是不同的。多个列表迭代直接使用zip就可以实现。而上述问题需要用到生成器。涉及一些生成和迭代器的知识。下面提供两种实现方法。

方法一:使用iter函数

  iter函数将列表(其实不只是列表,只要是包含多个元素的对象就行)转换成一个迭代器对象it,该迭代器对象通过调用next函数可以获取迭代器的下一个元素。直到迭代至最后一个元素结束(StopIteration)。
故代码可以这样写:

def pairwise(lst):
    it = iter(lst)
    while True:
        yield next(it), next(it)

这里用到了一个强大的函数,yield:

  1. 关于yield的理解。先看菜鸟教程中的一段话:
# 例子:菲波那切数列
def fab(max): 
    n, a, b = 0, 0, 1 
    while n < max: 
        yield b      # 使用 yield
        # print b 
        a, b = b, a + b 
        n = n + 1
 
for n in fab(5): 
    print n

  简单地讲,yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用 fab(5) 不会执行 fab 函数,而是返回一个 iterable 对象!在 for 循环执行时,每次循环都会执行 fab 函数内部的代码, 执行到 yield b 时,fab 函数就返回一个迭代值,下次迭代时,代码从 yield b 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。*

  也就是说,使用了yield的函数会返回一个生成器,然后该函数的代码会在对生成器的每一次迭代中被执行(故yield函数通常伴随着两个循环,一个是yield语句通常定义在函数的循环中;另一个是调用包含yield的函数时会使用循环)。每次执行函数时,代码会在执行yield语句之后返回一个迭代值,然后中断。下次再执行该函数,代码直接从yield的下一条语句开始,需要注意的是,函数的局部变量值会一直保留到结束。

  和yield相关的两个细节:next和return。next可以接收迭代器和生成器作为输入参数,然后每次返回一个迭代值。(python3中next不是成员函数,next是成员函数,这两种调用都可以。python2中next是成员函数)
  在generation function中如果执行过程遇到return,则直接跑出StopIteration终止迭代。

方法二:zip的妙用
def pairwise(lst):
    '''另一种方法:利用zip实现多元素迭代'''
    for x,y in zip(lst[0::2], lst[1::2]):
        yield x,y

  将列表的奇数项和偶数项元素zip到一起,然后生成。该部分内容参考stackoverflow

2.2 区间管理模块

  根据上面的描述,我们解决了如何从给定的输入时刻列表中两两取出开始和结束时刻点。接下来解决如何将这些时刻点组成多个闭合区间,最后再整合为一个区间。

  首先要强调一点,这里的区间是一个连续的区间,因为我们要判断当前帧是否在某时间区间内,而由2.1知,当前帧所对应的时刻(单位毫秒)不一定是一个整数!先来看一个简化版的问题,如何组合多个独立的列表(离散区间)。

  我们知道,用Python判断一个元素是否在列表中可以用if x in list这种简易表达。但是对于多个不连续的区间,怎么使用类似的方法呢?这里有几种不同的实现方法:
①最简单:几个列表直接相加。
②建一个空列表,然后每次循环append一个子区间。最后得到一个两层的嵌套列表,展开即得到整合区间。
小问题:如何展开嵌套列表?
这里我有一个不太常规的方法,但是蛮好用的:

Fig. 1 展开嵌套列表

可以展开任意层数的嵌套列表~不过注意下返回的是tuple类型。

  那么如何根据给定端点产生连续区间?这里用到一个区间管理的库——pyinter。直接上图来看看效果:

Fig. 2 pyinter区间管理库

然后只需要用pyinter.IntervalSet来组合多个区间即可。
Fig. 3 组合多个连续区间

更多关于pyinterval模块的介绍1, 2

三、总结

   至此,抽帧脚本需要的所有组件都准备好了。只需要读取视频,然后对每一帧获取时刻并判断是否在用户指定的时间区间中,若在则进一步处理,比如imwrite或imshow等。如需要完整定时抽帧脚本,请到我的github上去拿~脚本使用方法:
python get_frame.py 1.mp4 3 0:32 0:58 1:10 1:26 2:01 2:40
其中第一个参数为视频路径,第二个为抽帧间隔,后面的参数为感兴趣的时间段,这里我取了三小段~Repo里面还有一些个人经常用到的小脚本,喜欢的话记得留个star!

四、参考

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,504评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,434评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,089评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,378评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,472评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,506评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,519评论 3 413
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,292评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,738评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,022评论 2 329
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,194评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,873评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,536评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,162评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,413评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,075评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,080评论 2 352

推荐阅读更多精彩内容