我想從使用OpenCV 2.4.11的視頻文件獲取特定幀。 我試圖按照正確的文檔和在線教程,現在已經測試了兩種方法:OpenCV VideoCapture:如何正確獲取特定幀?
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文件兩個找到的幀只是稍微關閉?
有沒有人有這方面的經驗,可以解釋我的發現並告訴我從視頻文件中獲取特定幀的正確方法?
我不是這方面的專家,但我懷疑問題根本不是問題。檢查您的視頻文件是否包含索引。如果不是,那麼直接倒回到任何位置(不處理它之前的所有幀)只是比特率的平均估計。所以例程會估計文件從幀開始會有多少距離,然後圍繞關鍵幀塊的位置進行掃描。這可以是很多... – Spektre