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");//销毁窗口}
注意点:
- cvNameWindow:第一个参数指定窗口标题,当该窗口与其他函数进行交互时,利用该参数引用此窗口。cvShowImage显示图像,第一个参数指定窗口参数。注意在上面的代码中,我创建了两个窗口,而显示了一个图像,运行代码会发现该图像会出现在窗口“Example2”中。
- cvReleaseImage释放IplImage*所指向的内存,cvDestroyWindow也会同时释放为该窗口所分配的内存。养成随时释放内存的好习惯。
- 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" );}
注意点:
- cvQueryFrame返回的IplImage*使用在CvCapture*中分配好的内存,并不像cvLoadImage一样为图像新分配内存,也就不需要通过cvReleaseImage释放。只需要最后统一释放CvCapture*.内存垃圾处理在opencv中很重要,但是我们只需要释放自己显示分配的内存空间。
- 上面的程序中设置帧间隔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);}
注意点:
- 上述函数在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();}
注意:
- OpenCv利用CV_FOURCC()宏来指定编码格式,参考官方文档上所写:fourcc – 4-character code of codec used to compress the frames.更多的格式缩写
0 0
- learning opencv chapter2
- chapter2
- chapter2
- Learning OpenCV
- learning opencv
- learning Opencv
- Learning with python: Chapter2 Variables, expressions and statements
- 统计学习导论 Chapter2--What Is Statistical Learning?
- Learning OpenCV Capture 2
- Learning OpenCV Source Code
- Learning OpenCV: 关于 CvMemStorage
- Learning Opencv第二章
- O'Reilly Learning OpenCV
- OpenCV Learning: 函数cvConvertImage
- learning opencv系列
- [OPENCV] Learning Notes
- Learning OpenCV 绘图
- Learning OpenCV 鼠标事件
- 如何取出 Map中key和value的值
- HDU 4263 Red/Blue Spanning Tree(最小生成树)
- ★★★易忘点总结〖多线程〗
- Linux最大线程数及最大进程数
- hdu 4864 2014STD D题
- learning opencv chapter2
- lombok 简化java代码注解 理解
- 【未解决】SAE,本地,mysql,date类型,报错
- source insight的自动缩进 以及网上的一些使用技巧
- HD1096输入格式(8)--20140722
- 用户界面设计的40条技巧
- ★★★易忘点总结〖面向对象〗
- hdu 2008数值问题 20140722
- hdu 1045 Fire Net(贪心)