设定cvSetCaptureProperty后取帧不准的问题
2016-02-29 14:09
337 查看
转载地址:
http://www.linuxidc.com/Linux/2011-10/46045.htm
http://www.linuxidc.com/Linux/2011-10/46046.htm
最近刚刚开始学习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
http://www.linuxidc.com/Linux/2011-10/46045.htm
http://www.linuxidc.com/Linux/2011-10/46046.htm
最近刚刚开始学习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
相关文章推荐
- linux shell(1)
- Opencv中的ROI介绍
- ftok()函数深度解析
- 拿webshell权限方法(一)
- 利用XShell上传、下载文件(使用sz与rz命令),超实用!
- zabbix自定义ITEMS,提示not supported
- Hadoop技巧(01):插件,终端权限
- 【转】Linux 下修改Tomcat使用的JVM内存大小
- 类型:linux;问题:linux命令;结果:Linux常用命令大全
- OpenCV进行图像相似度对比的几种办法
- [Linux]Linux下如何查看有多少文件夹,多少子目录
- 搭建分布式Hadoop2.6.0和Spark1.6.0集群
- Linux——为CentOS 7添加Windows引导程序
- nginx反向代理--upstream模块
- cookielib和urllib2模块相结合模拟网站登录
- openGL的初始化设置
- C/S和B/S架构的概念、优缺点、应用以及区别
- Tomcat中session的管理机制
- Linux下用命令格式化U盘
- 点滴记录——Centos 6.5 yum安装Ganglia