opencv中cvSetCaptureProperty定位不准的原因及解决

以前在opencv2.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库,就可以了。

 

P.S:测试的代码

[c-sharp] view plain copy
  1. #include "opencv/highgui.h"  
  2. #include <iostream>  
  3. using namespace std;  
  4. int main( int argc, char** argv )  
  5. {   
  6.     cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE );  
  7.     CvCapture* capture = cvCreateFileCapture( "d://11.avi" );  
  8.     IplImage* frame;  
  9.     int pos=0;  
  10.     int pos1=0;  
  11.     while(1)  
  12.     {  
  13.         cvSetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES,pos);  
  14.         cout<<pos;  
  15.         frame = cvQueryFrame(capture);  
  16.         pos1=cvGetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES);  
  17.         cout<<"/t"<<pos1<<endl;  
  18.         if( !frame ) break;  
  19.         cvShowImage( "Example2", frame );  
  20.         char c = cvWaitKey(33);  
  21.         if( c == 27 ) break;  
  22.         pos++;  
  23.     }  
  24.     cvReleaseCapture( &capture );  
  25.     cvDestroyWindow( "Example2" );  
  26. }  

 

参考:http://wsqhs.spaces.live.com/blog/cns!94F639580F58209C!697.entry

http://www.ffmpeg.com.cn/index.php/%E5%85%B3%E4%BA%8E_frame%E7%9A%84%E4%B8%80%E4%BA%9B%E5%9F%BA%E6%9C%AC%E7%9F%A5%E8%AF%86


 

问题说明:

OpenCV 2.X 版本中,调用cvCaptureProperty()定位视频到指定帧,采用下面两种方法都会出现定位不准的问题。

  1. cvSetCaptureProperty( capture, CV_CAP_PROP_POS_AVI_RATIO, t)  
  1. cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, t);  
都会显示诸如此类的错误警告信息:

HIGHGUI ERROR: AVI: could not seek to position 2.701

其中黄色数字就是OpenCV函数中对应的帧数,不知道因为什么原因,变成非整数,与之前程序中指定的帧数不一致,导致无法定位到准确的位置。

之前用OpenCV 2.2版本,一样出现相同的问题。而使用OpenCV 1.1版本,就可以正常定位。


更详细的问题说明:

很多人都遇到这个问题,更详细的实验可以参见下面文章:

《设定cvSetCaptureProperty后取帧不准的问题》 见 http://www.linuxidc.com/Linux/2011-10/46045.htm

作者实验中使用的测试代码如下:

  1. #include "highgui.h"   
  2. #include <iostream>   
  3. using namespace std;  
  4. int main( int argc, char** argv )  
  5. {   
  6.    cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE );  
  7.    CvCapture* capture = cvCreateFileCapture( "d://11.avi" );  
  8.    IplImage* frame;  
  9.   
  10.    int pos=0;  
  11.    int pos1=0;  
  12.    while(1)  
  13.    {  
  14.       cvSetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES,pos);  
  15.       cout<<pos;  
  16.       frame = cvQueryFrame(capture);  
  17.   
  18.       pos1=cvGetCaptureProperty(capture,CV_CAP_PROP_POS_FRAMES);  
  19.       cout<<"\t"<<pos1<<endl;  
  20.   
  21.       if( !frame ) break;  
  22.       cvShowImage( "Example2", frame );  
  23.       char c = cvWaitKey(33);  
  24.       if( c == 27 ) break;  
  25.   
  26.       pos++;  
  27.    }  
  28.    cvReleaseCapture( &capture );  
  29.    cvDestroyWindow( "Example2" );  
  30. }  
作者发现,在OpenCV 2.X版本中,随着pos值递增,pos1值并不与pos1相等,而是有不规则的跳动,造成无法准确定位视频帧。


原因与改进方法:

原因在于opencv2.0以后,采用ffmpeg采集视频,而在opencv1.0采用vfw采集视频(具体的概念暂时还不清楚,有时间继续补上)。而opencv在定位时候,调用的ffmpeg的av_seek_frame()函数,此函数原型为:

  1. 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,

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

也就是按照默认的读取关键帧。因此,视频跳跃就出现了。

解决这个问题需要将0改为 AVSEEK_FLAG_ANY ,即:

  1. int ret = av_seek_frame(ic, video_stream, timestamp, AVSEEK_FLAG_ANY );  
之后重新编译opencv库,就可以了。

我在OpenCV 2.3.1中的处理方法:

OpenCV 2.3.1中的与cvCaptureProperty()和FFMPEG相关的文件是:opencv2.3.1解压目录\modules\highgui\src\cap_ffmpeg_impl.hpp

在函数 bool CvCapture_FFMPEG::setProperty( int property_id, double value ) 中

