节能与OpenCV的关键事件的视频片段

上周的博客文章教我们怎么写的视频OpenCV的使用和Python到文件。这是一个伟大的技能有,但它也带来了一个问题:

我如何写的视频剪辑包含 有趣的活动到文件,而不是整个视频?

在这种情况下,总的目标是建立一个 视频概要,蒸馏所述视频流的最关键,突出部,和有趣的部分成一系列短的视频文件。

究竟是什么定义了一个“键或有趣的事件”,是完全取决于你和你的应用程序。关键事件的潜在的例子包括:

运动在进入受限区域被发现。
入侵者进入你的房子或公寓。
一辆由你家里跑在繁忙的街道停止的迹象。
在每一种情况下,你不感兴趣的 整个视频采集- 相反,你只需要包含操作的视频剪辑!

要了解如何捕捉关键事件的视频剪辑OpenCV的做(和建立自己的视频简介),只是不停的阅读。

寻找源代码,这个帖子?直接跳到下载部分。

节能与OpenCV的关键事件的视频片段

这篇博客的目的是为了演示如何 写简短的视频剪辑文件,当一个 特定的动作发生。我们将使用我们从上周的博客中获得的知识编写视频OpenCV的文件来实现此功能。

正如我在这篇文章的顶部,定义了视频流“键”和“有趣”的事件中提到完全取决于你的应用程序和你想建什么工作服目标。

你可能会在一个房间检测运动有趣。监控你的房子。或创建一个系统来观察机动车驾驶人违反法律的流量和存储剪辑。

作为两者的一个简单的例子:

限定的关键事件。
编写视频剪辑提交载有该事件。
我们将处理视频流和寻找这个绿球的出现:

图1:绿球,我们将在视频流以检测的一个例子。
图1:绿球,我们将在视频流以检测的一个例子。
如果这个绿球出现在我们的视频流,我们将开辟一个新的文件视频(根据发生的时间戳),写剪辑文件,然后一旦球在我们的视野中消失停止写作过程。

此外,我们的实施将具有许多期望的性质,包括:

写入帧我们的视频文件中的几秒钟 之前的动作发生。
写入帧文件中的几秒钟 后,行动结束-在这两种情况下,我们的目标不仅是为了捕获 整个事件,而且 事件的情况下 也是如此。
利用线程,以确保双方的输入流和输出的视频剪辑文件执行I / O时,我们的主要程序没有减慢。
利用内置的Python数据结构,如 双端队列 和 队列 ,所以我们不必依靠外部库(比OpenCV的和其他imutils,当然)。
项目结构

在我们开始之前执行我们的关键事件视频的作家,让我们来看看在项目结构:

Saving key event video clips with OpenCV

|— output
|— pyimagesearch
| |— __init__.py
| |— keyclipwriter.py
|— save_key_events.py
1
2
3
4
5
|— output
|— pyimagesearch
| |— __init__.py
| |— keyclipwriter.py
|— save_key_events.py
里面 pyimagesearch 模块,我们将定义一个名为类 KeyClipWriter 里面 keyclipwriter 。PY 文件。这个类将处理从输入视频流中的广告写在一个安全,高效,和螺纹的方式接收的文件框架。

该驱动程序的脚本, save_key_events 。PY ,将定义什么是“有趣的事件”(即绿球进入相机的视图),其次的标准传递这些帧到 KeyClipWriter 那么这将创造我们的视频简介。

关于Python + OpenCV的版本,一个短的说明

本博客文章假定您使用 Python的3+和 OpenCV的3。正如我提到上周的帖子,我是不是能够得到 CV2 。VideoWriter 功能黑客周围的几个小时后,我的OpenCV 2.4的安装工作,所以没有运气,我最终放弃了OpenCV的2.4这个项目,并与3 OpenCV的坚持。

