歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

設定cvSetCaptureProperty後取幀不准的問題

最近剛剛開始學習opencv,在用到cvSetCaptureProperty函數設定從視頻指定幀的位置開始讀取幀的時候遇到一個問題如下:

我設定cvSetCaptureProperty從指定的幀數 pos 開始讀取,比如pos設定為20,想從視頻裡面取出第二十幀,可是取出來的時候卻不是第二十幀,而是亂的幀數,,有時候是23,有時候是18,具體數值根據不同的視頻不一樣。

小弟寫了一個測試的代碼如下。程序運行的環境是WINDOWS XP+opencv2.1+vs2008,pos和pos1分別代表我設定的幀數和通過cvSetCaptureProperty過後的得到的幀數的下一幀。本來應該是pos和pos1都是遞增的,但是程序的結果是pos遞增,pos1確是亂的。

可是當我將程序放到WINDOWS XP+opencv1.0+vc6.0環境下運行時卻能得出正確的結果,即pos和pos1都是遞增的。

於是我又換了幾台電腦測試,結果都和上面的一樣。

我的問題是:這是不是opencv2.1或者vs2008的問題?

這個問題讓小弟苦惱了好幾天了,也到處查了資料,看到sourceforge上面有人報告opencv2.1裡面cvSetCaptureProperty的bug
問題和小弟的差不多,但是沒有人回答。

--------------------------------------------------------------------------------
#include "highgui.h"
#include <iostream>
using namespace std;
int main( int argc, char** argv )
{
   cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE );
   CvCapture* capture = cvCreateFileCapture( "d://11.avi" );
   IplImage* frame;

   int pos=0;
   int pos1=0;
   while(1)
   {
      cvSetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES,pos);
      cout<<pos;
      frame = cvQueryFrame(capture);

      pos1=cvGetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES);
      cout<<"\t"<<pos1<<endl;

      if( !frame ) break;
      cvShowImage( "Example2", frame );
      char c = cvWaitKey(33);
      if( c == 27 ) break;

      pos++;
   }
   cvReleaseCapture( &capture );
   cvDestroyWindow( "Example2" );
}

--------------------------------------------------------------------------------

這個問題找到原因了。
以前在opencv 2.0裡面用到cvSetCaptureProperty函數的時候總是發生定位不准確的問題,明明是讓其跳到100幀,結果卻總不是100幀,定位一段連續的視頻,總是出現跳躍的現象。同樣的代碼在opencv1.0裡面完全沒錯。可是這是為什麼?這個問題一直困擾了我半年,終於在今天知道原因了。

經過差不多一晚上的探究,得出粗略的結論。原因在於opencv2.0以後,采用ffmpeg采集視頻,而在opencv1.0采用vfw采集視頻(具體的概念暫時還不清楚,有時間繼續補上)。而opencv在定位時候,調用的ffmpeg的av_seek_frame()函數,此函數原型為:

int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);

其中,最後一個參數有

AVSEEK_FLAG_BACKWARD = 1; ///< seek backward
AVSEEK_FLAG_BYTE = 2; ///< seeking based on position in bytes
AVSEEK_FLAG_ANY = 4; ///< seek to any frame, even non key-frames

ffmpeg默認的是選取關鍵幀(這個概念需要具體定義)。opencv裡面這個函數的參數flag是0,

int ret = av_seek_frame(ic, video_stream, timestamp, 0);

也就是按照默認的讀取關鍵幀。因此,視頻跳躍就出現了。

解決這個問題需要將0改為 AVSEEK_FLAG_ANY ,即:

int ret = av_seek_frame(ic, video_stream, timestamp, AVSEEK_FLAG_ANY );

之後重新編譯opencv庫,就可以了。http://www.linuxidc.com/Linux/2011-10/46046.htm

Copyright © Linux教程網 All Rights Reserved