初试牛刀——显示图像
这一节接触了以下内容:
头文件“highgui.h”,此模块主要服务于图像和视频的输入/输出(在第一章已经学习过);
IplImage,图像文件的数据结构体;
IplImage* cvLoadImage( const char* filename, int flags=CV_LOAD_IMAGE_COLOR ),将图像文件加载进内存,它可以读取大部分格式类型的图像文件;
int cvNamedWindow( const char* name, int flags=CV_WINDOW_AUTOSIZE ),创建图像窗口,第一个参数作为与其他函数交互的索引;
void cvShowImage( const char* name, const CvArr* image ),把img图像显示在name的窗口中;
cvWaitKey(0),参数为0或负数时,等待用户触发行为,参数为正整数时,则为所指的毫秒数,时间一到就继续执行下去,不等待用户行为;
返回值:被按键的值,如果超过指定时间则返回-1。
如果程序想响应某个按键,可利用if(cvWaitKey(1)==Keyvalue);——(第二小节会接触到)
cvReleaseImage(&img),释放img所占据的内存,显示图像的窗口图像不会消失;
cvDestroyWindow("name"),销毁name窗口,同时释放为副本图像所开辟的内存,图像窗口消失;
程序编写:
编程环境:windows xp系统; opencv 1.0; VC++6.0;
程序说明:
此程序实现了opencv图片的加载和现实;
加入头文件:
#include <highgui.h>
主要程序代码:
IplImage* img = cvLoadImage("./image/3.jpg"); //将图像文件加载进内存 if (!img) //检测文件是否成功读入 { AfxMessageBox("图像文件不存在!"); return TRUE; } cvNamedWindow("lovely", CV_WINDOW_AUTOSIZE); //创建图像窗口,第一个参数作为与其他函数交互的索引 cvShowImage("lovely", img); //把img图像显示在lovely的窗口中 cvWaitKey(0); //等待用户触发行为 cvReleaseImage(&img); //释放img所占据的内存,“lovely”窗口图像不会消失 cvDestroyWindow("lovely"); //销毁lovely窗口,同时释放为img的一个副本图像所开辟的内存,图像消失
运行成功界面:
编程过程遇到的问题:
编译错误:缺少lib文件所导致的编译错误
注意opencv的VC++6.0的配置,安装配置参照官网文档:VC6下安装与配置OpenCV1.0
第二个程序——播放AVI视频
这一节接触了以下内容:
CvCapture:可以理解为抽象视频接口结构体,它包括了所有关于读入AVI文件的信息;
CvCapture* cvCreateFileCapture( const char* filename ):给指定文件中的视频流分配和初始化CvCapture结构。当分配的结构不再使用的时候,它应该使用 cvReleaseCapture函数释放掉;
IplImage* cvQueryFrame( CvCapture* capture ):从摄像头或者文件中抓取一帧,然后解压并返回这一帧。这个函数仅仅是函数cvGrabFrame和函数cvRetrieveFrame在一起调用的组合。返回的图像不可以被用户释放或者修改。抓取后,capture被指向下一帧,可用cvSetCaptureProperty调整capture到合适的帧;
void cvReleaseCapture( CvCapture** capture ):释放由函数cvCreateFileCapture或者cvCreateCameraCapture分配的CvCapture结构,注:若从capture中使用cvQueryFrame获取图像指针,在releaseCapture的时候同时函数释放图像指针,用户不用再自己释放;
程序编写:
编程环境:windows xp系统; opencv 1.0; VC++6.0;
程序说明:
此程序实现了AVI视频文件的加载和播放功能;
加入头文件:
#include <highgui.h>
主要程序代码:
cvNamedWindow("lovely", CV_WINDOW_AUTOSIZE); CvCapture* capture = cvCreateFileCapture("./avi/Lucky.avi"); if (!capture) { AfxMessageBox("无法读入视频文件!"); return TRUE; } IplImage* frame; while(1) { frame = cvQueryFrame(capture); if (!frame) break; cvShowImage("lovely", frame); char c = cvWaitKey(33); if (c == 27) break; //等待ESC键 } cvReleaseCapture(&capture); cvDestroyWindow("lovely");
运行成功界面:
编程过程遇到的问题:
加载AVI视频失败:
原因很简单,肯定是视频格式有问题,AVI文件它有不同的编码方式,有些编码方式opencv是不支持的。
OpenCV支持的AVI如下:(我也看不懂下面说的什么意思,还是用暴风直接转吧!)
Container |
FourCC |
Name |
Description |
AVI |
'DIB ' |
RGB(A) |
Uncompressed RGB, 24 or 32 bit |
AVI |
'I420' |
RAW I420 |
Uncompressed YUV, 4:2:0 chroma subsampled |
AVI |
'IYUV' |
RAW I420 |
identical to I420 |
本程序使用的是暴风影音转码软件,对于AVI,它共有两种编码方式:opencv不支持MPEG4格式,请选用XVID编码格式;
视频播放控制
这一节接触了以下内容:
double cvGetCaptureProperty( CvCapture* capture, int property_id ):获得摄像头或者视频文件的指定属性。
译者注:有时候这个函数在cvQueryFrame被调用一次后,再调用cvGetCaptureProperty才会返回正确的数值。这是一个bug,建议在调用此函数前先调用cvQueryFrame。
int cvSetCaptureProperty( CvCapture* capture, int property_id, double value ):设置指定视频获取的属性。目前这个函数对视频文件只支持: CV_CAP_PROP_POS_MSEC, CV_CAP_PROP_POS_FRAMES, CV_CAP_PROP_POS_AVI_RATIO
int cvCreateTrackbar( const char* trackbar_name, const char* window_name,
int* value, int count, CvTrackbarCallback on_change ):函数cvCreateTrackbar用指定的名字和范围来创建trackbar(滑块或者范围控制),指定与trackbar位置同步的变量,并且指定当trackbar位置被改变的时候调用的回调函数。被创建的trackbar显示在指定窗口的顶端。
void cvSetTrackbarPos( const char* trackbar_name, const char* window_name, int pos ):设置指定trackbar的位置。
程序编写:
编程环境:windows xp系统; opencv 1.0; VC++6.0;
程序说明:
此程序实现了avi视频的播放和控制,书上的代码和说明只实现了手动移动滚动条来调节视频播放位置,本文程序代码已经实现了滚动条随着视频播放自动移动的功能。
滚动条自动移动的原理是,在循环体里面,每循环一次就添加一个帧,每添加一个帧,全局变量slider_position就自加一,它代表的是滚动条的位置向前移动一步,然后利用滚动条位置设置函数cvSetTrackbarPos设置滚动滑块的位置。当然,当人为手动时,要记得同时改写slider_position的值,以使它处于最新值状态。
本程序的opencv参考函数列表如下:
加入头文件:
<span style="font-size:16px;">#include <cv.h> #include <highgui.h></span>
主要程序代码:
<span style="font-size:16px;">//回调函数 void OnTrackbarSlide(int pos) { cvSetCaptureProperty(capture, CV_CAP_PROP_POS_FRAMES, pos); //设置视频获取属性 slider_position = pos; //设置滚动条位置状态值,为实时滚动服务 }</span>
cvNamedWindow("lovely", CV_WINDOW_AUTOSIZE); //创建窗口 capture = cvCreateFileCapture("./avi/Lucky.avi"); //获取视频 if (!capture) { AfxMessageBox("无法读入视频文件!"); return TRUE; } //获得视频获取结构的属性,CV_CAP_PROP_FRAME_COUNT - 视频文件中帧的总数 int frames = (int) cvGetCaptureProperty(capture, CV_CAP_PROP_FRAME_COUNT); if (frames != 0) { //创建滚动条并将它添加到指定的窗口 cvCreateTrackbar("Position", "lovely", &slider_position, frames, OnTrackbarSlide); } IplImage* frame; while(1) { frame = cvQueryFrame(capture); //获取视频帧 if (!frame) break; cvShowImage("lovely", frame); //显示视频帧 char c = cvWaitKey(33); if (c == 27) break; //等待ESC推出按键 slider_position++; cvSetTrackbarPos("Position", "lovely", slider_position); //设置滚动条位置 } cvReleaseCapture(&capture); //释放资源 cvDestroyWindow("lovely"); //销毁窗口
运行成功界面:
编程过程遇到的问题:
当把回调函数void OnTrackbarSlide(int pos)作为类成员定义时,会出现调用错误cvCreateTrackbar("Position", "lovely", &slider_position, frames, OnTrackbarSlide),错误信息如下:cannot convert parameter 5 from 'void (int)' to 'void (__cdecl *)(int)';
解决方式,把OnTrackbarSlide(int pos)声明为全局变量,这个不知是否跟回调函数的性质有关(待调研)。