在这一课中的代码是 技术上兼容的Python 2.7,但你需要改变一些(同样,你在使用Python 2.7使用OpenCV的3绑定提供) 导入 语句(我会沿途指出这些了)。

书写键/有趣的视频短片的OpenCV到文件

让我们继续前进,并开始检讨我们 KeyClipWriter 类:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False
我们通过导入我们所需的Python包开始 行2-6。本教程假设你正在使用Python 3中,所以如果你使用Python 2.7,你需要改变 4号线从 从队列进口队列 简单地 导入队列 。

9号线将定义构造我们的 KeyClipWriter ,它接受两个可选参数:

由bufSize :帧的最大数目为保持缓存在内存缓冲区。
超时 :表示的秒数睡时(1)写入视频剪辑到文件,(2)不存在的帧准备要被写入的整数。
然后,我们在初始化四个重要变量 线18-22:

框架 :用于商店最大的缓冲 由bufSize 框架已经最近从视频流中读取。
Q :“先入先出”(FIFO)的Python 队列数据结构,用于保存正在等待被写入到视频文件的帧。
笔者 :对的实例化 CV2 。VideoWriter 用于实际写入帧输出的视频文件类。
主题 :一个Python的 线程 写入视频时提交,我们将使用实例(以避免昂贵的I / O延迟延迟)。
录音 :布尔值,指示我们是否是在“录音模式”。
接下来,让我们来回顾一下 更新 方法:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False

def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)
24
25
26
27
28
29
30
def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)
该 更新 功能需要一个参数,该 架 从我们的视频流的读取。我们利用这个 框架 ,并将其存储在我们的 帧 缓冲(第26行)。如果我们已经在记录模式中,我们将存储 帧 中的 队列 以及因此它可以被刷新到视频文件(线路29和30)。

为了开球实际的视频片段拍摄,我们需要一个 启动 的方法:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False

def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)

def start(self, outputPath, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
self.writer = cv2.VideoWriter(outputPath, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()

# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i – 1])

# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def start(self, outputPath, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
self.writer = cv2.VideoWriter(outputPath, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()

# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i – 1])

# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()
首先,我们更新 记录 布尔值,表明我们是在“录音模式”。然后,我们初始化 CV2 。VideoWriter 使用附送 outputPath , fourcc值 ,并 fps的 提供给 起动 方法,与框架空间尺寸(即,宽度和高度)沿。为了彻底审查 CV2 。VideoWriter 参数,请参见本博客文章。

39行 初始化我们的 队列 用来存储准备被写入到文件的帧。然后,我们遍历我们的所有帧 的帧 缓冲,并将它们添加到队列中。

最后,我们生成一个单独的线程来处理写入帧视频 – 这样,我们不要等待I / O操作完成放慢我们主要的视频处理流水线。

正如上面提到的, 启动 方法创建一个新的线程,调用 写入 用于写入帧里面的方法 Q 到文件。让我们来定义这个 写 方法:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False

def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)

def start(self, outputPath, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
self.writer = cv2.VideoWriter(outputPath, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()

# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i – 1])

# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()

def write(self):
# keep looping
while True:
# if we are done recording, exit the thread
if not self.recording:
return

# check to see if there are entries in the queue
if not self.Q.empty():
# grab the next frame in the queue and write it
# to the video file
frame = self.Q.get()
self.writer.write(frame)

# otherwise, the queue is empty, so sleep for a bit
# so we don’t waste CPU cycles
else:
time.sleep(self.timeout)
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def write(self):
# keep looping
while True:
# if we are done recording, exit the thread
if not self.recording:
return

# check to see if there are entries in the queue
if not self.Q.empty():
# grab the next frame in the queue and write it
# to the video file
frame = self.Q.get()
self.writer.write(frame)

# otherwise, the queue is empty, so sleep for a bit
# so we don’t waste CPU cycles
else:
time.sleep(self.timeout)
53号线 开始一个无限循环,将继续对新帧,将它们写为文件,直到我们的视频录制已经完成投票。

线55和56 使看到一个检查,如果该记录应该停止,如果是这样,我们从线程返回。

否则,如果 Q 是不空的,我们抢下一帧,并将其写入视频文件(线59-63)。

如果在无帧 Q ,我们睡了一下,让我们不会无谓地浪费CPU周期纺(线67和68)。这是 特别重要的 使用时 队列 数据结构,这是 线程安全,这意味着我们必须获得一个锁定/信号量之前更新内部缓冲区。如果我们不叫 时间。睡觉 时,缓冲区为空,则 写入 和 更新 方法会不断争取这个锁。相反,它是最好让对位作家休眠状态,直到有队列中需要被写入文件帧的积压。

我们也将定义一个 冲洗 方法,只是将留在所有帧 Q 和他们转储到文件:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False

def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)

def start(self, outputPath, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
self.writer = cv2.VideoWriter(outputPath, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()

# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i – 1])

# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()

def write(self):
# keep looping
while True:
# if we are done recording, exit the thread
if not self.recording:
return

# check to see if there are entries in the queue
if not self.Q.empty():
# grab the next frame in the queue and write it
# to the video file
frame = self.Q.get()
self.writer.write(frame)

# otherwise, the queue is empty, so sleep for a bit
# so we don’t waste CPU cycles
else:
time.sleep(self.timeout)

def flush(self):
# empty the queue by flushing all remaining frames to file
while not self.Q.empty():
frame = self.Q.get()
self.writer.write(frame)
70
71
72
73
74
def flush(self):
# empty the queue by flushing all remaining frames to file
while not self.Q.empty():
frame = self.Q.get()
self.writer.write(frame)
当视频录制完成用这样的方法,我们需要立即刷新所有帧到文件。

最后,我们定义 光洁度 以下方法:

Saving key event video clips with OpenCVPython

# import the necessary packages
from collections import deque
from threading import Thread
from queue import Queue
import time
import cv2

class KeyClipWriter:
def __init__(self, bufSize=64, timeout=1.0):
# store the maximum buffer size of frames to be kept
# in memory along with the sleep timeout during threading
self.bufSize = bufSize
self.timeout = timeout

# initialize the buffer of frames, queue of frames that
# need to be written to file, video writer, writer thread,
# and boolean indicating whether recording has started or not
self.frames = deque(maxlen=bufSize)
self.Q = None
self.writer = None
self.thread = None
self.recording = False

def update(self, frame):
# update the frames buffer
self.frames.appendleft(frame)

# if we are recording, update the queue as well
if self.recording:
self.Q.put(frame)

def start(self, outputPath, fourcc, fps):
# indicate that we are recording, start the video writer,
# and initialize the queue of frames that need to be written
# to the video file
self.recording = True
self.writer = cv2.VideoWriter(outputPath, fourcc, fps,
(self.frames[0].shape[1], self.frames[0].shape[0]), True)
self.Q = Queue()

# loop over the frames in the deque structure and add them
# to the queue
for i in range(len(self.frames), 0, -1):
self.Q.put(self.frames[i – 1])

# start a thread write frames to the video file
self.thread = Thread(target=self.write, args=())
self.thread.daemon = True
self.thread.start()

def write(self):
# keep looping
while True:
# if we are done recording, exit the thread
if not self.recording:
return

# check to see if there are entries in the queue
if not self.Q.empty():
# grab the next frame in the queue and write it
# to the video file
frame = self.Q.get()
self.writer.write(frame)

# otherwise, the queue is empty, so sleep for a bit
# so we don’t waste CPU cycles
else:
time.sleep(self.timeout)

def flush(self):
# empty the queue by flushing all remaining frames to file
while not self.Q.empty():
frame = self.Q.get()
self.writer.write(frame)

def finish(self):
# indicate that we are done recording, join the thread,
# flush all remaining frames in the queue to file, and
# release the writer pointer
self.recording = False
self.thread.join()
self.flush()
self.writer.release()
76
77
78
79
80
81
82
83
def finish(self):
# indicate that we are done recording, join the thread,
# flush all remaining frames in the queue to file, and
# release the writer pointer
self.recording = False
self.thread.join()
self.flush()
self.writer.release()
此方法指示录音已经完成,主要的脚本加入写线程,刷新剩余帧中的 Q 到文件,最后释放 CV2 。VideoWriter 指针。

现在,我们已经定义了 KeyClipWriter 类,我们可以继续用于实现“键/有趣的事件”检测到驾驶员的脚本。

节能与OpenCV的关键事件

为了保持这个博客帖子简单动手,我们将定义我们的“关键事件”是当该绿色球进入我们的视频流:

图2:在视频流中的一个关键/有趣的事件的一个例子。
图2:在视频流中的一个关键/有趣的事件的一个例子。
一旦我们看到这个绿色的球,我们将调用 KeyClipWriter 编写包含绿球,以文件中的所有帧。从本质上讲,这会给我们一组整齐地总结了事件短片的 全视频流-总之, 视频简介。

当然,你可以使用此代码作为样板/起点,以确定自己的行为-干脆我们就用“绿球”事件,因为我们之前多次覆盖其上PyImageSearch博客,包括跟踪物体的移动和球跟踪。

在继续本教程的其余部分,确保你有之前imutils在系统上安装包:

Saving key event video clips with OpenCVPython

$ pip install imutils
1
$ pip install imutils
这将确保您可以使用 视频流 这将创建一个类既内置/ USB摄像头和树莓派相机模块的统一访问。

让我们开始吧。打开 save_key_events 。PY 文件,插入下面的代码:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())
2-8行导入我们需要Python包而 行11-22分析我们的命令行参数。该组命令行参数详情如下:

– 输出 :这是路径 输出目录 ,我们将存储输出的视频剪辑。
– picamera :如果你想使用你的树莓派摄像头(而非内置/ USB摄像头),然后提供一个值 – picamera 1 。你可以阅读更多有关访问都内置/ USB摄像头和树莓派相机模块(不改变的一行代码)在这个岗位。
– FPS :此开关可以控制你的输出视频的期望FPS。此值应类似于每秒的图像处理流水线可处理的帧的数量。
– 编解码器 :该的FourCC输出的视频剪辑的编解码器。请参阅以前的文章以了解更多信息。
– 缓冲器- 尺寸 :的内存使用缓冲器来存储从相机传感器最近轮询帧的大小。较大的 – 缓冲器- 大小 将允许之前,也可以包括在输出视频片段中的“键事件”后更多的上下文,而较小的 – 缓冲器- 大小 将前和“键事件”之后存储较少帧。
让我们来执行一些初始化:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())

# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0
第26-28行 初始化我们的 视频流 并让相机传感器的热身。

从那里, 线32和33限定用于在HSV颜色空间中的绿球下部和上部色阈边界。有关我们如何定义这些颜色的阈值的更多信息,请看到这个帖子。

37号线 实例我们 KeyClipWriter 使用我们提供的 – 缓冲- 大小 ,以初始化用来计数的数量的整数以及连续帧的未包含的任何有趣的事件。

现在,我们可以从我们的视频流开始处理框架:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())

# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0

# keep looping
while True:
# grab the current frame, resize it, and initialize a
# boolean used to indicate if the consecutive frames
# counter should be updated
frame = vs.read()
frame = imutils.resize(frame, width=600)
updateConsecFrames = True

# blur the frame and convert it to the HSV color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# construct a mask for the color “green”, then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

# find contours in the mask
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# keep looping
while True:
# grab the current frame, resize it, and initialize a
# boolean used to indicate if the consecutive frames
# counter should be updated
frame = vs.read()
frame = imutils.resize(frame, width=600)
updateConsecFrames = True

# blur the frame and convert it to the HSV color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# construct a mask for the color “green”, then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

# find contours in the mask
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
上 线41我们开始遍历从我们的视频流的帧。 线路45和46 读出的下一个 帧 从视频流,然后调整其大小以具有600像素的宽度。

进一步预处理是在完成 线路50和51通过稍微模糊的图像,然后将图像从RGB颜色空间到HSV色空间转换(这样我们可以应用我们的颜色的阈值)。

实际颜色阈值是在执行 第56行使用 CV2 。INRANGE 功能。该方法找到的所有像素 p是 greenLower <= p <= greenUpper 。然后,我们进行了一系列的糜烂和扩张术,以消除留在面具的小斑点。

最后, 行61-63找到阈值的图像中的轮廓。

如果你感到困惑这个处理管道的任何步骤,我建议要回我们以前的帖子球追踪和物体运动的主题,以进一步熟悉。

我们现在就可以检查,看看绿球是在我们的图像中发现:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())

# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0

# keep looping
while True:
# grab the current frame, resize it, and initialize a
# boolean used to indicate if the consecutive frames
# counter should be updated
frame = vs.read()
frame = imutils.resize(frame, width=600)
updateConsecFrames = True

# blur the frame and convert it to the HSV color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# construct a mask for the color “green”, then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

# find contours in the mask
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use it
# to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
updateConsecFrames = radius <= 10

# only proceed if the redius meets a minimum size
if radius > 10:
# reset the number of consecutive frames with
# *no* action to zero and draw the circle
# surrounding the object
consecFrames = 0
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 0, 255), 2)

