基于ZedBoard的Webcam设计
更新时间:2024-06-27 14:26:01 阅读量: 综合文库 文档下载
基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集
硬件平台:DigilentZedBoard + USB 摄像头
开发环境:Windows XP 32 bit + Wmare 8.0 + Ubuntu 10.04 + arm-linux-xilinx-gnueabi交叉编译环境
Zedboardlinux: Digilent OOB Design
一、一些知识 1、V4L和V4L2。
V4L是Linux环境下开发视频采集设备驱动程序的一套规范(API),它为驱动程序的编写提供统一的接口,并将所有的视频采集设备的驱动程序都 纳入其的管理之中。V4L不仅给驱动程序编写者带来极大的方便,同时也方便了应用程序的编写和移植。V4L2是V4L的升级版,由于我们使用的OOB是 3.3的内核,不再支持V4L,因而编程不再考虑V4L的api和参数定义。 2、YUYV与RGB24
RGB是一种颜色的表示法,计算机中一般采用24位来存储,每个颜色占8位。YUV也是一种颜色空间,为什么要出现YUV,主要有两个原因,一个是 为了让彩色信号兼容黑白电视机,另外一个原因是为了减少传输的带宽。YUV中,Y表示亮度,U和V表示色度,总之它是将RGB信号进行了一种处理,根据人 对亮度更敏感些,增加亮度的信号,减少颜色的信号,以这样“欺骗”人的眼睛的手段来节省空间。YUV到RGB颜色空间转换关系是: R = Y + 1.042*(V-128);
G = Y - 0.34414*(U-128) - 0.71414*(V-128); B = Y + 1.772*(U-128);
YUV的格式也很多,不过常见的就是422、420等。YUYV就是422形式,简单来说就是,两个像素点P1、P2本应该有Y1、U1、V1和Y2、U2、V2这六个分量,但是实际只保留Y1、U1、Y2、V2。
图1 YUYV像素
二、应用程序设计
先定义一些宏和结构体,方便后续编程
1#define TRUE 1 2#define FALSE 0 3
4#define FILE_VIDEO \
5#define BMP \ 6#define YUV \ 7
8#define IMAGEWIDTH 640 9#define IMAGEHEIGHT 480 10
11staticintfd;
12staticstruct v4l2_capability cap; 13struct v4l2_fmtdesc fmtdesc; 14struct v4l2_format fmt,fmtack; 15struct v4l2_streamparm setfps; 16struct v4l2_requestbuffers req; 17struct v4l2_buffer buf; 18enum v4l2_buf_type type;
19unsignedcharframe_buffer[IMAGEWIDTH*IMAGEHEIGHT*3]; 其中
#define FILE_VIDEO \是要访问的摄像头设备,默人都是/dev/video0 #define BMP \#define YUV \
是采集后存储的图片,为了方便测试,这里将直接获取的yuv格式数据也保存成文件,可以通过yuvviewer等查看器查看。
staticintfd;
staticstruct v4l2_capability cap; struct v4l2_fmtdesc fmtdesc; struct v4l2_format fmt,fmtack; struct v4l2_streamparm setfps; struct v4l2_requestbuffers req; struct v4l2_buffer buf; enum v4l2_buf_type type;
这些结构体的定义都可以从/usr/include/linux/videodev2.h中找到定义,具体含义在后续编程会做相应解释。
#define IMAGEWIDTH 640
#define IMAGEHEIGHT 480 为采集图像的大小。
定义一个frame_buffer,用来缓存RGB颜色数据
unsigned charframe_buffer[IMAGEWIDTH*IMAGEHEIGHT*3]
这些宏和定义结束后,就可以开始编程配置摄像头并采集图像了。一般来说V4L2采集视频数据分为五个步骤:首先,打开视频设备文件,进行视频采集 的参数初始化,通过V4L2接口设置视频图像的采集窗口、采集的点阵大小和格式;其次,申请若干视频采集的帧缓冲区,并将这些帧缓冲区从内核空间映射到用 户空间,便于应用程序读取/处理视频数据;第三,将申请到的帧缓冲区在视频采集输入队列排队,并启动视频采集;第四,驱动开始视频数据的采集,应用程序从 视频采集输出队列取出帧缓冲区,处理完后,将帧缓冲区重新放入视频采集输入队列,循环往复采集连续的视频数据;第五,停止视频采集。在本次设计中,定义了 三个函数实现对摄像头的配置和采集。
int init_v4l2(void); int v4l2_grab(void); int close_v4l2(void);
同时由于采集到的图像数据是YUYV格式,需要进行颜色空间转换,定义了转换函数。 int yuyv_2_rgb888(void); 下面就详细介绍这几个函数的实现。 1、初始化V4l2
(1)打开视频。linux对摄像头的访问和普通设备一样,使用open函数就可以,返回值是设备的id。
1if ((fd = open(FILE_VIDEO, O_RDWR)) == -1) 2{
3printf(\); 4return (FALSE); 5 }
(2)读video_capability中信息。通过调用IOCTL函数和接口命令VIDIOC_QUERYCAP查询摄像头的信息,结构体 v4l2_capability中有包括驱动名称driver、card、bus_info、version以及属性capabilities。这里我们 需要检查一下是否是为视频采集设备V4L2_CAP_VIDEO_CAPTURE以及是否支持流IO操作V4L2_CAP_STREAMING。
1if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) 2{
3printf(\,FILE_VIDEO); 4return (FALSE); 5}
6else 7{
8printf(\,cap.driver); 9printf(\,cap.card);
10printf(\,cap.bus_info); 11printf(\,cap.version);
12printf(\,cap.capabilities); 13
14if ((cap.capabilities& V4L2_CAP_VIDEO_CAPTURE) == V4L2_CAP_VIDEO_CAPTURE) 15 {
16printf(\,FILE_VIDEO); 17 } 18
19if ((cap.capabilities& V4L2_CAP_STREAMING) == V4L2_CAP_STREAMING) 20 {
21printf(\,FILE_VIDEO); 22 } 23 }
(3)列举摄像头所支持像素格式。使用命令VIDIOC_ENUM_FMT,获取到的信息通过结构体
v4l2_fmtdesc查询。这步很关键,不 同的摄像头可能支持的格式不一样,V4L2可以支持的格式很多,/usr/include/linux/videodev2.h文件中可以看到。
1fmtdesc.index=0;
2fmtdesc.type=V4L2_BUF_TYPE_VIDEO_CAPTURE; 3printf(\);
4while(ioctl(fd,VIDIOC_ENUM_FMT,&fmtdesc)!=-1) 5{
6printf(\,fmtdesc.index+1,fmtdesc.description); 7fmtdesc.index++; 8 }
(4)设置像素格式。一般的USB摄像头都会支持YUYV,有些还支持其他的格式。通过前一步对摄像头所支持像素格式查询,下面需要对格式进行设 置。命令为VIDIOC_S_FMT,通过结构体
v4l2_format把图像的像素格式设置为V4L2_PIX_FMT_YUYV,高度和宽度设置为 IMAGEHEIGHT和IMAGEWIDTH。一般情况下一个摄像头所支持的格式是不可以随便更改的,我尝试把把一个只支持YUYV和MJPEG的摄像 头格式改为RGB24或者JPEG,都没有成功。
1fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
2fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV; 3fmt.fmt.pix.height = IMAGEHEIGHT; 4fmt.fmt.pix.width = IMAGEWIDTH;
5fmt.fmt.pix.field = V4L2_FIELD_INTERLACED; 6
7if(ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) 8{
9printf(\); 10return FALSE; 11 }
为了确保设置的格式作用到摄像头上,再通过命令VIDIOC_G_FMT将摄像头设置读取回来。
1if(ioctl(fd, VIDIOC_G_FMT, &fmt) == -1) 2{
3printf(\); 4return FALSE; 5} 6{
7printf(\,fmt.type);
8printf(\,fmt.fmt.pix.pixelformat&0xFF, (fmt.fmt.pix.pixelformat>>8) &0xFF,(fmt.fmt.pix.pixelformat>>16) &0xFF, (fmt.fmt.pix.pixelformat>>24) &0xFF);
9printf(\,fmt.fmt.pix.height); 10printf(\,fmt.fmt.pix.width); 11printf(\,fmt.fmt.pix.field); 12 }
完整的初始化代码如下:
1int init_v4l2(void) 2{ 3inti;
4int ret = 0; 5
6//opendev
7if ((fd = open(FILE_VIDEO, O_RDWR)) == -1) 8 {
9printf(\); 10return (FALSE); 11 } 12
13//query cap
14if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) 15 {
16printf(\,FILE_VIDEO); 17return (FALSE); 18 }
37if(g1>255)
38 g1 = 255; 39elseif(g1<0)
40 g1 = 0; 41
42if(r2>255)
43 r2 = 255; 44elseif(r2<0)
45 r2 = 0; 46
47if(b2>255)
48 b2 = 255; 49elseif(b2<0)
50 b2 = 0; 51
52if(g2>255)
53 g2 = 255; 54elseif(g2<0)
55 g2 = 0; 56
57 *(frame_buffer + ((480-1-i)*320+j)*6 ) = (unsigned char)b1; 58 *(frame_buffer + ((480-1-i)*320+j)*6 + 1) = (unsigned char)g1; 59 *(frame_buffer + ((480-1-i)*320+j)*6 + 2) = (unsigned char)r1; 60 *(frame_buffer + ((480-1-i)*320+j)*6 + 3) = (unsigned char)b2; 61 *(frame_buffer + ((480-1-i)*320+j)*6 + 4) = (unsigned char)g2; 62 *(frame_buffer + ((480-1-i)*320+j)*6 + 5) = (unsigned char)r2; 63 } 64 }
65printf(\); 66 }
4、停止采集和关闭设备
使用命令VIDIOC_STREAMOFF停止视频采集,并关闭设备。
1int close_v4l2(void) 2{
3ioctl(fd, VIDIOC_STREAMOFF, &buf_type); 4if(fd != -1) 5 { 6close(fd); 7return (TRUE); 8 }
9return (FALSE); 10 }
5、主函数
需要把我们采集到图像数据存储成图片,为了方便调试,先将原始的数据存储为yuv格式文件,再将转换成RGB后的数据存储为BMP。定义BMP头结构体
1typedefstructtagBITMAPFILEHEADER{
2 WORD bfType; // the flag of bmp, value is \ 3 DWORD bfSize; // size BMP file ,unit is bytes 4 DWORD bfReserved; // 0
5 DWORD bfOffBits; // must be 54 6
7}BITMAPFILEHEADER; 8 9
10typedefstructtagBITMAPINFOHEADER{
11 DWORD biSize; // must be 0x28 12 DWORD biWidth; // 13 DWORD biHeight; //
14 WORD biPlanes; // must be 1 15 WORD biBitCount; // 16 DWORD biCompression; // 17 DWORD biSizeImage; // 18 DWORD biXPelsPerMeter; // 19 DWORD biYPelsPerMeter; // 20 DWORD biClrUsed; // 21 DWORD biClrImportant; // 22 }BITMAPINFOHEADER;
完整的主函数
//@超群天晴
//http://www.cnblogs.com/surpassal/ int main(void) {
FILE * fp1,* fp2;
BITMAPFILEHEADER bf; BITMAPINFOHEADER bi;
fp1 = fopen(BMP, \if(!fp1) {
printf(\BMP\
return(FALSE); }
fp2 = fopen(YUV, \if(!fp2) {
printf(\YUV\return(FALSE); }
if(init_v4l2() == FALSE) {
return(FALSE); }
//Set BITMAPINFOHEADER bi.biSize = 40;
bi.biWidth= IMAGEWIDTH; bi.biHeight= IMAGEHEIGHT; bi.biPlanes= 1; bi.biBitCount= 24; bi.biCompression= 0;
bi.biSizeImage= IMAGEWIDTH*IMAGEHEIGHT*3; bi.biXPelsPerMeter= 0; bi.biYPelsPerMeter= 0; bi.biClrUsed= 0;
bi.biClrImportant= 0;
//Set BITMAPFILEHEADER bf.bfType = 0x4d42;
bf.bfSize= 54 +bi.biSizeImage; bf.bfReserved= 0; bf.bfOffBits= 54;
v4l2_grab();
fwrite(buffers[0].start, 640*480*2, 1, fp2); printf(\YUV\
yuyv_2_rgb888(); fwrite(&bf, 14, 1, fp1); fwrite(&bi, 40, 1, fp1);
fwrite(frame_buffer, bi.biSizeImage, 1, fp1); printf(\BMP\
fclose(fp1); fclose(fp2);
close_v4l2();
return(TRUE); }
三、PC测试
程序编写完后,可以先在PC上做测试(实际整个调试过程都是在PC上,直道最后PC上能实现功能再挪到ZedBoard上的)。PC上测试的结果
在/usr目录下可以查看到采集到的图片
四、Zedboard测试
PC上测试OK后,可以“挪”到ZedBoard上了。使用arm-xilinx-linux交叉编译环境对源文件进行交叉编译,将生成的可执行文件拷贝到ZedBoard上运行即可。 使用命令
arm-xilinx-linux-gnueabi-gcc v4l2grab.c -o zed-camera
对程序进行编译,编译通过后将生成的可执行文件zed-camera拷贝到到ZedBoard上,并将USB摄像头连接到ZedBoard上,通过命令 ls /dev
查看dev目录下的是否有video0设备。如果有,可以运行可执行文件了。在运行前我比较习惯获得可执行文件的权限,使用命令 chmod +x zed-camera
参数+x的意思是这个文件对于当前用户是可执行的。也可以使用 chmod 777 zed-camera
这样所有用户都有读写执行的权限。使用命令 ./zed-camera
执行可执行程序,程序运行,并输出以下信息:
zynq> ./zed-camera
[ 318.290000] usb 1-1.3: reset high-speed USB device number 3 using xusbps-ehci
driver: uvcvideo
card: UVC Camera (046d:0825) bus_info: usb-xusbps-ehci.0-1.3 version: 197376 capabilities: 4000001
Device /dev/video0: supports capture. Device /dev/video0: supports streaming. Support format: 1.YUV 4:2:2 (YUYV) 2.MJPEG
fmt.type: 1 pix.pixelformat: YUYV pix.height: 480 pix.width: 640 pix.field: 1 init /dev/video0 [OK] grabyuyv OK
save /usr/image_yuv.yuv OK change to RGB OK
save /usr/image_bmp.bmp OK
可以看到我使用的USB摄像支持YUYV和MJPEG两种格式。我也试过其他USB摄像头,大部分都只支持YUYV而不支持MJPEG或者RGB24。
采集到的图片默认是在/usr目录下的,将其拷贝出来 cp /usr/image* /mnt 再PC上查看,效果还不错
=============================
正在阅读:
基于ZedBoard的Webcam设计06-27
第7章原油的储存和外输07-26
Unit3 My favourite food is hamburgers11-05
昆虫记作文450字02-04
北京市劳动合同管理规定05-20
ATP习题12-08
12中旬 许 波 邱国华 浅谈园林施工中的质量管理03-11
好听的姐妹闺蜜说说11-20
《绿山墙的安妮》阅读检测题等03-14
- 多层物业服务方案
- (审判实务)习惯法与少数民族地区民间纠纷解决问题(孙 潋)
- 人教版新课标六年级下册语文全册教案
- 词语打卡
- photoshop实习报告
- 钢结构设计原理综合测试2
- 2014年期末练习题
- 高中数学中的逆向思维解题方法探讨
- 名师原创 全国通用2014-2015学年高二寒假作业 政治(一)Word版
- 北航《建筑结构检测鉴定与加固》在线作业三
- XX县卫生监督所工程建设项目可行性研究报告
- 小学四年级观察作文经典评语
- 浅谈110KV变电站电气一次设计-程泉焱(1)
- 安全员考试题库
- 国家电网公司变电运维管理规定(试行)
- 义务教育课程标准稿征求意见提纲
- 教学秘书面试技巧
- 钢结构工程施工组织设计
- 水利工程概论论文
- 09届九年级数学第四次模拟试卷
- ZedBoard
- 基于
- Webcam
- 设计
- 儿童发展讲义(中学)
- 凯发苑四期临时用电专项方案
- 合作合同补充协议范本
- 大数定律及其应用( 刘胜举200702014001)
- 2013最新《低碳经济》试题汇总
- 秋五年级数学上册54小数点向左移动引起小数大小变化的规律
- 扬州西区大润发选址的商圈分析
- 关于针对高考英语作文满分法宝
- 本科毕业论文格式参照
- 党员日记材料
- 第三届小学数学希望杯四年级第一试试题
- 商业银行信用风险压力测试的宏观因子测定
- 张掖丹霞赋评析(常江) - 图文
- 2012年湄洲湾电厂“十八大”保电方案
- 第三节 函数的单调性与最值
- 山煤集团东古城矿防灭火方案设计(修改)20111024 - 图文
- 人教版初中数学八年级上册同步练习试题及答案 - 第20章
- 某遗址博物馆建设项目可行性研究报告
- 寻甸县殡仪服务中心建设项目可行性研究报告
- 二年级造句