import os
import cv2
path='/home/nlpr4/video-data/UCF-101/GolfSwing/v_GolfSwing_g24_c06.avi'
cap=cv2.VideoCapture(path)
video_length=int(cap.get(cv2.cv.CV_CAP_PROP_FRAME_COUNT))
success=True
count=0
while success:
success,image=cap.read()
if success==False:
break
count=count+1
print video_length,count
输出:
149
146
为什么两个数字不同? 怎么了?
CAP_PROP_FRAME_COUNT
的 get() 永远不应该是准确的!如果你检查opencv源代码。你可以找到这个:
int64_t CvCapture_FFMPEG::get_total_frames() const
{
int64_t nbf = ic->streams[video_stream]->nb_frames;
if (nbf == 0)
{
nbf = (int64_t)floor(get_duration_sec() * get_fps() + 0.5);
}
return nbf;
}
这意味着它将首先查看流标头中的
nb_frames
,您可以使用 ffprobe 检查。如果没有这样的字段,那么没有比直接解码视频更好的获取帧号的方法了。 opencv 通过 get_duration_sec() * get_fps() + 0.5
进行了粗略估计,这肯定不意味着准确。
因此,要获得正确的帧号,您必须解码并读取整个流,或者您必须要求视频生成器生成带有
nb_frames
字段的正确流标头。
不幸的是,近 10 年后 opencv 仍然没有纠正实现:我们应该使用
av_read_frame(fmt_ctx, &pkt)
来读取和解析所有数据包,而不需要实际解码它们。
我个人在十多年前就不再依赖opencv进行视频解码了,但最近我不得不与一些使用opencv的项目合作来这样做。我必须在子进程中调用 ffprobe 才能获得正确的帧计数:
ffprobe -v error -select_streams v:0 -count_packets -show_entries stream=nb_read_packets -of csv=p=0 input.mp4
CV_CAP_PROP_FRAME_COUNT
给出来自视频标题的“帧数”属性。另一个数字基本上是“我可以从这个视频文件中读取多少帧?”。
如果视频包含无法读取/解码的帧(例如,由于损坏),OpenCV 会跳过这些帧(在尝试读取它们之后)并为您提供下一个有效帧。所以你的两个数字之间的差异就是无法读取的帧数。
此外,如果您的视频标头已损坏和/或无法被 OpenCV 使用的底层编解码器解析,那么这些数字也可能不同。
试试这个代码:
#!/usr/bin/env python
import numpy as np
import cv2
video = "../videos/sample.avi"
video_capture = cv2.VideoCapture(video)
video_length = int(video_capture.get(cv2.CAP_PROP_FRAME_COUNT))
count = 0
while(True):
# Capture frame-by-frame
ret, frame = video_capture.read()
if not ret:
break
count += 1
print video_length, count
# When everything done, release the capture
video_capture.release()
cv2.destroyAllWindows()
在我的机器上它给了我:
$ ./openstack_video_frames.py
1232 1232