一、问题描述
在深度学习场景中,面对相对开放的场景,我们经常会需要处理长时间的视频,而花费叫长的时间,就让人头疼。比如为了获取一个厂/小区的所有摄像头下一周的画面背景,当然其极高的同质性也不可能每一帧画面都获取,就需要一种快速的间隔帧抽帧方案。
为了优化读取图片的速度,经过调研研究后,可将图片的获取分为两个阶段:读取 ,解码,分别对应opencv的VideoCapture函数的grab()和retrieve()两个子函数。实验证明可以有效的加快视频画面的抽取效率。具体的实验代码如下。
二、视频抽帧处理代码
import cv2
import os
import time
import threading
import random
def readAll_by_grab(video_file_path):
videRead = cv2.VideoCapture(video_file_path)
while True:
tag = videRead.grab()
if not tag:
break
ret, frame = videRead.retrieve()
time.sleep(0.01)
videRead.release()
def readAll_by_cvread(video_file_path):
videRead = cv2.VideoCapture(video_file_path)
while True:
tag, frame = videRead.read()
if not tag:
break
time.sleep(0.01)
videRead.release()
def read_by_grab(video_file_path):
videRead = cv2.VideoCapture(video_file_path)
fps = videRead.get(cv2.CAP_PROP_FPS)
idx = 0
choose_idx = random.randint(0, fps)
while True:
idx += 1
tag = videRead.grab()
if not tag:
break
if idx % fps == choose_idx:
ret, frame = videRead.retrieve()
time.sleep(0.01)
videRead.release()
def read_by_cvread(video_file_path):
videRead = cv2.VideoCapture(video_file_path)
fps = videRead.get(cv2.CAP_PROP_FPS)
idx = 0
choose_idx = random.randint(0, fps)
while True:
tag, frame = videRead.read()
if not tag:
break
if idx % fps == choose_idx:
time.sleep(0.01)
videRead.release()
if __name__ == '__main__':
'''
readAll_by_grab: 耗时: 45.87809038162231
readAll_by_cvread: 耗时: 45.898966550827026
read_by_grab: 耗时: 11.92901349067688
read_by_cvread: 耗时: 17.04421854019165
'''
video_file_path = r'd:\Data\trash\test_louyou_06112\16-26-29.avi'
for way in [readAll_by_grab, readAll_by_cvread, read_by_grab, read_by_cvread]:
start_time = time.time()
way(video_file_path)
print(time.time() - start_time)
三、进阶采用多线程进行加速推理
import cv2
import os
import time
import threading
import random
def threading_operate(threads_nums, index, video_file_path):
videRead = cv2.VideoCapture(video_file_path)
fps = videRead.get(cv2.CAP_PROP_FPS)
idx = 0
choose_idx = random.randint(0, 25)
while True:
tag = videRead.grab()
if not tag:
break
if idx % (threads_nums * fps) == (choose_idx + fps * index):
ret, frame = videRead.retrieve()
time.sleep(0.01)
videRead.release()
def video_by_grad_threads(video_file_path):
threads_nums = 2
threads = []
for index in range(threads_nums):
t = threading.Thread(target=threading_operate, args=[threads_nums, index, video_file_path]) # 传个任务,和参数进来
t.start() # 线程开始
threads.append(t)
for t in threads:
t.join()
if __name__ == '__main__':
'''
video_by_grad_threads: 耗时: 10.581750392913818
'''
video_file_path = r'd:\Data\trash\test_louyou_06112\16-26-29.avi'
start_time = time.time()
way(video_file_path)
print(time.time() - start_time)