本帖内容摘要:将开源进行到底——如何在ZED内利用底层V4L2+OPENCV进行图像处理以及移植策略。
百转千回,终于到了最后的总结时间,每一个帖子都是几天几周反复探索的结果,将一些教训和弯路都分享一下,能给利用zed开发摄像头和视频的同学一点指导。
1. ZED开发摄像头的几种思路以及选择。。。
想在ZED上开发摄像头,其实和其它ARM系列上开发摄像头,是异曲同工的,都有两种基本思路:
第一,利用OPENCV的CvCapture*cvCaptureFromCAM( int index )来实现,屏蔽掉V4L2底层的繁琐操作。
第二,通过V4L2,从摄像头的像素格式,视频流格式,包括视频的输出格式等作设置和定制,包括视频帧显示的大小等都可以进行修改。
那么很显然,包括我在内,大多数新手一开始肯定希望如何利用第一种方案,简单嘛,首先在PC下的虚拟机UBuntu 12.04内实现摄像头读取,然后存储为一幅照片,验证上面的函数是否可行。一开始必然是不行的,那么通过下面的办法,安装一些第三方库,便可以让程序走通,但是。。。一会儿就知道,这条路是死路
apt-get install ffmpeg libavcodec-dev libavcodec52 libavformat52 libavformat-dev
apt-get install libgstreamer0.10-0-dbg libgstreamer0.10-0 libgstreamer0.10-dev
apt-get install libxine1-ffmpeg libxine-dev libxine1-bin
apt-get install libunicap2 libunicap2-dev
apt-get install libdc1394-22-dev libdc1394-22 libdc1394-utils
apt-get install swig
apt-get install libv4l-0 libv4l-dev
apt-get install python-numpy
apt-get install libpython2.6 python-dev python2.6-dev #You must install this for python support
装好之后重新编译摄像头程序,还是不行。然而,问题是,本机上可以了,那么这些库里哪些是真正让摄像头打开的呢,经过对这些库的了解,才发现,最为关键的几个库为ffmpeg以及libv4l,libavcodec。特别是libv4l是直接用来捕获摄像头的库,只有有了这些,在opencv重新编译后,才能够将cvCaptureFromCAM于真正的设备连接,从而获取视频。
本机PC上确实可以,但是我们最终目的是在嵌入式ARM内实现,这又该怎么办,虽然论坛里也有一些帖子中说到关于v4l2/v4l的配置问题,经过很多帖子的阅读,而且经过很多实验,发现很不容易,最大的问题就是libv4l.so,没有ARM的版本,如果能够在ARM平台下找到libv4l.so的库文件,选上with v4l,在编译OPENCV时就是走不通,因为首先在交叉编译器的目录下就得有这个ARM版本的libv4l.so的库啊,但是实际是没有,而且网上也没有人提供这项资源。
所以,这种方案走不通,pass了。
那么,如何在ZED内打开摄像头呢,OK,底层的V4L2真的那么恐怖吗,其实非也,底层V4L2非常容易理解,而且也不难,看我细细道来。
V4L是Linux环境下开发视频采集设备驱动程序的一套规范(API),它为驱动程序的编写提供统一的接口,并将所有的视频采集设备的驱动程序都纳入其的管理之中。V4L不仅给驱动程序编写者带来极大的方便,同时也方便了应用程序的编写和移植。V4L2是V4L的升级版,我们使用的OOB是3.3的内核,不再支持V4L,所以是以v4l2作为底层的摄像头视频开发。
video4linux2(V4L2)是Linux内核中关于视频设备的内核驱动,它为Linux中视频设备访问提供了通用接口,在Linux系统中,V4L2驱动的Video设备节点路径通常/dev/video/中的videoX。
V4L2的主要作用使程序有发现设备和操作设备的能力.它主要是用一系列的回调函数来实现这些功能,像设置摄像头的频率、帧频、视频压缩格式和图像参数等等。此框架只能运行在Linux操作系统中,而且是针对uvc的免驱usb设备的编程框架。
V4L2打开视频的流程可以用以下的软件框图表示:
就分这么几步,具体的操作,我也不敢妄自吹嘘,确实也是学超群天晴的博客而来。 http://www.cnblogs.com/surpassal/archive/2012/12/22/zed_webcam_lab2.html
至少我觉得很好用,这种视频开发思路,虽然有点费周折,但是不用移植任何第三方库,就可以在ZED内打开摄像头,而且最为关键的,CV下的cvCaptureFromCAM,在ZED内最大是640*480,但是V4L2的底层函数,则可以完全地按照摄像头的像素来设置窗口大小,像我的Logitech C270,像素300万,我甚至可以放大到1920*1080来观察摄像头视频,这就是V4L2的强大之处。具体的开发过程大家可以参照上面的链接,还是大神写的好啊,惭愧。
2. V4L2+OPENCV,如何在V4L2读取摄像头视频的基础上,利用OPENCV进行处理。。。
OpenCV的移植并不复杂,按照教材上一步步来,基本的函数都可以直接拿来使用,当然前提是指定Opencv库文件的路径,然而,Opencv进行处理,是基于IplImage数据类型的,IplImage是CV内的struct类型的图像变量。
而V4L2是通过malloc申请动态内存,并将图像连续存放在uchar *的指针所指向的内存内部的,如何转换呢?
由于我这里很早就开始用QT进行程序开发,因此,我就毫不犹豫的,想到用QT来做中介,
没错,具体怎么实现呢,OK,uchar *的变量,可以通过下列函数,直接转化为QImage,没有任何问题
QImage frame;
frame->loadFromData((uchar *)pp,window_width * window_hight * 3 * sizeof(char));
这就将转换为了QImage的图像对象,可以任意在QT内贴图啊,存储啊等等。
那么然后,QImage如何和IplImage转换呢,最基本的转换函数为,当然这是网上大家通用的一个:
void labeltest::cvxCopyQImage(const QImage *qImage, IplImage *pIplImage) //QImage to Iplimage
{
int x, y;
for(x = 0; x < pIplImage->width; ++x)
{
for(y = 0; y < pIplImage->height; ++y)
{
QRgb rgb = qImage->pixel(x, y);
cvSet2D(pIplImage, y, x, CV_RGB(qRed(rgb), qGreen(rgb), qBlue(rgb)));
}
}
}
Ok,在经过OPENCV一阵处理后,特别是很多CV函数,都需要首先对图像进行灰度化,即BGR2GRAY,之后图像的通道数都变为1,图像的数据量也发生变化,处理后的数据想要显示在QT中,怎么办呢,两种思路:
1. 如果是彩色图像,则很简单一句话:
IplImage *img = cvLoadImage("lena.jpg", 1);
QImage qImage(img->imageData, img->width, img->height, img->widthStep, QImage::Format_RGB888);