我们使用Opencv读取视频时,常规的做法是使用read()函数逐帧读取,如
import cv2
cap = cv2.VideoCapture("./test.mp4")
while True:
# read a frame
ret, frame = cap.read()
if not ret:
break
# do something else
...
cap.release()
但是在图像处理时,并不需要逐帧处理,而是抽样的方式,这种情况下每一帧都读取会造成计算资源的浪费。查看Opencv的文档,会发现有这么几个函数介绍
virtual bool read (OutputArray image)
Grabs, decodes and returns the next video frame. More...
virtual bool grab ()
Grabs the next frame from video file or capturing device. More...
virtual bool retrieve (OutputArray image, int flag=0)
Decodes and returns the grabbed video frame. More...
可以看出,read函数其实是grab和retireve函数的组合,grap是跳转到下一帧的位置,而retrieve是做具体的解码工作。显而易见,单纯的跳转要比解码快的多,所以我们不妨修改以下代码,假如抽样频率是5
import cv2
cap = cv2.VideoCapture("./test.mp4")
idx = 0
freq = 5
While True:
idx += 1
ret = cap.grab()
if not ret:
break
if idx % freq == 1:
continue
ret, frame = cap.retrieve()
if frame is None: # exist broken frame
break
# do something else
...
cap.release()
读取速度会变成之前的1/5。
virtual bool read (OutputArray image)
Grabs, decodes and returns the next video frame. More...
virtual bool grab ()
Grabs the next frame from video file or capturing device. More...
virtual bool retrieve (OutputArray image, int flag=0)
Decodes and returns the grabbed video frame. More...
但是对于超大的视频,这样单线程的读取方式还是不够快,因此可以考虑多线程同时读取,以加速处理速度
def process_video(self, start_frame, length):
cap = cv2.VideoCapture("./test.mp4")
cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame)
freq = 5
for idx in range(length):
ret = cap.grab()
if not ret:
break
if idx % freq == 0:
continue
ret, frame = cap.retrieve()
if frame is None: # exist broken frame
break
# do something else
...
cap.release()
在通过
frames_num = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
获取视频的总帧数,就可以平均分N个线程来处理视频了。
博客介绍了如何使用OpenCV优化视频处理速度。通过理解`grab()`和`retrieve()`函数的区别,实现按固定频率抽帧以减少计算资源浪费。此外,提出使用多线程技术并行处理视频帧,进一步提升处理效率。这种方法尤其适用于处理大型视频文件。

919

被折叠的 条评论
为什么被折叠?



