Linux环境下使用V4L2+opencv以MJPEG格式读取USB摄像头并实时显示

转眼间,V4L2已经搞了很长时间,从最开始的一窍不通,到后来的渐渐熟悉,从最开始照猫画虎的使用YUYV格式之间转换,到后来使用MJPEG格式读取,中间颇有周折。趁任务完成间隙,来简单总结下V4L2的使用。(文章只主要写了过程,完整程序已经附在最后)

有读者要问,opencv已经有相关的读取摄像头的函数,为什么要使用V4L2这么麻烦呢。其实主要是因为后面要将程序移植到板子上,而在板子上不能直接使用opencv中读取摄像头的函数的,所以需要借助V4L2来实现读取视频的功能。还有,既然YUYV格式这么简单(见文章末尾附的大神的博客),为什么要用MJPEG格式呢?这一点主要是考虑到YUYV数据量较大,影响摄像头读取速度,也会影响到后面都视频数据传输的扩展。

V4L2主要应用于linux读取USB摄像头,有关它的介绍网上有很多资料,这里不再赘述。结合主题,本文主要讲述如何使用MJPEG格式读取并将其转换为OpenCV中的IplImage格式,以方便进行图像处理,最后以视频的形式进行实时显示。截至到今天晚上,已经使得程序能够实时以MJPEG格式读取并显示,图像分辨率为1920*1080,速度100ms每帧。由于项目需要,所以尽可能使用较大分辨率,导致速度有点慢,如果使用普通的640*480,速度比较会比较快。

有点啰嗦,下面进入主题:使用MJPEG格式读取视频,并实时显示。整个过程主要分为以下几个步骤:

1.      打开视频设备文件,并进行参数初始化,设置采集分辨率、格式等;

该步骤中主要使用函数:

Open(“/dev/video0”,O_RDWR);//打开USB摄像头

ioctl(fd,VIDIOC_QUERYCAP,&cap);//查询设备的信息

ioctl(fd,VIDIOC_S_STD,&fmt);//设置视频的格式

2.      申请帧缓冲区,并将其映射到用户空间;

ioctl(fd,VIDIOC_REQBUFS,&req);//申请缓冲帧

malloc(req.count*sizeof(*buffer));

ioctl(fd,VIDIOC_QUERYBUF,&buf);//将申请到的帧缓冲映射到用户空间

3.      将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;

ioctl(fd,VIDIOC_QBUF,&buf);//将申请到的帧缓冲全部加入队列

ioctl(fd,VIDIOC_STREAMON,&byte);//开始采集

4.      应用程序从视频采集输入队列取出帧缓冲区,将其转换为OpenCV中的通用数据格式,然后显示,之后重新放入视频采集队列,循环该过程;

ioctl(fd,VIDIOC_DQBUF,&buf);//取缓冲帧

CvMatcvmat=cvMat(IMAGEHEIGHT,IMAGEWIDTH,CV_8UC3,(void*)buffer);//将帧内容赋值给CvMat格式的数据

IplImage img =cvDecodeImage(&cvmat,1);//解码,这一步将数据转换为IplImage格式

cvShowImage(“one”,img);//显示图像

cvReleaseImage(&img);//释放图像空间

ioctl(fd,VIDIOC_QBUF,&buf);//将缓冲重新加入队尾

循环上面的步骤,就可以形成视频啦

5.      停止视频采集,关闭设备文件。

ioctl(fd,VIDIOC_STREAMOFF,&byte);

close(fd);

 

由于时间关系,上面只是简单介绍了一下整个过程,相关函数的使用和函数中的结构体参数网上都有很多资料可供参考,当然也可以看下官方给的API手册,讲的很详细,但是有点长,且是英文的。下面列出我学习时找到的一些资料,

最后附上我自己的程序,目前程序能够实现基本的功能,但是本人还想进一步优化以提高效率,有其他好的想法的朋友可以与我联系。Mail:[email protected]

一个大神的博客,最开始我就是按照这个学习的

网址:

V4L2的官方手册:

网址:

我自己的程序:

网址:

程序是在linux环境下使用QT编译的,需要自己安装OPENCV,并在.pro文件中配置,我的.pro文件中已经将相关路径写入,读者使用时可以按照自己安装OPENCV的路径修改。

最后,加上效果图展示,由于分辨率较大,屏幕不能显示完整窗口:

你可能感兴趣的:(linux,opencv,摄像头)