OpenCV视频捕获:如何正确获取特定帧
OpenCV VideoCapture: Howto get specific frame correctly?
我正试图使用OpenCV 2.4.11从视频文件中获取特定帧。我试着按照文档和在线教程正确操作,现在已经测试了两种方法:
1( 第一种方法是使用video.grab((暴力读取每一帧,直到我到达我想要的特定帧(时间戳(。如果特定帧在视频序列中较晚,则此方法会很慢!
string videoFile(videoFilename);
VideoCapture video(videoFile);
double videoTimestamp = video.get(CV_CAP_PROP_POS_MSEC);
int videoFrameNumber = static_cast<int>(video.get(CV_CAP_PROP_POS_FRAMES));
while (videoTimestamp < targetTimestamp)
{
videoTimestamp = video.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = static_cast<int>(video.get(CV_CAP_PROP_POS_FRAMES));
// Grabe frame (but don't decode the frame as we are only "Fast forwarding")
video.grab();
}
// Get and save frame
if (video.retrieve(frame))
{
char txtBuffer[100];
sprintf(txtBuffer, "Video1Frame_Target_%f_TS_%f_FN_%d.png", targetTimestamp, videoTimestamp, videoFrameNumber);
string imgName = txtBuffer;
imwrite(imgName, frame);
}
2( 第二种方法我使用video.set(…(。这种方法更快,如果特定帧在视频序列中较晚,似乎不会更慢。
string videoFile(videoFilename);
VideoCapture video2(videoFile);
videoTimestamp = video2.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = static_cast<int>(video2.get(CV_CAP_PROP_POS_FRAMES));
video2.set(CV_CAP_PROP_POS_MSEC, targetTimestamp);
while (videoTimestamp < targetTimestamp)
{
videoTimestamp = video2.get(CV_CAP_PROP_POS_MSEC);
videoFrameNumber = (int)video2.get(CV_CAP_PROP_POS_FRAMES);
// Grabe frame (but don't decode the frame as we are only "Fast forwarding")
video2.grab();
}
// Get and save frame
if (video2.retrieve(frame))
{
char txtBuffer[100];
sprintf(txtBuffer, "Video2Frame_Target_%f_TS_%f_FN_%d.png", targetTimestamp, videoTimestamp, videoFrameNumber);
string imgName = txtBuffer;
imwrite(imgName, frame);
}
问题(现在的问题是,使用这两种方法确实会导致相同帧数的目标图像的内容帧数不相等?!?
我很想得出结论,方法1是正确的,OpenCV video.set(…(方法有问题。但是,如果我使用VLC播放器找到近似的目标帧位置,那么实际上是方法2最接近"正确"的结果?
作为一些额外的信息:我测试了相同的视频序列,但在两个不同的视频文件中分别用"avc1"MPG4和"wmv3"WMV编解码器编码。
使用WMV文件,找到的两个帧相差甚远?
使用MPG4文件,找到的两个帧只是略有偏离?
有没有人对此有一定的经验,可以解释我的发现,并告诉我从视频文件中获取特定帧的正确方法?
显然opencv/ffmpeg中仍然存在一个错误。ffmpeg无法提供所需的帧,和/或opencv无法处理此问题。看看这里和这里。
[编辑:在这个错误被修复之前(无论是在ffmpeg中,还是在opencv中(,按数字获取确切帧的唯一方法就是像以前一样"快进"。(关于VLC播放器:我怀疑它使用了那个bug集((-接口。对于玩家来说,寻找准确的帧通常并不太重要。但对于编辑来说,这是(。]
我认为OpenCV使用FFmpeg进行视频解码。
我们曾经遇到过类似的问题,但直接使用了FFmpeg。默认情况下,不能保证随机(但精确(帧访问。WMV解码器特别模糊。FFmpeg的较新版本允许您访问较低级别的例程,这些例程可用于构建帧的检索功能。这个解决方案有点复杂,我现在记不清了。我稍后会设法找到更多的细节。
作为一种快速解决方案,我建议离线解码视频,然后处理图像序列。尽管这增加了所需的存储量,但它保证了精确的随机帧访问。您可以使用FFmpeg将您的视频文件转换为如下图像序列:
ffmpeg -i "input.mov" -an -f image2 "output_%05d.png"
- 为什么我的for循环不能正确获取argv
- 如何在C++中获取 std::u8string 的正确长度?
- 如何在给定时钟偏移的情况下正确获取时间
- 如何在 c++ 中正确从正整数中获取偶数和奇数?
- 如何以正确的时区从XTS索引中获取数字时间?
- c++ 使用复杂的依赖项获取正确的转发声明
- 如何在Vxworks中正确运行时钟获取时间以获得准确的时间
- 如何正确获取 Unicode 窗口标题
- 尝试获取矩阵的正确对角线会导致"vector out of range"错误
- 获取Windows版本的正确方法
- 如何正确使用 libvlc (C++) 从 h264 视频流中获取帧
- 如何获取正确的线程 ID 和值
- 从 SIOCGIFCONF 和 SIOCGIFADDR 获取的 Solaris SPARC 中虚拟接口的接口名称不正确
- 我的代码有什么问题以获取正确的梯度
- C 数组未从文件中获取正确的输入
- 获取函数正确执行的问题
- 使用Arduino Due从MPU-6050获取/处理正确的值U
- getline() 获取不正确的字符
- 使用stat api获取不正确的文件修改时间
- 使用不同类中的类对象获取不正确的数据