# if we are not already recording, start recording
if not kcw.recording:
timestamp = datetime.datetime.now()
p = “{}/{}.avi”.format(args[“output”],
timestamp.strftime(“%Y%m%d-%H%M%S”))
kcw.start(p, cv2.VideoWriter_fourcc(*args[“codec”]),
args[“fps”])
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use it
# to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
updateConsecFrames = radius <= 10

# only proceed if the redius meets a minimum size
if radius > 10:
# reset the number of consecutive frames with
# *no* action to zero and draw the circle
# surrounding the object
consecFrames = 0
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 0, 255), 2)

# if we are not already recording, start recording
if not kcw.recording:
timestamp = datetime.datetime.now()
p = “{}/{}.avi”.format(args[“output”],
timestamp.strftime(“%Y%m%d-%H%M%S”))
kcw.start(p, cv2.VideoWriter_fourcc(*args[“codec”]),
args[“fps”])
66线使一个检查,以确保所述至少一个轮廓被发现,且如果是的话, 线路69和70发现在掩模(按面积)最大的轮廓,并使用该轮廓来计算最小外接圆。

如果圆的半径达到10个像素(最小叙74号线),那么我们会认为我们已经找到了绿球。 线78-80 重置次数 consecFrames 不包含任何有趣的事件(因为一个有趣的事件“发生目前”),并画一个圆突出的框架我们的球。

