关于VideoCapture.read()视频未读完整问题

关于VideoCapture.read()视频未读完整问题

本篇简要说明OpenCV中VideoCapture类的相关问题,可以解决一些 如视频文件可以正常使用播放器播放,但不能使用OpenCV完整获取每一帧的情况.

一、对于OpenCV中的VideoCapture类的简单说明

VideoCapture既支持从视频文件(.mp4/.avi /.mpg/...)读取,也支持直接从摄像机(比如电脑自带摄像头)中读取,要想获取视频需要先创建一个VideoCapture对象,

1. Python示例

# Python 对视频的读取
import cv2  # pip install opencv-python
cap = cv2.VideoCapture("./test_video.mp4")
ret,frame = cap.read()

2. C++示例

// C++ 对视频读取
cv::VideoCapture capture("./test_video.mp4"); 
cv::Mat frame;  
// 方法一 
capture.read(frame); 
// 方法二 
capture.grab(); 
// 方法三
capture.retrieve(frame); 
// 方法四
capture >> frame;

二、VideoCapture.read()的原理分析

以C++代码为例,当我们使用OpenCV的function去读取视频的时候,经常使用的就是 VideoCapture::read() 函数: [1]

VideoCapture::read()
该函数结合VideoCapture::grab()和VideoCapture::retrieve(),
用于捕获、解码和返回下一个视频帧这是一个最方便的函数对于读取视频文件或者捕获数据从解码和返回刚刚捕获的帧,假如没有视频帧被捕获(相机没有连接或者视频文件中没有更多的帧)将返回False。

那么 VideoCapture::grab() 和 VideoCapture::retrieve() 又是干什么用的?

VideoCapture::grab()
从视频文件或捕获设备中抓取下一个帧,返回值为布尔型,如果调用成功则返回True。
VideoCapture::retrieve()
解码并且返回的是 抓取的当前视频帧 ,如果此时没有视频帧被捕获(相机没有连接或者视频文件中没有更多的帧)将返回False。

也就是说,当我们使用read()去读取视频的时候,会做两个判断:

  • 一是获取当前的视频帧
  • 二是指定下一帧,并判断能否读取

然而某些视频文件由于种种编码问题,导致部分帧“损坏”,判断下一帧的时候,返回值为False,从而不能进行视频读取。此时,我们可以换一种思路,就是 指定帧 读取。

cv::VideoCapture capture("./test_video.mp4"); 
int frameToStart = 25 //指定第25帧
Mat frame;