【python】OpenCV—Faster Video File FPS

在这里插入图片描述

1、需求描述

使用线程和队列数据结构将视频文件的 FPS 速率提高 !

我们的目标是将视频文件帧的读取和解码移动到程序的一个完全独立的线程中,释放我们的主线程来处理实际的图像处理。

2、正常方法 cv2.read

import datetime

# class FPS:
# 	def __init__(self):
# 		# 存储开始时间、结束时间和在开始和结束间隔之间检查的帧总数
# 		self._start = None
# 		self._end = None
# 		self._numFrames = 0
#
# 	def start(self):
# 		# 开始计时器
# 		self._start = datetime.datetime.now()
# 		return self
#
# 	def stop(self):
# 		# 停止计时器
# 		self._end = datetime.datetime.now()
#
# 	def update(self):
# 		# 增加在开始和结束间隔期间检查的总帧数
# 		self._numFrames += 1
#
# 	def elapsed(self):
# 		# 返回开始和结束间隔之间的总秒数
# 		return (self._end - self._start).total_seconds()
#
# 	def fps(self):
# 		# 计算每秒(近似)帧数
# 		return self._numFrames / self.elapsed()


# import the necessary packages
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import cv2
# 构造参数解析器并解析参数
ap = argparse.ArgumentParser()
# 解析我们的命令行参数。对于这个脚本,我们只需要一个开关 --video ,它是我们输入视频文件的路径。
ap.add_argument("-v", "--video", default="1.mp4",
	help="path to input video file")
args = vars(ap.parse_args())
# 打开一个指向视频流的指针,并启动FPS定时器
stream = cv2.VideoCapture(args["video"])
fps = FPS().start()  # 启动一个我们可以用来测量 FPS 的计时器

# 循环视频文件流中的帧
while True:
	# 从线程视频文件流中抓取帧
	(grabbed, frame) = stream.read()
	# 如果帧没有被抓取,那么我们已经到达了流的末尾
	if not grabbed:
		break
	# 调整帧大小并将其转换为灰度(同时仍保留 3 个通道)
	frame = imutils.resize(frame, width=450)
	frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	frame = np.dstack([frame, frame, frame])
	# 在图像中显示一段文本(这样我们就可以公平地对快速方法进行基准测试)
	cv2.putText(frame, "Slow Method", (10, 30),
		cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
	# 显示帧并更新 FPS 计数器
	cv2.imshow("Frame", frame)
	cv2.waitKey(1)
	fps.update()

# 停止定时器,显示FPS信息
fps.stop()
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
# 做一些清理工作
stream.release()
cv2.destroyAllWindows()

output

[INFO] elasped time: 13.08
[INFO] approx. FPS: 29.27

在这里插入图片描述

3、加速方法 imutils.video.FileVideoStream

# 导入必要的包
from imutils.video import FileVideoStream
from imutils.video import FPS
import numpy as np
import argparse
import imutils
import time
import cv2

# 构造参数解析并解析参数
ap = argparse.ArgumentParser()
ap.add_argument("-v", "--video", default="1.mp4",
                help="path to input video file")
args = vars(ap.parse_args())
# 启动文件视频流线程并允许缓冲区开始填充
print("[INFO] starting video file thread...")
fvs = FileVideoStream(args["video"]).start()
time.sleep(1.0)
# 启动 FPS 计时器
fps = FPS().start()

# 循环播放视频文件流中的帧
while fvs.more():
    # 从线程视频文件流中抓取帧,调整大小,并将其转换为灰度(同时仍保留 3 个通道)
    frame = fvs.read()
    try:
        frame = imutils.resize(frame, width=450)
    except:
        break
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    frame = np.dstack([frame, frame, frame])
    # 在frame上显示队列的大小
    cv2.putText(frame, "Queue Size: {}".format(fvs.Q.qsize()),
                (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
    # 显示帧并更新 FPS 计数器
    cv2.imshow("Frame", frame)
    cv2.waitKey(1)
    fps.update()

# 停止计时器并显示 FPS 信息
fps.stop()
print("[INFO] elasped time: {:.2f}".format(fps.elapsed()))
print("[INFO] approx. FPS: {:.2f}".format(fps.fps()))
# 做一些清理工作
cv2.destroyAllWindows()
fvs.stop()

output

[INFO] starting video file thread...
[INFO] elasped time: 8.87
[INFO] approx. FPS: 43.19

在这里插入图片描述

帧率从30-提升到了40+

确实有效

4、涉及到的核心库函数

4.1、imutils.video.FPS

import datetime

class FPS:
	def __init__(self):
		# 存储开始时间、结束时间和在开始和结束间隔之间检查的帧总数
		self._start = None
		self._end = None
		self._numFrames = 0

	def start(self):
		# 开始计时器
		self._start = datetime.datetime.now()
		return self

	def stop(self):
		# 停止计时器
		self._end = datetime.datetime.now()

	def update(self):
		# 增加在开始和结束间隔期间检查的总帧数
		self._numFrames += 1

	def elapsed(self):
		# 返回开始和结束间隔之间的总秒数
		return (self._end - self._start).total_seconds()

	def fps(self):
		# 计算每秒(近似)帧数
		return self._numFrames / self.elapsed()

4.2、imutils.video.FileVideoStream

# import the necessary packages
from threading import Thread
import sys
import cv2

# 从 Python 3 导入 Queue 类
if sys.version_info >= (3, 0):
    from queue import Queue
# 否则,为 Python 2.7 导入 Queue 类
else:
    from Queue import Queue

class FileVideoStream:
    def __init__(self, path, queueSize=128):
        # 初始化文件视频流以及用于指示线程是否应该停止的布尔值
        self.stream = cv2.VideoCapture(path)
        self.stopped = False
        # 初始化存储视频文件帧的队列
        self.Q = Queue(maxsize=queueSize)
    def start(self):
        # 启动一个线程从文件视频流中读取帧
        t = Thread(target=self.update, args=())
        t.daemon = True
        t.start()
        return self
    def update(self):
        # 循环
        while True:
            # 如果设置了线程指示器变量,则停止线程
            if self.stopped:
                return
            # 否则,请确保队列中有空间
            if not self.Q.full():
                # 从文件中读取下一帧
                (grabbed, frame) = self.stream.read()
                # 如果 grabbed 布尔值为 False,那么我们已经到了视频文件的末尾
                if not grabbed:
                    self.stop()
                    return
                # 将帧添加到队列中
                self.Q.put(frame)
    def read(self):
        # 返回队列中的下一帧
        return self.Q.get()
    def more(self):
        # 如果队列中还有帧,则返回 True
        return self.Q.qsize() > 0
    def stop(self):
        # 指示应该停止线程
        self.stopped = True

5、参考

参考学习来自:

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值