相关的原始代码如下:

  1. int flags = AVSEEK_FLAG_FRAME;  
  2. if (timestamp < ic->streams[video_stream]->cur_dts)  
  3. flags |= AVSEEK_FLAG_BACKWARD;  
  4. int ret = av_seek_frame(ic, video_stream, timestamp, flags);  
  5. if (ret < 0)  
  6. {  
  7.    fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",  
  8.           (double)timestamp / AV_TIME_BASE);  
  9.    return false;  
  10. }  
问题就在于flags的值为  AVSEEK_FLAG_FRAME,而不是AVSEEK_FLAG_ANY

仅修改第一行,还是不能达到效果。

与OpenCV 2.0的代码进行比较,发现OpenCV 2.0的代码更少,在2.0版本基础上进行修改:

  1. int ret = av_seek_frame(ic, video_stream, timestamp, AVSEEK_FLAG_ANY);  
  2. if (ret < 0)  
  3. {  
  4.     fprintf(stderr, "HIGHGUI ERROR: AVI: could not seek to position %0.3f\n",  
  5.     (double)timestamp / AV_TIME_BASE);  
  6.     return false;  
  7. }  
这样就可以正确定位了,但还不清楚这样修改对2.3整体代码有什么影响,有待更进一步研究。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: OpenCVSharp是一个用于计算机视觉和图像处理的C#封装库,它提供了丰富的特征和功能,能够快速而方便地实现各种视觉定位任务。视觉定位是计算机视觉非常重要的任务之一,也被广泛应用于许多领域,例如机器人导航、自动驾驶、医学图像处理等。 OpenCVSharp能够通过色彩分布、形状匹配、特征提取等方式进行物体检测与跟踪。例如,在机器人导航,我们需要通过相机捕捉实时环境图像来判断其所处的位置和方向,这就需要依靠视觉定位技术。OpenCVSharp提供了可靠的图像处理和模式识别工具,在机器人导航等场景能够实现高精度的目标检测以及位置和方向的确定。 除此之外,OpenCVSharp还适用于其他各种视觉定位任务。例如,在医学图像处理,医生需要通过X光和磁共振图像来识别重要的组织和器官,并确定疾病的位置和程度。OpenCVSharp提供了强大的图像处理和分析工具,能够帮助医生轻松地完成这些任务。 总之,OpenCVSharp是一个功能强大的计算机视觉和图像处理库,它提供了各种视觉定位技术和工具,能够应用于许多领域,并实现高效、高精度的图像处理任务。 ### 回答2: OpenCVSharp 是一个基于C#的开源计算机视觉库,它提供了大量的图像处理和计算机视觉算法,包括图像处理、特征检测、目标跟踪和机器学习等。这个库非常适合使用C#编程语言来实现视觉定位。 视觉定位是基于图像处理和计算机视觉算法来实现对物体或场景进行精确定位的过程。在工业或者机器人领域,视觉定位通常被用来实现自动化生产,在医学领域,则可以用来辅助病人手术等应用。 使用 OpenCVSharp 实现视觉定位可以让用户快速开发出定位功能强大的计算机视觉算法。OpenCVSharp在图像处理、特征检测、目标跟踪等方面都提供了很多强大的算法,以及快速的图像处理效率。用户可以根据实际应用场景选择适合的算法组合,以达到特定目标的视觉定位效果。 总之,OpenCVSharp 是一个十分优秀的计算机视觉库,它整合了大量的视觉定位算法和工具,让用户能够快速地构建出令人满意的视觉定位应用程序。它的应用范围非常广泛,可以被用于很多领域的自动化和识别应用。 ### 回答3: OpenCVSharp是一个基于开源计算机视觉库OpenCV的C#封装库。它使得C#程序员们能够使用OpenCV的各种功能和算法来增强他们的视觉应用程序。 视觉定位OpenCVSharp在计算机视觉领域的一个重要应用。它是指将摄像机捕获到的图像与预先建立的场景或模型进行比较和匹配,并确定摄像机在场景的位置和方向。这种应用广泛应用于实际生产、无人系统、机器人等场合。 在视觉定位OpenCVSharp为程序员提供了许多强大的工具和算法,比如SURF、SIFT、ORB等局部特征描述子算法,以及机器学习算法、分类器等。这些工具和算法可以帮助我们在图像检测关键特征并确定摄像机的位置和方向。 同时,OpenCVSharp还提供了完善的图像处理和处理工具,比如图像变换、色彩空间转换、噪声滤波、形态学处理等等。这些工具可以很好地完善图像的前置处理,为后续的视觉定位提供更准确的数据和信息。 总之,OpenCVSharp在视觉定位的应用是相当广泛和重要的,在增强视觉应用程序的除此之外还扮演着重要的角色。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值