最后,我们做一个检查,如果看看我们是否正在录制视频片段(83号线)。如果没有,我们生成基于当前的时间戳的视频剪辑一个输出文件名 ​​,并调用 启动 的方法 KeyClipWriter 。

否则,我们将不承担任何键/有趣的事件已经发生:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())

# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0

# keep looping
while True:
# grab the current frame, resize it, and initialize a
# boolean used to indicate if the consecutive frames
# counter should be updated
frame = vs.read()
frame = imutils.resize(frame, width=600)
updateConsecFrames = True

# blur the frame and convert it to the HSV color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# construct a mask for the color “green”, then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

# find contours in the mask
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use it
# to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
updateConsecFrames = radius <= 10

# only proceed if the redius meets a minimum size
if radius > 10:
# reset the number of consecutive frames with
# *no* action to zero and draw the circle
# surrounding the object
consecFrames = 0
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 0, 255), 2)

# if we are not already recording, start recording
if not kcw.recording:
timestamp = datetime.datetime.now()
p = “{}/{}.avi”.format(args[“output”],
timestamp.strftime(“%Y%m%d-%H%M%S”))
kcw.start(p, cv2.VideoWriter_fourcc(*args[“codec”]),
args[“fps”])

# otherwise, no action has taken place in this frame, so
# increment the number of consecutive frames that contain
# no action
if updateConsecFrames:
consecFrames += 1

