zoukankan      html  css  js  c++  java
  • OpenCV 入门级之USB摄像头采集[转]

    前面两篇博文呢,介绍了 OpenCV 的环境搭配以及最基本的几个函数的使用,

    而这一篇博文则还是延续以 Demo 讲述 OpenCV API 的方式,

    因为有些 API 是用得很多的,所以必须要熟练,而至于其他的一些比较罕见的 API ,

    则可以通过在 OpenCV 官网上下载必要的 API 文档来熟悉就 OK 了,

    对于在前面呢,基本上介绍了 IplImage 以及 CvCapture 的使用,下面的 Demo 呢,

    其实和前面差不多,只不过,我是通过摄像设备捕捉到帧后进行的处理,

    其实这个并不难,有兴趣的可以在等下的 Demo 中看到,对于摄像设备的处理,

    和处理普通的视频文件其实没有什么太大的区别,但是,兴趣这个东西是很神奇的,

    只有兴趣浓厚,才有可能学好一门技术,而视频文件和摄像设备相比,

    很显然,能够控制摄影摄像设备更让人振奋,

    所以下面的 Demo 使用了摄像设备,同时可以实现拍照以及录视频的功能。

          

    首先,我使用的环境是 VS2008 + OpenCV 2.0 ,同时,由于涉及到摄像设备,而我电脑这里没有摄像头,

    所以勉强拿了个手机充当了摄像头,所以拍出来效果极差。

                 

                                       

    拍照功能

    注意注释部分,其中使用的比较生疏的 API 包括 cvPyrDown  , cvCreateCameraCapture

    以及 cvCopy 和 cvSaveImage

    下面就来一一解释这几个 API 的具体使用:

              

    void cvPyrDown( const CvArr* src, CvArr* dst, int filter=CV_GAUSSIAN_5x5 );

              

    其中 src 为 CvArr * 类型,这里顺便解释一下 OpenCV 基本上是用 C 实现的,当然其中包括一定的 C++ 成分,

    但是 OpenCV 中仍然也使用了面向对象的思想,即有以下的继承关系:

    image

    所以在实际使用当中,完全可以使用 ”子类” CvMat 或者是 IplImage 来代替 CvArr ,

    也就是说在参数中完全可以传入一个 IplImage 类型,

    src 代表的就是源图像,即传入函数的图像,而 dst 则是输出图像,即缩放一倍后的图像,

    但是需要注意的是,在这里传入的 dst 图像必须是在初始化以后才能传入,

    对于这一点,在下面的 Demo 中可以看到。而至于卷积滤波器的类型则一般采用默认类型即可。

                   

    CvCapture* cvCreateCameraCapture( int index );

               

    大伙应该还记得 cvCreateFileCapture 这个函数吗?这在笔者前面的一篇博文中有使用的,

    尚不清楚的可以参考:

    http://www.cnblogs.com/QinBaoBei/archive/2010/10/24/1859704.html

    其实对于 cvCreateFileCapture 来说,其是根据一个指定的视频文件来初始化,

    而对于 cvCreateCameraCapture 则不同,其是通过初始化一个视频设备 (也可以看做就是一个摄像头),

    初始化以后,便可以从这个摄像设备中获取视频了。

    至于参数 index 的话,如果您的电脑上连接了多个摄像设备,则需要通过这个  index  来指定到底要使用哪一个摄像头。

            

    void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL );

             

    这个函数的作用是拷贝一个数组到另一个数组,而根据前面的继承关系,IplImage  继承自  CvMat,

    而 CvMat 又是继承于  CvArr ,所以在此处可以直接传入一个  IplImage  来实现拷贝,

    很明显,src 是传入的数组,而 dst 则是复制完成后返回的结果数组,

    而至于 mask 这个数组呢,比较变态,

    它指定了数组 src 中那些元素需要拷贝到 dst 数组中,那些元素不能够拷贝到 dst 数组中,

    mask 数组中标记为非 0 的则可以拷贝到 dst 中,标记为 0 的则不会拷贝到 dst 数组当中去。

    这里需要注意的是,dst 数组和 src 数组必须是相同的类型,并且具有相同的维数和大小,否则整个程序会崩溃。

              

    int cvSaveImage( const char* filename, const CvArr* image );

                      

    这个函数的作用很明显,即保存图片到文件,而至于保存的图片的文件则看  filename  这个参数指定的后缀名是什么了。

          

    上面几个 API 的具体使用可以参见下面的 Demo :

    #include <cv.h>
    #include <highgui.h>
    #include <stdio.h>
    
    
    //实现将拍下来的图片缩放一倍
    IplImage * DoPyrDown(IplImage * image,int filter = IPL_GAUSSIAN_5x5)
    {
    	//设置大小缩小一倍
    	CvSize size = cvSize(image->width / 2,image -> height / 2);
    
    	//初始化图片
    	IplImage * outImage = cvCreateImage(size,image->depth,image->nChannels);
    
    	//实现缩放
    	cvPyrDown(image,outImage);
    
    	cvReleaseImage(&image);
    	return outImage;
    }
    
    int main(int argc,char ** argv)
    {
    	cvNamedWindow("Demo08");
    	CvCapture * capture;
    
    	//首先是要通过摄像设备来得到一个CvCapture 对象
    	if(argc == 1)
    	{
    		capture=cvCreateCameraCapture(0);
    	}
    	else
    	{
    		capture=cvCreateCameraCapture(atoi(argv[1]));
    	}
    	assert(capture!=NULL);
    
    	IplImage * frame;
    
    	char keyCode;
    	//每隔30ms 捕捉一次视频图像
    	while((keyCode = cvWaitKey(30)))
    	{		
    		//表示按下了Esc 键
    		if(keyCode == 27)
    		{
    			break;
    		}
    		
    		//表示按下了回车键,此时应当保存照片
    		if(keyCode == 13)
    		{
    			//初始化一张图片
    			IplImage * outImage = cvCreateImage(
    				cvGetSize(frame),
    				frame->depth,
    				frame->nChannels);
    			//将原图拷贝过来
    			cvCopy(frame,outImage,NULL);
    
    			//实现缩放操作
    			outImage= DoPyrDown(outImage);
    
    			char *outImageName = "XiaoZhen.jpg";
    
    			//将图片保存
    			cvSaveImage(outImageName,outImage);
    
    			cvReleaseImage(&outImage);
    
    			printf("恭喜你, 保存图片成功! 
    ");
    		}
    
    		//得到摄像设备中的下一帧图像
    		frame = cvQueryFrame(capture);		
    		
    		if(!frame)
    		{
    			break;
    		}
    		cvShowImage("Demo08",frame);		
    	}
    
    	cvReleaseImage(&frame);
    	cvDestroyAllWindows();
    	return 0;
    }

    下面就来看看效果是什么样了:(手机差,所以效果不咋的)

    image

    当按下回车键的时候便可以实现保存图片了

    image

    由于我对从摄像头中的图片进行了缩放,所以看起来效果就更差了

    image

    好,第一个 Demo 就到此结束了,下面呢,在介绍一个 Demo ,

    这个 Demo 呢,通过从摄像头读到的内容来生成一个视频文件。

                

                 

    制作视频功能

    和第一个 Demo 一样,还是从 API 说起,

    在下面的 Demo 中呢,主要是使用了以下的几个特殊点的 API ,包括  cvCreateVideoWriter  和  cvWriteFrame 至于其他的一些 API ,在前面的博文都是有所触及的。

             

    CvVideoWriter* cvCreateVideoWriter( const char* filename,

                                        int fourcc,

                                        double fps,

                                        CvSize frame_size,

                                        int is_color=1 );

          

    这个函数的作用就是初始化一个视频文件写入器,其中的参数的话,

    filename  不用多说,自然是指将要创建的视频文件的名称,

    fourcc  则代表的是视频压缩的编码格式,

               CV_FOURCC('P','I','M','1')  是 MPEG-1 codec,

               CV_FOURCC('M','J','P','G')  是motion-jpeg codec等。

               在 Win32 下,如果传入参数 -1,可以从一个对话框中选择压缩方法和压缩参数。

    fps  则代表的是帧率。

    is_color  则代表是希望得到彩色帧还是得到灰度帧。

            

    int cvWriteFrame( CvVideoWriter* writer, const IplImage* image );

            

    这个 API 的作用是非常明显的,即写一个帧到视频文件中,至于参数的话我想也不需要多做解释了。

    下面就来看 Demo 了:

    #include <highgui.h>
    #include <cv.h>
    #include <stdio.h>
    
    int main(int argc,char ** argv)
    {
    	cvNamedWindow("Demo09");
    	CvCapture * capture = 0;
    
    	if(argc == 1)
    	{
    		 capture = cvCreateCameraCapture(0);
    	}
    	else
    	{
    		capture = cvCreateCameraCapture(atoi(argv[1]));
    	}
    
    	if(!capture)
    	{
    		return -1;
    	}
    
    	IplImage * frame;
    	//指定视频中每一帧的大小(我的摄像头拍摄下的图片均是 160 * 120 的)
    	CvSize size = cvSize(160,120);
    	//需要初始化一个写视频文件的对象,这里注意使用的编解码器格式是 MJPG
    	//帧率设置为 5
    	CvVideoWriter * videoWriter = 
    		cvCreateVideoWriter("BoyXiao.avi",CV_FOURCC('M','J','P','G'),5,size);
    
    	char keyCode;
    	//每隔30ms 从摄像头中取出一帧
    	while(( keyCode = cvWaitKey(30)))
    	{
    		if(keyCode == 27)
    		{
    			break;
    		}
    		//得到从摄像头中获取的帧
    		frame = cvQueryFrame(capture);
    
    		//将帧写入视频文件中
    		cvWriteFrame(videoWriter,frame);
    
    		cvShowImage("Demo09",frame);
    	}
    
    	cvReleaseVideoWriter(&videoWriter);
    	cvReleaseImage(&frame);
    	cvDestroyWindow("Demo09");
    
    	return 0;
    }

    下面就来验收一下结果了:

    首先自然是录制视频了。

    image

    视频录制完成后可以在项目根目录下看到创建好的视频文件

    image

    当然视频文件也是可以播放的

    image

    这一篇博文到此又结束了,其实呢,这篇博文没什么技术含量,

    主要是通过使用了摄像头来摆弄视频,

    想在此展现的就是一种好玩的心态,或者说是兴趣,

    笔者一直都认为,只要对一个东西有了兴趣,那么接下来想搞定它那就不会太难了,

    所以本篇博文纯粹本着培养兴趣的心态而作。

  • 相关阅读:
    nginx.conf 配置解析之 http配置
    nginx.conf 配置解析之 events配置
    nginx.conf 配置解析之 全局配置
    nginx.conf 配置解析之文件结构
    centos7 编译安装nginx1.16.0( 完整版 )
    SQL注入是什么?如何防止?
    数据库的脏读、不可重复读、幻读以及不可重复读和幻读的区别
    唯一索引与主键索引的比较
    分布式session的几种实现方式
    反向代理和负载均衡
  • 原文地址:https://www.cnblogs.com/zhouwenJS/p/3737220.html
Copyright © 2011-2022 走看看