linux 从摄像头采集一帧 jpg,基于Video4Linux 的USB 摄像头图像采集实现.pdf

基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 1 基于基于 Video4Linux 的的 USB 摄像头图像采集实现摄像头图像采集实现 Write by daily3 戴小鼠 著作权 戴丽 合肥工业大学 email daily3 做了一段时间的摄像头图像采集 有了一些心得 在论坛上开的2410摄像头 问题专贴 zImage make modules然后就在 driver usb下生成ov511 o 同 时生成的zImage自动放在 tftpboot下 6 然后用新内核启动板子后insmod ov511 o就可以成功加载 动态方式与静态方式相比 测试时要简单的多 不需要下载整个内核 只需 通过nfs 加载驱动即可测试 在测试成功后就可以编译进内核 模块加载中出现的问题 1 insmod 和 modprobe 间的一个区别试后者不会在当前目录中查找模块 它只 在 lib modules 下的缺省目录下查找 这是因为该程序只是一个系统实用例程 不是一个交互工具 可以通过在 etc modules conf 中指定自己的目录 来把它们 加到缺省目录集中 2 如果插入模块 ov511 o 时 出现以下信息 Ov511 o unresolved symbol video 之类的 说明还有其它模块 videodev o 没有加 3 出现错误 ov511 o couldn t find the kernel version this modules was compiled for 这是试图插入一个不是可装入模块的目标文件 因为在内核配置阶段 是 把 ov511 模块静态加到内核中的 虽然看起来和可装入模块的文件名 ov511 o 完 全一样 但是不能用 insmod 命令加入 4 如果出现 Ov511 o unresolved symbol video 那就选中 video for linux 用新生成的内核启动系统 再 insmod videodev o insmod ov511 o 就可以啦 1 2 zc301 驱动驱动 摄像头的驱动是从http mxhaard free fr 下的针对embeded环境 有专门的patch 我用的是usb 2 4 31LE06 patch 1 把它放到 HHARM9 EDU kernel driver usb下 解压 打补丁 就会在此目 录下看到spca5xx文件夹了 可能会有一些错误 我的错误是在Makefile和config in 文件中 根据它的提示 进行相应的修改即可 Patch时会将修改方法写到 Makefile rej和config in rej文件中 把这两个文件里的内容加到Makefile和config in 中就行了 2 编译内核 进入 HHARM9 EDU kernel make menuconfig 我采用和上面 介绍的ov511驱动的方法一样 动态加载 M 选中SPCA5XX这一项 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 3 3 make dep make zImage make modules 就 会 在 HHARM9 EDU kernel driver usb spca5xx中生成 spca5xx o spcadecoder o spca core o啦 这就是我们要的驱动 4 用新内核启动 insmod这三个 o文件 可以不用加载spcadecoder o 摄像 头就加载成功啦 不过这种LE的驱动有许多问题 比如运行到设置图像格式 RGB565或RGB24 时 出 错 说 不 支 持 此 参 数 原 因 在 于 摘 自 驱 动 程 序 主 页 http mxhaard free fr spca5le html The spca5xx LE design is very different from the spca5xx full package LE版的驱动 和完全版的差很多 The memory in use are the most smaller as possible LE版的驱动会尽量减少内存的 使用 The spcadecoder is reduce and only raw jpeg webcam are used 驱动模块只支持输 出原始jpeg格式 还 有 一 种 方 法 从 http mxhaard free fr download html 下 载 最 新 的 驱 动 spca5xx 20060402 tar gz 这个可独立编译 无需放到linux内核里面 编译生成一个spca5xx o 即可 不要三个 o做驱动了 因为这个驱动是针对2 6的 编译时会出现很多错误 修改 CFLAGS即可 华恒的群里已经有编译好的驱动提供大家下载 模块加载中出现的问题 1 运行 servfox时出现Error Opening V4L interface 我测试一下 是没有加载驱动 虽然内核中 M 选中了驱动 但是启动后要手 工加进去 insmod一下啦 2 insmod spcadecoder o时 出现错误 spcadecoder o couldn t find the kernel version this modules was compiled for 如果你insmod spca5xx o成功的话就不需要再 insmod其他模块了 3 insmod video o时却说can t find the kernel version the modules was compiled for 这是因为video for linux一般是直接编译到内核中去的 不需要加载的 二二 Video4linux 编程编程 2 1 Video4linux 简介简介 Video4Linux是为市场现在常见的电视捕获卡和并口及USB口的摄像头提供 统一的编程接口 同时也提供无线电通信和文字电视广播解码和垂直消隐的数据 接口 本文主要针对USB摄像头设备文件 dev video0 进行视频图像采集方面的 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 4 程序设计 2 2 Video4linux 编程指南编程指南 1 视频编程的流程 1 打开视频设备 2 读取设备信息 3 更改设备当前设置 可以不做 4 进行视频采集 两种方法 a 内存映射 b 直接从设备读取 5 对采集的视频进行处理 6 关闭视频设备 定义的数据结构及使用函数 struct v4l struct int fd struct video capability capability struct video buffer buffer struct video window window struct video channel channel 8 struct video picture picture struct video mmap mmap struct video mbuf mbuf unsigned char map typedef struct v4l struct v4l device extern int v4l open char v4l device extern int v4l close v4l device extern int v4l get capability v4l device extern int v4l set norm v4l device int extern int v4l get picture v4l device extern int v4l grab init v4l device int int extern int v4l grab frame v4l device int extern int v4l grab sync v4l device extern int v4l mmap init v4l device 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 5 extern int v4l get mbuf v4l device extern int v4l get picture v4l device extern int v4l grab picture v4l device unsigned int extern int v4l set buffer v4l device extern int v4l get buffer v4l device extern int v4l switch channel v4l device int 3 Video4linux支持的数据结构及其用途 1 video capability 包含设备的基本信息 设备名称 支持的最大最小分辨 率 信号源信息等 name 32 设备名称 maxwidth maxheight minwidth minheight Channels 信号源个数 type 是 否 能 capture 彩 色 还 是 黑 白 是 否 能 裁 剪 等 等 值 如 VID TYPE CAPTURE等 2 video picture 设备采集的图象的各种属性 Brightness 0 65535 hue colour contrast whiteness depth 8 16 24 32 palette VIDEO PALETTE RGB24 VIDEO PALETTE RGB565 VIDEO PALETTE JPEG VIDEO PALETTE RGB32 3 video channel 关于各个信号源的属性 Channel 信号源的编号 name tuners Type VIDEO TYPE TV IDEO TYPE CAMERA Norm 制式 PAL NSTC SECAM AUTO 4 video window 包含关于capture area的信息 x x windows 中的坐标 y y windows 中的坐标 width The width of the image capture height The height of the image capture chromakey A host order RGB32 value for the chroma key 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 6 flags Additional capture flags clips A list of clipping rectangles Set only clipcount The number of clipping rectangles Set only 5 video mbuf 利用mmap进行映射的帧的信息 size 每帧大小 Frames 最多支持的帧数 Offsets 每帧相对基址的偏移 6 video mmap 用于mmap 4 关键步骤介绍 注 接多个摄像头 方法如下 买一个usb hub接到开发板的usb host上 cat proc devices可以知道video capture device的major是81 再ls l dev看到video0 的次设备号是0 两个摄像头当然要两个设备号 所以mknod dev video1 c 81 1 如果接4个 就mknod dev video2 c 81 2 mknod dev video3 c 81 3 依次类推 1 打开视频 int v4l open char dev v4l device vd if dev dev dev video0 if vd fd open dev O RDWR fd VIDIOCGCAP if ioctl vd fd VIDIOCSPICT for i 0 i capability channels i vd channel i channel i if ioctl vd fd VIDIOCGCHAN return 0 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 8 重点 截取图象的两种方法 一 用mmap 内存映射 方式截取视频 mmap 系统调用使得进程之间通过映射同一个普通文件实现共享内存 普 通文件被映射到进程地址空间后 进程可以向访问普通内存一样对文件进行访 问 不必再调用read write 等操作 两个不同进程A B共享内存的意思是 同一块物理内存被映射到进程A B各自的进程地址空间 进程A可以即时看到进 程B对共享内存中数据的更新 反之亦然 采用共享内存通信的一个显而易见的好处是效率高 因为进程可以直接读写 内存 而不需要任何数据的拷贝 1 设置picture的属性 2 初始化video mbuf 以得到所映射的buffer的信息 ioctl vd fd VIDIOCGMBUF 若调用成功 开始一帧的截取 是非阻塞的 是否截取完毕留给VIDIOCSYNC来判断 6 调用VIDIOCSYNC等待一帧截取结束 if ioctl vd fd VIDIOCSYNC 返回值为实际读写的字符数 int len unsigned char vd map unsigned char malloc vd capability maxwidth vd capability maxheight len read vd fd vd vd map vd capability maxwidth vd capability maxheight 3 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 10 2 3 编程实例 编程实例 mouse capture 不管是ov511还是zc301的摄像头 它们采集的方式都是相同的 只不过采集 到的数据有所差异 ov511的就是rgb的位流 而zc301是jpeg编码的位流 mouse capture是根据servfox改编的一个专门从zc301摄像头获取一张jpeg图片 用来测试摄像头是否加载成功的小程序 这样就可以不用cat dev video0 1 jpg来 测试摄像头是否正常 cat命令一运行 就源源不断地采集jpeg流 但是采到的图 片只能显示第一个jpeg头和jpeg尾之间的数据 mouse capture仅仅获得一张完整 的jpeg 可以从 static int SetVideoPict struct vdIn vd 设置图片属性 static int isSpcaChip const char BridgeName 测试芯片类型 static int GetStreamId const char BridgeName 测试输出数据的格式 static int GetDepth int format 获取颜色深度 void exit fatal char messages 错误显示 int init videoIn struct vdIn vd char device int width int height int format int grabmethod 初始化设备 int convertframe unsigned char dst unsigned char src int width int height int formatIn int size 把共享缓冲区中的数据放到一个变量中 通知系统已获得一 帧 int v4lGrab struct vdIn vd char filename 从摄像头采集图片 int close v4l struct vdIn vd 关闭摄像头 int get jpegsize unsigned char buf int insize 获取jpeg图片大小 三三 实例程序实例程序 3 1 LCD 实时显示从实时显示从 ov511 上采集的图像上采集的图像 参考HHARM9 EDU applications usbcam2lcd 从摄像头获取bmp位流直接显示 在framebuffer中 此程序图像的采集采用read的方式 注意由于lcd液晶屏显示的 是16bits的RGB图片 所以 ov511输出的图片格式也应该是16bits的RGB图片数 据 宏VIDEO PALETTE RGB565定义的就是16bits的RGB数据图片 而linux自 带的ov511驱动中图像采集是32位的 这样采集到的图片显示在lcd上是雪花点 因此需要修改驱动 在kernet driver usb 目录下有ov511芯片的驱动ov511 c 驱 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 11 动里的ov51x set default params函数是设置芯片默认的输出图片的格式 该函数 中的 for i 0 i frame i width ov511 maxwidth ov511 frame i height ov511 maxheight ov511 frame i bytes read 0 if force palette ov511 frame i format force palette else ov511 frame i format VIDEO PALETTE RGB24 ov511 frame i depth ov511 get depth ov511 frame i format 部分语句是主要设置ov511默认输出图片格式的 其中maxwidth和maxheight 设置了图片的最大的宽度和高度 Ifelse语句设置了图片的格式 作如下的修改 for i 0 i frame i width ov511 maxwidth ov511 frame i height ov511 maxheight ov511 frame i bytes read 0 ov511 frame i format VIDEO PALETTE RGB565 ov511 frame i depth ov511 get depth ov511 frame i format 如果需要 也可以改变图片的默认输出大小 3 2 LCD 实时显示从实时显示从 zc301 上采集的图像上采集的图像 编程思想 从摄像头采集到的图片存放在本地文件夹 通过minigui加载jpeg 来实现显示 具体过程 1 从网上下载jpegsrc 6b的jpeg库 交叉编译 1 configure enable static enable shared prefix libs 2 修改Makefile 将编译器改成交叉编译器 例如 我改成 opt host armv4l bin armv4l unknown linux gcc 3 make 后即在 libs目录中生成for arm的 libjpeg a libjpeg la libjpeg so libjpeg so 62 libjpeg so 62 0 0 将这些文件拷贝到系 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 12 统库文件目录 我的是 usr lib中 2 因为看从zc301采集的图片的二进制位流 jpeg头是ff d8 ff db 而在minigui库 文件libminigui的源文件src mybmp jpeg c中 load jpg和check jpg的时候测试的头 位EXIF和JFIF两种格式的jpeg图片 这两种对应的二进制分别是ff d8 ff e1和ff d8 ff e0 所以我们minigui通过判断认为这是错误的jpeg格式而不加载 故无法显示 实际上通过测试 在源码中去掉这两个判断就能正确加载 3 交叉编译minigui 1 编 译 库 configure host arm unknown linux enable jpgsupport yes enable pngsupport no enable gifsupport no disable lite prefix HHARM9 EDU applications minigui free nfsroot enable smdk2410ial yes make make install 2 编译实例程序时 要加上jpeg库的支持 即在Makefile中加上 ljpeg 此时 将在nfsroot生成的库文件和可执行文件移到ramdisk image gz相应的目录下 具 体参考华恒的2410开发手册 3 Minigui程序的编写 编程小技巧 我采取的方法是一刻不停地从摄像头采集到图片存储在 tmp 1 jpg中 在minigui中通过loadbitmap函数来加载图片 而图片加载后不会自 动更新 不能自动根据1 jpg的改变自动变化 因此 我在程序中设定一个timer 每隔100ms刷新屏幕 基本上实现实时更新了 而出现另外一个问题 刷新时会 以背景色来填充桌面 导致屏幕闪烁严重 故想到采用MSG ERASEBKGND的 方式 用前一张图片做为刷新屏幕时的填充背景图片 这样就保证了lcd上图像 的连续性啦 Minigui程序如下 其中一些自定义的函数跟mouse capture中的一样 只是 变采集单幅到采集多幅 具体您可以自己改一下 也可以向我索取源码 include include include include include include spcav4l h define IDTIMER 100 static BITMAP bmp 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 13 static int LoadBmpWinProc HWND hWnd int message WPARAM wParam LPARAM lParam HDC hdc RECT rc 0 0 240 320 switch message case MSG CREATE SetTimer hWnd IDTIMER 100 return 0 case MSG ERASEBKGND RECT rcTemp if LoadBitmap HDC SCREEN return 1 GetClientRect hWnd hdc BeginPaint hWnd FillBoxWithBitmap hdc rcTemp left rcTemp top rcTemp right rcTemp left rcTemp bottom rcTemp top EndPaint hWnd hdc return 0 case MSG TIMER InvalidateRect hWnd return 0 case MSG CLOSE UnloadBitmap DestroyMainWindow hWnd PostQuitMessage hWnd return 0 return DefaultMainWinProc hWnd message wParam lParam int MiniGUIMain int argc const char argv MSG Msg HWND hMainWnd MAINWINCREATE CreateInfo char videodevice dev video0 char jpegfile tmp 1 jpg int grabmethod 0 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 14 int format VIDEO PALETTE JPEG int width 240 int height 320 int i ifdef LITE VERSION SetDesktopRect 0 0 1024 768 endif CreateInfo dwStyle WS VISIBLE WS BORDER WS CAPTION CreateInfo dwExStyle WS EX NONE CreateInfo spCaption Load and display a bitmap CreateInfo hMenu 0 CreateInfo hCursor GetSystemCursor 0 CreateInfo hIcon 0 CreateInfo MainWindowProc LoadBmpWinProc CreateInfo lx 0 CreateInfo ty 0 CreateInfo rx 240 CreateInfo by 320 CreateInfo iBkColor PIXEL lightwhite CreateInfo dwAddData 0 CreateInfo hHosting HWND DESKTOP hMainWnd CreateMainWindow if hMainWnd HWND INVALID return 1 ShowWindow hMainWnd SW SHOWNORMAL memset if init videoIn else printf init is wrong n while GetMessage v4lGrab DispatchMessage close v4l MainWindowThreadCleanup hMainWnd return 0 ifndef LITE VERSION include endif 基于 Video4Linux 的 USB 摄像头图像采集实现 戴小鼠 daily3 15 先写到这里吧 呵呵 希望能对您有所帮助 如果您在阅读的过程中发现问 题 欢迎和我交流 2006 7 7 晚 参考文献参考文献 1 HHARM2410摄像头调试记录 华恒科技 2 基于video4linux的视频设备编程 Lingzhi Shi Apr 7 2004 3 video4linux programming Alan Cox 4 video streaming 探讨 陈俊宏 5 Video4Linux Kernel API Reference 6

展开阅读全文

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值