# update the key frame clip buffer
kcw.update(frame)

# if we are recording and reached a threshold on consecutive
# number of frames with no action, stop recording the clip
if kcw.recording and consecFrames == args[“buffer_size”]:
kcw.finish()

# show the frame
cv2.imshow(“Frame”, frame)
key = cv2.waitKey(1) & 0xFF

# if the `q` key was pressed, break from the loop
if key == ord(“q”):
break
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# otherwise, no action has taken place in this frame, so
# increment the number of consecutive frames that contain
# no action
if updateConsecFrames:
consecFrames += 1

# update the key frame clip buffer
kcw.update(frame)

# if we are recording and reached a threshold on consecutive
# number of frames with no action, stop recording the clip
if kcw.recording and consecFrames == args[“buffer_size”]:
kcw.finish()

# show the frame
cv2.imshow(“Frame”, frame)
key = cv2.waitKey(1) & 0xFF

# if the `q` key was pressed, break from the loop
if key == ord(“q”):
break
如果没有有趣的事件已经发生,我们更新 consecFrames 并通过 框架 到我们的缓冲区。

101行提出了一个重要检查-如果我们 正在录制并达到足够数量的 连续帧 没有关键事件,那么我们就应该停止录音。

最后, 行105-110显示输出 帧 到我们的屏幕,并等待一个按键。

我们的代码最终块确保视频已成功关闭,然后执行位清理:

Saving key event video clips with OpenCVPython

# import the necessary packages
from pyimagesearch.keyclipwriter import KeyClipWriter
from imutils.video import VideoStream
import argparse
import datetime
import imutils
import time
import cv2

# construct the argument parse and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument(“-o”, “–output”, required=True,
help=”path to output directory”)
ap.add_argument(“-p”, “–picamera”, type=int, default=-1,
help=”whether or not the Raspberry Pi camera should be used”)
ap.add_argument(“-f”, “–fps”, type=int, default=20,
help=”FPS of output video”)
ap.add_argument(“-c”, “–codec”, type=str, default=”MJPG”,
help=”codec of output video”)
ap.add_argument(“-b”, “–buffer-size”, type=int, default=32,
help=”buffer size of video clip writer”)
args = vars(ap.parse_args())

# initialize the video stream and allow the camera sensor to
# warmup
print(“[INFO] warming up camera…”)
vs = VideoStream(usePiCamera=args[“picamera”] > 0).start()
time.sleep(2.0)

# define the lower and upper boundaries of the “green” ball in
# the HSV color space
greenLower = (29, 86, 6)
greenUpper = (64, 255, 255)

# initialize key clip writer and the consecutive number of
# frames that have *not* contained any action
kcw = KeyClipWriter(bufSize=args[“buffer_size”])
consecFrames = 0

# keep looping
while True:
# grab the current frame, resize it, and initialize a
# boolean used to indicate if the consecutive frames
# counter should be updated
frame = vs.read()
frame = imutils.resize(frame, width=600)
updateConsecFrames = True

# blur the frame and convert it to the HSV color space
blurred = cv2.GaussianBlur(frame, (11, 11), 0)
hsv = cv2.cvtColor(blurred, cv2.COLOR_BGR2HSV)

# construct a mask for the color “green”, then perform
# a series of dilations and erosions to remove any small
# blobs left in the mask
mask = cv2.inRange(hsv, greenLower, greenUpper)
mask = cv2.erode(mask, None, iterations=2)
mask = cv2.dilate(mask, None, iterations=2)

