前几天做实验的时候,用到了opencv-python读视频并进行检测。
用的就是传统的一样的方法,cv2.VideoCapture(video_path),read()方法读取一帧,然后再把读到帧送入检测器,此处贴一部分代码上去。
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
while True:
ret, frame = capture.read()
if not ret:
break
results = detector.predict(frame)
cv2.waiiKey(-1)
但是这样存在一些问题, 在特定的应用上每帧都检测的话,时间效率上很差。
于是我对代码进行了一些改进,设定每秒检测一次。
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
fps = capture.get(cv2.CAP_PROP_FPS) # 视频的帧率FPS
total_frame = capture.get(cv2.CAP_PROP_FRAME_COUNT) # 视频的总帧数
for i in range(int(total_frame)):
ret, frame = capture.read()
if not ret:
break
if i % fps == 0:
results = detector.predict(frame)
cv2.waitKey(-1)
这样修改之后,每秒会选取一帧进行检测,速度明显快了许多。但是呢,自己又测试了一下,这样大部分的时间都会浪费在读视频帧的过程中。
例如:我的视频是30FPS,也就是说每30帧取出来1帧进行检测,这就浪费了29帧的读取时间。
还样的方式还是太耗时,于是再次进行了一波改进:
read函数其实是grab和retrieve函数的结合
–grab函数 捕获下一帧
–retrieve函数 对该帧进行解码
思路就是:只捕获,但是不解码,对于需要的帧再进行解码。
附上我参考的博客:
read、grab、retrieve函数详细解释
import cv2
video_path = "F:/1/1.mp4"
capture = cv2.VideoCapture(video_path)
fps = capture.get(cv2.CAP_PROP_FPS) # 视频的帧率FPS
total_frame = capture.get(cv2.CAP_PROP_FRAME_COUNT) # 视频的总帧数
for i in range(int(total_frame)):
ret = capture.grab()
if not ret:
print("Error grabbing frame from movie!")
break
if i % fps == 0:
ret, frame = capture.retrieve()
if ret:
results = detector.predict(frame)
else:
print("Error retrieving frame from movie!")
break
cv2.waitKey(-1)
这样,速度就更快了。
此外,还有一个方法是人为设定读取的帧数,利用set函数,但是在测试中,有的视频无法读取帧。就只简单附在后面,供大家参考吧。
i = 100 # 人为设定要读取的视频帧,从0开始计数
capture.set(cv2.CAP_PROP_POS_FRAMES, i)
ret, frame = capture.read()