python - 如何通过opencv不间断地读取视频中的所有帧
问题描述
我写了这段代码来从视频中提取所有帧并保存为图像。但是不知何故 VideoCapture.read() 即使没有到达结束帧,也会返回 false 。
如何修复它并读取所有帧?
我试过捕捉异常,但它什么也没返回。
我跟踪了源代码,发现 VideoCaputre.read() 调用 VideoCapture.grab,这称为 icap->grabFrame(),但无法获取有关 icap->grabFrame() 的详细信息。
python3.6.7(默认,2018 年 10 月 22 日,11:32:17) Opencv 3.4.3 Google Colaboratory
视频信息 'coded_width': 4000 'coded_height': 3000 'r_frame_rate': '30000/1001' 'avg_frame_rate': '30000/1001'
import os
import ffmpeg
import json
import cv2
import sys
base_dir = './gdrive/My Drive/'
files = os.listdir(base_dir)
# only videos
mp4s =[]
mp4s = [file for file in files if 'MP4' in file ]
# get metadata
file_list = []
for video in mp4s:
video_dir = base_dir + '/' + video
video_info = ffmpeg.probe(video_dir)
time = video_info['streams'][0]['tags']['creation_time']
slice_str = time.find('T')
slice_end = time.find('.')
file_list.append({
'file_name':video,
'start_rec':time[slice_str + 1:slice_end],
'end_rec':video_info['streams'][0]['tags']['timecode'],
'duration':video_info['streams'][0]['duration'],
'nb_frames':video_info['streams'][0]['nb_frames'],
'coded_width':video_info['streams'][0]['coded_width'],
'coded_height':video_info['streams'][0]['coded_height'],
'r_frame_rate':video_info['streams'][0]['r_frame_rate'],
'avg_frame_rate':video_info['streams'][0]['avg_frame_rate']
})
#sort by recording start time
list_sorted = sorted(file_list, key=lambda x:x['start_rec'])
print(list_sorted)
#opencv extract all frames and save as png
dir_path = base_dir + '/' + 'images'
basename ='intervention'
ext = 'png'
n = 0
for dic in list_sorted:
print('start', dic['file_name'])
video_path = base_dir + '/' + dic['file_name']
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print('not opened')
sys.exit()
os.makedirs(dir_path, exist_ok=True)
base_path = os.path.join(dir_path, basename)
digit = len(str(int(cap.get(cv2.CAP_PROP_FRAME_COUNT))))
# below this code ret supposed to be true until the end frame but did't reach the end
while True:
ret, frame = cap.read()
print('ret=', ret)
print(cap.get(cv2.CAP_PROP_POS_FRAMES), '/', cap.get(cv2.CAP_PROP_FRAME_COUNT))
if ret:
cv2.imwrite('{}_{}.{}'.format(base_path, str(n).zfill(digit), ext), frame)
n += 1
else:
print('done', dic['file_name'])
cap.release()
cv2.destroyAllWindows()
break
这是返回的
开始 GX010223.MP4 ret= True 1.0 / 96.0 ~ ret= True 96.0 / 96.0 ret= False 96.0 / 96.0 完成 GX010223.MP4 开始 GX010224.MP4 ret= True 1.0 / 105.0 ~ ret= True 105.0 / 105.0 ret= False 105.0完成 GX010224.MP4
开始 GX010225.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX010225.MP4
开始 GX020225.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX020225.MP4
开始 GX030225.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX030225.MP4
开始 GX040225.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX040225.MP4
开始 GX050225.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX050225.MP4
开始 GX060225.MP4 ret= True 1.0 / 539.0 ~ ret= True 29.0 / 539.0 ret= False 29.0 / 539.0 完成 GX060225.MP4
开始 GX010226.MP4 ret= True 1.0 / 282.0 ~ ret= True 29.0 / 282.0 ret= False 29.0 / 282.0 完成 GX010226.MP4
开始 GX010227.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX010227.MP4
开始 GX020227.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX020227.MP4
开始 GX030227.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX030227.MP4
开始 GX040227.MP4 ret= True 1.0 / 15960.0 ~ ret= True 29.0 / 15960.0 ret= False 29.0 / 15960.0 完成 GX040227.MP4
开始 GX050227.MP4 ret= True 1.0 / 2514.0 ~ ret= True 29.0 / 2514.0 ret= False 29.0 / 2514.0 完成 GX050227.MP4
我试图通过这段代码检查“它是否为空”
while True:
ret, frame = cap.read()
print('ret=', ret)
print(cap.get(cv2.CAP_PROP_POS_FRAMES), '/', cap.get(cv2.CAP_PROP_FRAME_COUNT))
cv2.imwrite('{}_{}.{}'.format(base_path, str(n).zfill(digit), ext), frame)
n += 1
if ret == False:
if frame == None:
print('done', dic['file_name'])
cap.release()
cv2.destroyAllWindows()
break
但是当 cap.read() 失败时,它返回 None 对象,所以它不能正常工作。
解决方案
VideoCapture cap("your_video.avi");
if(!cap.isOpened()) // check if we succeeded
return -1;
Mat frame;
while(1) // looply reading frames from the video file
{
cap >> frame; // try to get an image frame
if (frame.empty())
{
// reach to the end of the video file
break;
}
}
frame.empty() 将解决您的问题。它在 c++ 中,但在 python 中可能相同。
推荐阅读
- regex - 如何在 Google Data Studio 中提取特定文本?
- c++ - 如何在 C++ 中映射多个值?
- javascript - 在 AngularJS 模态模板中显示更多和隐藏细节
- google-sheets - 将 Google 表格列拆分为行 - 忽略任何空白
- sql-server - 使用链接服务器连接 Analysis Services 多维数据集时出错
- java - 使用 Thymeleaf (Java) 读取布尔值的问题
- c++ - 循环中用户输入的总和
- java - 在 JFrame 具有背景时添加带有时间和日期的状态栏
- azure - 如何在 Azure 门户中查看/编辑用户声明中的值
- r - 求解 R 中的三对角幂矩阵