# find contours in the mask
cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]

# only proceed if at least one contour was found
if len(cnts) > 0:
# find the largest contour in the mask, then use it
# to compute the minimum enclosing circle
c = max(cnts, key=cv2.contourArea)
((x, y), radius) = cv2.minEnclosingCircle(c)
updateConsecFrames = radius <= 10

# only proceed if the redius meets a minimum size
if radius > 10:
# reset the number of consecutive frames with
# *no* action to zero and draw the circle
# surrounding the object
consecFrames = 0
cv2.circle(frame, (int(x), int(y)), int(radius),
(0, 0, 255), 2)

# if we are not already recording, start recording
if not kcw.recording:
timestamp = datetime.datetime.now()
p = “{}/{}.avi”.format(args[“output”],
timestamp.strftime(“%Y%m%d-%H%M%S”))
kcw.start(p, cv2.VideoWriter_fourcc(*args[“codec”]),
args[“fps”])

# otherwise, no action has taken place in this frame, so
# increment the number of consecutive frames that contain
# no action
if updateConsecFrames:
consecFrames += 1

# update the key frame clip buffer
kcw.update(frame)

# if we are recording and reached a threshold on consecutive
# number of frames with no action, stop recording the clip
if kcw.recording and consecFrames == args[“buffer_size”]:
kcw.finish()

# show the frame
cv2.imshow(“Frame”, frame)
key = cv2.waitKey(1) & 0xFF

# if the `q` key was pressed, break from the loop
if key == ord(“q”):
break

# if we are in the middle of recording a clip, wrap it up
if kcw.recording:
kcw.finish()

# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
112
113
114
115
116
117
118
# if we are in the middle of recording a clip, wrap it up
if kcw.recording:
kcw.finish()

# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()
视频简介结果

要生成关键事件(即绿球出现在我们的视频流),只需执行以下命令视频剪辑:

Saving key event video clips with OpenCVPython

$ python save_key_events.py –output output
1
$ python save_key_events.py –output output
我已经包含完整 1米分46秒的视频(无需解压突出剪辑)如下:

运行后 save_key_events 。PY 剧本,我现在有 4个输出视频,每一个时间绿球存在于我的视频流:

图3:创建每个有趣和关键事件一个独立的视频剪辑。
图3:创建每个有趣和关键事件一个独立的视频剪辑。
关键事件的视频片段显示如下,以证明我们的脚本工作正常,准确地提取我们的“有趣的事件”,基本建立了一系列的视频剪辑作为一个正常运作的 视频简介:

视频剪辑#1:

视频剪辑#2:

视频剪辑#3:

视频剪辑#4:

概要

在这篇博客中,我们学会了如何保存关键事件的视频剪辑使用的OpenCV和Python到文件。

究竟是什么定义“键或有趣的事件”是完全依赖于你的应用和你的整个项目的目标。的例子关键事件包括:

监控您的前门运动检测(即有人进入你的房子)。
认识到入侵者的面孔,因为他们进入你的房子。
报告你家到外面当局不安全驾驶。
同样,正是构成“关键事件”,是无止境的。但是,无论你如何定义一个有趣的事件,您仍然可以使用在这篇文章详细介绍了Python代码,以帮助挽救这些有趣的活动,以文件作为一个缩短的视频剪辑。

使用这种方法,就可以凝结 小时的 视频流素材到 秒有趣的活动,有效地产生一个的 视频简介 -全部使用Python,计算机视觉生成,图像处理技术。

无论如何,我希望你喜欢这篇博客文章!

如果你没有,请考虑分享它在您最喜爱的社交媒体渠道,如Facebook的,Twitter的,LinkedIn,等我把 大量的精力投入到过去两年的博客文章在这个系列,我真的很感激,如果你能帮助传播这个单词。

标签