learning opencv chapter2

来源:互联网 发布:怎么修改淘宝店铺网址 编辑:程序博客网 时间:2024/05/21 10:03

第一个程序——显示图像

#include "opencv2/highgui/highgui.hpp"int main( int argc, char** argv ){  IplImage* img = cvLoadImage( argv[1] ); //IplImage储存图像文件的数据结构  //cvNameWindow创建窗口,第一个参数指定窗口标题,并且其他函数通过此参数来与该窗口交互  //第二个参数定义窗口属性,0窗口大小可调,CV_WINDOW_AUTOSIZE固定  cvNamedWindow("Example1", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE );  //cvShowImage显示IplImgae*指针对应的图像,第一个参数用于指定窗口,第二个参数为IplImage*  cvShowImage("Example2", img );  cvWaitKey(0);//等待键盘输入  cvReleaseImage( &img );//释放IplImage*  cvDestroyWindow("Example1");//销毁窗口}


注意点:

  1. cvNameWindow:第一个参数指定窗口标题,当该窗口与其他函数进行交互时,利用该参数引用此窗口。cvShowImage显示图像,第一个参数指定窗口参数。注意在上面的代码中,我创建了两个窗口,而显示了一个图像,运行代码会发现该图像会出现在窗口“Example2”中。
  2. cvReleaseImage释放IplImage*所指向的内存,cvDestroyWindow也会同时释放为该窗口所分配的内存。养成随时释放内存的好习惯。
  3. IplImage, cvLoadImage跟Mat, imread有什么区别?IplImage, cvLoadImage是C接口,Mat, imread是C++接口,并且自动帮助处理内存问题,而且字母更少,推荐使用。


第二个程序——播放avi视频

#include "opencv2/highgui/highgui.hpp"int main( int argc, char** argv ) {     cvNamedWindow( "Example2", CV_WINDOW_AUTOSIZE );    //CvCapture* capture = cvCaptureFromAVI( argv[1] ); // either one will work//cvCreateFileCapture读入avi文件并返回指向CvCapture的指针,返回的CvCapture结构被初始化到对应avi文件开头    CvCapture* capture = cvCreateFileCapture( argv[1] );    IplImage* frame;//while循环读入avi文件    while(1) {//cvQueryFrame参数为CvCapture指针,用来将下一帧视频文件载入内存,并且更新CvCapture指针//注意cvQueryFrame返回的图像内存问题        frame = cvQueryFrame( capture );        if( !frame ) break;        cvShowImage( "Example2", frame );//每帧之间间隔33ms,也可以由用户按Esc(ASCLL码27)键退出视频        char c = cvWaitKey(33);        if( c == 27 ) break;    }    cvReleaseCapture( &capture );    cvDestroyWindow( "Example2" );}


注意点:

  1. cvQueryFrame返的IplImage*使用在CvCapture*中分配好的内存,并不像cvLoadImage一样为图像新分配内存,也就不需要通过cvReleaseImage释放。只需要最后统一释放CvCapture*.内存垃圾处理在opencv中很重要,但是我们只需要释放自己显示分配的内存空间。
  2. 上面的程序中设置帧间隔33ms,其实也根据CvCapture结构体读取视频实际帧率(见第四章)

视频播放控制

添加进度条来调整视频播放位置:cvCreateTrackerbar添加进度条,以视频总帧数作为进度条长度,进度条位置代表在视频中的帧数,每次进度条位置变化则自动调用回调函数来改变读取的帧(cvSetCaptureProperty)

