1、引言
摄像头分为数字摄像头和模拟摄像头两大类。传统的模拟摄像头,获取图像信息需要先将视频采集设备产生的模拟视频信号经过特定的视频捕捉卡转换成数字信号,进而才能进行存储等处理。数字摄像头可以直接捕捉影像产生数字信号,然后通过串、并口或者USB接口传输到计算机里。数码摄像头的一般结构如图1 所示。
图1 数码摄像头的结构
相比于模拟摄像头,数码摄像头具有很大优势:CMOS图像传感器直接产生图像原始数据;硬件支持标准的JPEG压缩;主流高速的USB总线设备接口等。
由于模拟摄像头的整体成本较高,并且USB接口的传输速度远远高于串口、并口的速度,所以当前市场热点主要是USB接口的数码摄像头。比较而言,USB摄像头在一些嵌入式的应用场合具有明显的优势。本文介绍了基于XScale的嵌入式Linux下利用USB 摄像头采集图像的硬件、软件设计过程, 最终实现了在目标板上图像的采集和显示。
2、系统设计与器件选择
基于XScale的USB摄像头图像采集硬件平台如图2所示。
图中各个主要模块基本组成描述如下:
① 微处理器(MPU):针对开发视频终端的需要,并考虑到系统外围设备的需求情况,本系统采用INTEL公司XScale架构的PXA270 处理器,主频时钟可达520MHz。
② SDRAM 存储部分采用两颗SAMSUNG 公司的K4S561632E-TC75内存,每个大小为32M。
③ FLASH 存储器采用两颗INTEL 公司的JS28F128 J3D75 NOR Flash,每个大小为16M。
④ LCD:采用SAMSUNG 公司的3.5 寸LCD,分辨率为320×240。
图2 硬件结构原理图
3、基于XScale 的USB 摄像头图像采集的软件系统
由于嵌入式Linux 具有成本低、代码开放、移植性好的特点,其用于嵌入式系统的优势和发展潜力是不容置疑的。软件部分的搭建主要依赖于以下三个部分:
① Boatloader: 本系统采用u-boot作为引导程序,可以从网站上下载,经过交叉编译生成映像文件,然后通过JTAG 接口将映像烧写到目标板,实现引导程序的装载。
② Kernel:本系统采用Linux- 2.6.12.4.tar.bz2 版本的内核。
③ 文件系统:考虑到程序运行的速度,本系统采用ramdisk技术制作文件系统映像。
在Linux 操作系统下有3类主要的设备文件类型:块设备、字符设备和网络设备。而在Linux 下要使系统所挂接的外部设备正常工作,必须加载相应的驱动程序。Linux 下对于驱动的加载有两种方式:一种是直接加载到系统的内核当中去;另一种是以模块方式进行加载。在Linux 下要采集视频类数据,需要加载Video4Linux 驱动模块Videodev.o。然后再加相应的摄像头驱动程序。在项目开发中,我们把Video4Linux的驱动编译进内核,而摄像头驱动以模块方式加载。我们所使用是采用中芯微公司生产的zc301芯片的摄像头,所对应的驱动程序可以从网上下载,本项目用的是gspcav1-20070508.tar.gz。所以在系统启动时必须要通过如下命令来加载所需要的模块:
#insmod gspca.ko
通过开源项目spca5xx 可以得到模块的全部源代码。上层软件部分我们参考了servfox软件的操作过程,使用了spcav4l.c中的函数,经过交叉编译,在实验板上实现了实时图像采集的目的。
4、在Linux 下采集并显示USB 摄像头数据
图3 图像采集流程图
Linux 下摄像头的驱动程序是以81 为主设备号,在编写应用程序的时候,要通过打开一个具有该主设备号的设备文件来建立与设备驱动程序的通信,我们所使用的Linux 没有该文件,所以需要手工创建,并建立其软连接。我们用到的videodev.o 模块即为视频部分的标准Video for Linux (简称V4L)。这个标准定义了一套接口,内核、驱动、应用程序以这个接口为标准进行通信。
4.1 图像数据的采集过程
Linux下图像采集流程如图3所示。
第一步:打开摄像头设备,在Linux 下可以通过系统的设备文件来访问设备,在前面我们创建了摄像头的设备文件,文件描述符( vd->fd) 可以如下方法获取:
if ((vd->fd = open (vd->videodevice, O_RDWR)) == -1)
exit_fatal (“ERROR opening V4L interface”);
第二步:读取设备信息。首先可以在kernel 的源代码中找到头文件videodev.h,这个头文件定义了我们要编写的应用程序的所有数据结构和函数。我们先要获得摄像头的信息,可以通过头文件中的video_capability结构来了解摄像头的性能。按如下方法可读出其中内容。
if (ioctl (vd->fd, VIDIOCGCAP, &(vd->videocap)) == -1)
exit_fatal (“Couldn’t get videodevice capability”);
然后通过访问结构体vd->videocap 就可以读出摄像头的基本信息,如摄像头名称、支持的最大最小分辨率、信号源信息等。
第三步:访问摄像头设备采集的图像的各种属性。
可以通过videodev.h文件中的video_picture结构来了解图像的属性,按如下方法可读出其中内容。
if (ioctl (vd->fd, VIDIOCGPICT, &vd->videopict) < 0)
exit_fatal (“Couldnt get videopict params with VIDIOCGPICT”);
然后通过访问结构体vd->videopict 就可以读出图像的各种信息。
当然,vd->videopict中分量的值是可以改变的,实现方法为:先为分量赋新值,再调用VIDIOCSPICT。
if (ioctl (vd->fd, VIDIOCSPICT, &vd->videopict) < 0)
exit_fatal (“Couldnt set videopict params with VIDIOCSPICT”);
第四步:进行图像采集
考虑到图片的大小及USB接口的传输速率,本项目采集的图片格式为jpeg,实现函数为v4lGrab(&videoIn,jpegfile),通过该函数可以将设备文件中的图象数据的信息读出来并存储在jpegfile文件中。
截取图像有两种方法:一种是用mmap(内存映射)方式截取视频
mmap( )系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用read(),write()等操作。采用共享内存通信的一个显而易见的好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝。
另一种是直接读设备
关于缓冲大小,图象等的属性须事先设置;
调用read();
int read (要访问的文件描述符;指向要读写的信息的指针;应该读写的字符数);
返回值为实际读写的字符数。
4.2 LCD实时显示从摄像头上采集的图像
为了满足“所见即所得”的特性,本系统使用FrameBuffer驱动LCD,能够提供16BPP的颜色深度,满足嵌入式系统的需求。当然在编译ARM-Linux内核时,应当将这项特性包括在内。
编程思想:从摄像头采集到的图片存放在本地文件夹,再把jpeg转换成RGB通过直接写屏来实现显示。
把jpeg图片转换成RGB格式需要使用jpeg库,这可以从网上下载,交叉编译即可。
5、结论
本文详细介绍了基于XScale 的嵌入式Linux 下的USB摄像头图像采集的硬件、软件构建过程,可以灵活应用于基于嵌入式的各种电子产品及机器人视觉模块中。由于所采用的软件全部是开放源码而且免费获得,所以对于需要有较高的数据处理能力且成本要求严格的方面尤其适合。
参考文献
[1] 郑灵翔 等 嵌入式系统设计与应用开发.北京航空航天大学出版社,2006.
[2] 马忠梅 李善平 康慨 叶楠 ARM&Linux嵌入式系统教程. 北京航空航天大学出版社,2004.
[3] 刘晶晶.基于ARM- Linux 嵌入式系统引导程序的设计[J].微计算机信息,2006,2- 2.
[4] KarimYaghmour 构建嵌入式Linux 系统.中国电力出版社.
[5] Jonathan Corbet, Alessandro Rubini, Greg Kroah- Hartman 著,魏永明等译,《Linux 设备驱动程序》(第三版).中国电力出版社,2000.