您的位置:首页 > 其它

(原创)基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集

2012-12-19 15:45 639 查看
一直想把USB摄像头接到Zedboard上,搭建一个简易视频监控系统方便后续做视频处理。Xilinx官方给出了一个Webcam摄像头监控的例子,跑的是linaro,不知道是我的SD卡问题还是摄像头的问题,播放视频的时候总是会很卡,而且突然系统就死掉了。还是很喜欢自己动手,能学到新东西。Digilent官方给的OOB设计,那个精简的linux足够做简单的linux开发了,而且OOB设计中USB驱动和V4L(Video for Linux)都提供好了。这几天找了一些的V4L的资料,完成了摄像头的单帧图片采集,接下来要做的是QT界面显示和视频流的显示了,最终的计划是完成视频采集、编码、存储和以太网传输。希望能有时间和精力完成这么多。先把这几天的做的东西整理出来和大家分享。为了方便大家对程序的理解,先简单介绍一下linux下的V4L2的一些知识,然后再详细介绍V4L2编程。

更多更新请关注我的博客:@超群天晴 http://www.cnblogs.com/surpassal/

相关阅读

(原创)基于ZedBoard的Webcam设计(一):USB摄像头(V4L2接口)的图片采集

(原创)基于ZedBoard的Webcam设计(二):USB摄像头图片采集+QT显示

(原创)基于ZedBoard的Webcam设计(三):视频的采集和动态显示

(原创)基于ZedBoard的Webcam设计(四):MJPG编码和AVI封装

(原创)基于ZedBoard的Webcam设计(五):x264编码在zedboard上的实现(软编码)

硬件平台:Digilent ZedBoard + USB 摄像头

开发环境:Windows XP 32 bit + Wmare 8.0 + Ubuntu 10.04 + arm-linux-xilinx-gnueabi交叉编译环境

Zedboard linux: 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。

View Code

int yuyv_2_rgb888(void)
{
int           i,j;
unsigned char y1,y2,u,v;
int r1,g1,b1,r2,g2,b2;
char * pointer;

pointer = buffers[0].start;

for(i=0;i<480;i++)
{
for(j=0;j<320;j++)
{
y1 = *( pointer + (i*320+j)*4);
u  = *( pointer + (i*320+j)*4 + 1);
y2 = *( pointer + (i*320+j)*4 + 2);
v  = *( pointer + (i*320+j)*4 + 3);

r1 = y1 + 1.042*(v-128);
g1 = y1 - 0.34414*(u-128) - 0.71414*(v-128);
b1 = y1 + 1.772*(u-128);

r2 = y2 + 1.042*(v-128);
g2 = y2 - 0.34414*(u-128) - 0.71414*(v-128);
b2 = y2 + 1.772*(u-128);

if(r1>255)
r1 = 255;
else if(r1<0)
r1 = 0;

if(b1>255)
b1 = 255;
else if(b1<0)
b1 = 0;

if(g1>255)
g1 = 255;
else if(g1<0)
g1 = 0;

if(r2>255)
r2 = 255;
else if(r2<0)
r2 = 0;

if(b2>255)
b2 = 255;
else if(b2<0)
b2 = 0;

if(g2>255)
g2 = 255;
else if(g2<0)
g2 = 0;

*(frame_buffer + ((480-1-i)*320+j)*6    ) = (unsigned char)b1;
*(frame_buffer + ((480-1-i)*320+j)*6 + 1) = (unsigned char)g1;
*(frame_buffer + ((480-1-i)*320+j)*6 + 2) = (unsigned char)r1;
*(frame_buffer + ((480-1-i)*320+j)*6 + 3) = (unsigned char)b2;
*(frame_buffer + ((480-1-i)*320+j)*6 + 4) = (unsigned char)g2;
*(frame_buffer + ((480-1-i)*320+j)*6 + 5) = (unsigned char)r2;
}
}
printf("change to RGB OK \n");
}


4、停止采集和关闭设备

使用命令VIDIOC_STREAMOFF停止视频采集,并关闭设备。

int close_v4l2(void)
{
ioctl(fd, VIDIOC_STREAMOFF, &buf_type);
if(fd != -1)
{
close(fd);
return (TRUE);
}
return (FALSE);
}


5、主函数

需要把我们采集到图像数据存储成图片,为了方便调试,先将原始的数据存储为yuv格式文件,再将转换成RGB后的数据存储为BMP。定义BMP头结构体

typedef struct tagBITMAPFILEHEADER{
WORD    bfType;                // the flag of bmp, value is "BM"
DWORD    bfSize;                // size BMP file ,unit is bytes
DWORD    bfReserved;            // 0
DWORD    bfOffBits;             // must be 54

}BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER{
DWORD    biSize;                // must be 0x28
DWORD    biWidth;           //
DWORD    biHeight;          //
WORD        biPlanes;          // must be 1
WORD        biBitCount;            //
DWORD    biCompression;         //
DWORD    biSizeImage;       //
DWORD    biXPelsPerMeter;   //
DWORD    biYPelsPerMeter;   //
DWORD    biClrUsed;             //
DWORD    biClrImportant;        //
}BITMAPINFOHEADER;


完整的主函数

//@超群天晴
//http://www.cnblogs.com/surpassal/
int main(void)
{

FILE * fp1,* fp2;

BITMAPFILEHEADER   bf;
BITMAPINFOHEADER   bi;

fp1 = fopen(BMP, "wb");
if(!fp1)
{
printf("open "BMP"error\n");
return(FALSE);
}

fp2 = fopen(YUV, "wb");
if(!fp2)
{
printf("open "YUV"error\n");
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("save "YUV"OK\n");

yuyv_2_rgb888();
fwrite(&bf, 14, 1, fp1);
fwrite(&bi, 40, 1, fp1);
fwrite(frame_buffer, bi.biSizeImage, 1, fp1);
printf("save "BMP"OK\n");

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]
grab yuyv 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上查看,效果还不错



=============================

完整工程和代码:lab_v4l2_yuyv.zip

可以指定任意分辨率摄像头的代码:v4l2grab_Anysize.rar 《感谢@jiaquwang分享》
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: