【问题标题】:OpenCV VideoCapture: Howto get specific frame correctly?OpenCV VideoCapture:如何正确获取特定帧?
【发布时间】:2015-09-23 08:18:43
【问题描述】:

我正在尝试使用 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 文件,找到的两个帧只是略有偏差?

有没有人有这方面的经验,可以解释我的发现并告诉我从视频文件中获取特定帧的正确方法?

【问题讨论】:

  • 我不是这方面的专家,但我怀疑这个问题根本不是错误。检查您的视频文件是否包含索引。如果不是,那么直接倒回到任何位置(不处理之前的所有帧)只是比特率的平均估计。因此,该例程估计从文件开始帧的距离,然后围绕该位置扫描关键帧块。这可能会很多......

标签: c++ opencv video video-capture


【解决方案1】:

我认为 OpenCV 使用FFmpeg 进行视频解码。

我们曾经遇到过类似的问题,但是直接使用了FFmpeg。默认情况下,不保证随机(但精确)帧访问。 WMV 解码器特别模糊。 较新版本的 FFmpeg 允许您访问可用于构建帧检索功能的较低级别的例程。这个解决方案有点复杂,我现在什么都记不起来了。我稍后会尝试找到更多详细信息。

作为一种快速解决方法,我建议您离线解码您的视频,然后处理图像序列。虽然这增加了所需的存储量,但它保证了精确的随机帧访问。你可以像这样使用 FFmpeg 来convert your video file in to a sequence of images

ffmpeg -i "input.mov" -an -f image2 "output_%05d.png"

【讨论】:

  • 是不是还是不能使用OpenCV提取特定帧?
【解决方案2】:

显然opencv/ffmpeg 中还有一个bug。 ffmpeg 不提供所需的帧和/或 opencv 不处理此问题。请参阅herehere

[编辑: 在修复该错误之前(在 ffmpeg 中或(作为 opencv 中的解决方法)),按数字获取精确帧的唯一方法是像您一样“快进”。 (关于 VLC 播放器:我怀疑它使用了那个有问题的 set () 接口。对于播放器来说,寻找精确帧通常不太重要。但对于编辑器来说,它是)。]

【讨论】:

  • 您错过了重点:不允许将 cmets 作为答案发布。场外链接也只能回答......您的最后一次编辑使事情变得更好,删除过程已经结束,有利于不删除您的帖子。
猜你喜欢
  • 2016-02-05
  • 2016-02-12
  • 2021-12-28
  • 2016-11-06
  • 1970-01-01
  • 1970-01-01
  • 2020-02-25
  • 1970-01-01
相关资源
最近更新 更多