#include <stdio.h>#include <iostream>#include <fstream>#include "opencv2/core/core.hpp"#include "opencv2/highgui/highgui.hpp"using namespace std;//通过全局变量来表示滚动条位置int        g_slider_position = 0;//回调函数需要使用CvCapture对象,将其也设为全局变量CvCapture* g_capture         = NULL;//回调函数更新变量并重新设置视频读入位置void onTrackbarSlide(int pos) {//cvSet(Get)CaptureProperty可以设置(查看)CvCapture对象的各种属性//参数CV_CAP_PROP_POS_FRAMES利用帧数来设置读入位置(CV_CAP_PROP_POS_AVI_RATIO利用视频长度比例来设置读入位置)cvSetCaptureProperty(g_capture,CV_CAP_PROP_POS_FRAMES,pos);}int main( int argc, char** argv ) {cvNamedWindow( "Example2_3", 0 );g_capture = cvCreateFileCapture( argv[1] );//IplImage *foo = cvQueryFrame( g_capture);//读取总帧数int frames = (int) cvGetCaptureProperty(g_capture,CV_CAP_PROP_FRAME_COUNT);if( frames ){//创建滚动条,参数依次为:滚动条名称,所属窗口,绑定变量,最大值,回调函数(在不需要时置为空)cvCreateTrackbar("Position","Example2_3",&g_slider_position,frames,onTrackbarSlide);}IplImage* frame;frames = 0;while(1) {frame = cvQueryFrame( g_capture );if( !frame ) break;//cvGetCaptureProperty读取当前所在帧int frames = cvGetCaptureProperty( g_capture, CV_CAP_PROP_POS_FRAMES);//更新进度条cvSetTrackbarPos("Position","Example2_3",frames);cvShowImage( "Example2_3", frame );char c = (char)cvWaitKey(10);if( c == 27 ) break;}cvReleaseCapture( &g_capture );cvDestroyWindow( "Example2_3" );return(0);}


注意点:

  1. 上述函数在linux平台上可能运行错误,详情可以下载原始示例代码,其中有说明以及针对性的代码变化


更多变换

基本的计算机视觉任务包括对视频流的滤波,实现方法是随着视频的播放对其中每一帧进行简单的运算。下面的代码分别是对图像进行Gaussian平滑滤波,比例为2的缩放处理,以及canny边缘检测。

#include "opencv2/highgui/highgui.hpp"#include <opencv/cv.h>IplImage* doSmooth(IplImage*);IplImage* doPyrDown(IplImage*, int);IplImage* doCanny(IplImage* in, double, double, double);int main( int argc, char** argv ){  IplImage* img = cvLoadImage( argv[1] );  cvNamedWindow("Example1", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example2", CV_WINDOW_AUTOSIZE );  IplImage* img2 = doSmooth(img);  //IplImage* img2 = doPyrDown( img, IPL_GAUSSIAN_5x5 );  //IplImage* img2 = doCanny( img, 10, 100, 3 );  cvShowImage("Example1", img );  cvShowImage("Example2", img2);  cvWaitKey(0);  cvReleaseImage( &img );  cvReleaseImage( &img2);  cvDestroyAllWindows();}/**********************变换*************************/IplImage* doSmooth( IplImage* in ){    //cvCeateImage 分配自己的图像结构空间来存储平滑后的图像,第一个参数说明当前图像大小//第二个参数指明各通道像素点的数据类型(或者说图像元素的位深度,e.g image->depth),第三个参数说明通道数    IplImage* out = cvCreateImage(        cvGetSize(in),        IPL_DEPTH_8U,        3    );        //高斯平滑,后面会再学    cvSmooth( in, out, CV_GAUSSIAN, 5, 5 );    cvSmooth( out, out, CV_GAUSSIAN, 5, 5 );    return out;}//比例为2的缩放处理IplImage* doPyrDown(  IplImage* in,  int       filter = IPL_GAUSSIAN_5x5){    // Best to make sure input image is divisible by two.    //    assert( in->width%2 == 0 && in->height%2 == 0 );    IplImage* out = cvCreateImage(         cvSize( in->width/2, in->height/2 ),        in->depth,        in->nChannels    );    cvPyrDown( in, out );    return( out );};//canny边缘检测IplImage* doCanny(    IplImage* in,    double    lowThresh,    double    highThresh,    double    aperture){    if (in->nChannels != 1)        return(0); // Canny only handles gray scale images    IplImage* out = cvCreateImage(         cvGetSize( in ),        in->depth, //IPL_DEPTH_8U,            1);    cvCanny( in, out, lowThresh, highThresh, aperture );    return( out );};


在 learning opencv上提到,对前面的函数进行嵌套调用是个很不好的注意,这样将会对内存空间的释放造成困难。建议的方式是使用“自清理”模式,在每一个封装中加入

cvRealeaseImage( &in );

但是如此一来就无法对中间步骤的图像进行处理。或者改用每个独立阶段释放内存的方式简化图像处理流程。嵌套调用以及改进的方式如下:

//嵌套调用int main( int argc, char** argv ){  cvNamedWindow("Example Gray", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example Pyr", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example Canny", CV_WINDOW_AUTOSIZE );  IplImage* img_rgb  = cvLoadImage( argv[1] );  IplImage* img_gry  = cvCreateImage( cvSize( img_rgb->width,img_rgb->height ), img_rgb->depth, 1);  cvCvtColor(img_rgb, img_gry ,CV_BGR2GRAY);  IplImage* img_pyr  = doPyrDown( img_gry, IPL_GAUSSIAN_5x5 );  IplImage* img_pyr2 = doPyrDown( img_pyr, IPL_GAUSSIAN_5x5 );  IplImage* img_cny  = doCanny( img_pyr2, 10, 100, 3 );  cvShowImage("Example Gray", img_gry );  cvShowImage("Example Pyr", img_pyr2 );  cvShowImage("Example Canny", img_cny );  cvWaitKey(0);  cvReleaseImage( &img_cny);  cvReleaseImage( &img_rgb);  cvReleaseImage( &img_pyr);  cvReleaseImage( &img_pyr2);  cvReleaseImage( &img_gry);  cvDestroyAllWindows();}//每个独立阶段释放内存int main( int argc, char** argv ){  cvNamedWindow("Example Gray", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example Pyr", CV_WINDOW_AUTOSIZE );  cvNamedWindow("Example Canny", CV_WINDOW_AUTOSIZE );  IplImage* img_rgb = cvLoadImage( argv[1] );  IplImage* out;  out = cvCreateImage( cvSize( img_rgb->width,img_rgb->height ), img_rgb->depth, 1);  cvCvtColor(img_rgb, out ,CV_BGR2GRAY);  cvReleaseImage(&img_rgb);  cvShowImage("Example Gray", out );  out = doPyrDown( out );  out = doPyrDown( out );  cvShowImage("Example Pyr", out );  out = doCanny( out, 10, 100, 3 );  cvShowImage("Example Canny", out );  cvWaitKey(0);  cvReleaseImage( &out);  cvDestroyAllWindows();}



从摄像机读入数据

只要将上面示例代码2中的

cvCreateFileCapture(const char* fname);
改为

cvCreateCameraCapture(0);
他们都是同样返回CvCapture*指针,CvCapture*结构初始化后,从视频文件或摄像设备读入图像没有区别。


写入AVI视频文件

创建一个视频流文件以便写入视频文件,实现该功能的函数是cvCreateVideoWriter(),利用cvWriterFrame逐帧将视频流写入文件

#include "opencv/cv.h"#include "opencv/highgui.h"// Convert a video to log-polar// argv[1]: input video file// argv[2]: name of new output fileint main( int argc, char* argv[] ) {cvNamedWindow( "Example2_10", CV_WINDOW_AUTOSIZE );cvNamedWindow( "Log_Polar", CV_WINDOW_AUTOSIZE );CvCapture* capture = cvCreateFileCapture( argv[1] );if (!capture){return -1;}//用于读取原始视频帧IplImage* bgr_frame;//fps视频帧率double fps = cvGetCaptureProperty (capture,CV_CAP_PROP_FPS);//视频图像大小CvSize size = cvSize((int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_WIDTH),(int)cvGetCaptureProperty( capture, CV_CAP_PROP_FRAME_HEIGHT));//CvVideoWriter创建视频流文件,参数依次为:文件名称,//文件格式(OpenCv利用CV_FOURCC()宏来指定编码格式),帧率,视频图像大小CvVideoWriter* writer = cvCreateVideoWriter(argv[2],CV_FOURCC('M','J','P','G'),    fps,size);//对数极坐标格式帧IplImage* logpolar_frame = cvCreateImage(size,IPL_DEPTH_8U,3);//逐帧处理图像并且利用cvWriteFramw()将视频流写入视频文件while( (bgr_frame=cvQueryFrame(capture)) != NULL ) {cvShowImage( "Example2_10", bgr_frame );cvLogPolar( bgr_frame, logpolar_frame,  //This is just a fun conversion that mimic's the human visual systemcvPoint2D32f(bgr_frame->width/2,bgr_frame->height/2), 40, CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );cvShowImage( "Log_Polar", logpolar_frame );cvWriteFrame( writer, logpolar_frame );char c = cvWaitKey(10);if( c == 27 ) break;}cvReleaseVideoWriter( &writer );cvReleaseImage( &logpolar_frame );cvReleaseImage( &bgr_frame );cvReleaseCapture( &capture );cvDestroyAllWindows();}

注意:

  1. OpenCv利用CV_FOURCC()宏来指定编码格式,参考官方文档上所写:fourcc – 4-character code of codec used to compress the frames.更多的格式缩写


0 0
原创粉丝点击