这是一个文章系列的一部分,介绍基于MK802这类MiniPC的扩展开发,并展示他在计算机视觉、机器人控制方面的潜能
欢迎转载,但请保留原始作者信息(Shikai Chen, http://www.csksoft.net),以及指向本文原始出处的链接!
访问目录:基于MK802 MiniPC的扩展开发应用-简介篇(http://www.csksoft.net/blog/post/mk802_dev_intro.html)
revision: 0
这里将介绍MK802这类基于Cortrex A8/A9相对于Arduino这类单片机开发版、树梅派、以及PC对于爱好者来说最具有吸引力的优势所在:性能足够强大,可以运行OpenCV这类库的视觉算法,同时体积足够小,也相对于PC足够的省电。
这篇文章正是介绍如何在MK802上使用OpenCV库并利用它进行计算视觉相关应用的开发的。在我实际使用的体验来看,OpenCV在MK802上运行的性能虽然相比PC还有一些差距,一些复杂的算法运行的较慢,但是大部分的算法都可以满足需求。并且如果进一步的优化后,相信可以有更多的性能提升。
需要注意的是本文并不是OpenCV以及计算机视觉方面的教程,对于涉及到的一些视觉算法的知识以及OpenCV本身的背景知识,还需要读者自行学习。本文将着重关注如何在MK802这类MiniPC上使用OpenCV这个问题。
1. 在MK802上使用USB摄像头实现视觉感知
要用MK802进行计算机视觉处理,最直接的手段就是使用摄像头。由于MK802已经带有USB2.0高速接口了,因此绝大多数市面上常见的usb摄像头都可以用于MK802。
对于其他接口类型的摄像头,比如最底层的CSI接口,虽然MK802所用的Allwinner A10 CPU带有他们的总线,可惜MK802并没有把这些信号引出,因此我们不做讨论了。
另外对于IP摄像头,由于数据使用网络通讯,因此MK802也可以直接使用。对于IPCam大家更应该关注如何在OpenCV中获取他的图像的问题(通过厂家的SDK?或者提供了标准的通讯接口,如rtsp协议)。这些本文也不做探讨。
这里再次提醒一下各位:在MK802上使用摄像头,需要使用按照我前文[1]描述的方式,编译内核将对应的摄像头驱动和video4liunx驱动框架加入系统内核。如果你采用的是目前其他人打包的系统镜像或者没有将这些驱动加入内核中,则无法使用usb摄像头。具体可以参考我之前的文章[1]。
另外这里介绍的过程其实对于所有Linux系统都有效,并不特别针对MK802。
1.1. USB摄像头的选取
目前市面绝大多数的usb摄像头都可以被MK802支持,但也不排除不支持的型号。这里我给出一个基本的选择标准供大家参考。
基本原则是:
摄像头使用的DSP芯片方案具有Linux驱动支持
摄像头的数据可以通过标准的API获取
MK802的运算性能能够承受摄像头的数据
这里先从最后一项说起,提及这条的原因是目前市面的一些高清摄像头使用了H.264甚至更高级的视频编码来压缩USB2.0高速总线已经无法承受的高清数据量。对于这类摄像头,就需要在主机这段将编码压缩的视频信息重新解码。这样的运算量并不亚于对于高清视频的解码任务。由于目前MK802所采用的Allwinner A10芯片中视频解码SOC部分均没有传统linux的驱动,因此对于MK802将采用软解码的方式来处理这类摄像头的画面。按MK802的性能,处理720p视频的软解码已经是承重的负担了,即使勉强可以达到原始摄像头的输出帧率,也没有额外的CPU资源供用于后期的计算机视觉计算了。
对于第二点,对于一些摄像头采用了厂家自己的视频传输格式或者因为摄像头的特殊性(比如深度摄像头),他的输出画面并不能通过传统的Linux视频捕获接口(Video4Linux[2])获得。对于这类摄像头即使我们拥有它在Linux Kernel层次的驱动,但只要没有厂家提供的SDK支持,也无法正常的获得他的图像。想微软的Kinect传感器,在几年前就是这样一种状态,后来随着社区的深入挖掘,才使得获取他的数据成为可能。
不过前面提到的情况一般都是个别现象,主要的问题还是摄像头DSP芯片方案本身是否具有Linux驱动了。这里先简单介绍下目前USB摄像头的大致构成框图:
图:典型的USB摄像头的内部构成
上图是目前典型的USB摄像头的内部构成框图。这里我们关注其中一般会出现的2类芯片:
感光芯片
该芯片主要负责感受光学系统投影而来的外界画面,并转换成原始的图像信号输出。这类芯片是无法直接与外部USB信号连接的,一方面是他输出的图像格式并不符合usb总线的协议要求。另外usb总线的带宽可能也无法负担这类芯片原始输出的数据量。
(虽然目前这类感光芯片自身也带有一定的DSP处理能力,甚至可以直接输出mjpeg压缩过的视频流或者usb信号,但这里还是对他们做这样的划分)
图像处理和接口芯片
这类芯片主要就是一个DSP,负责将感光芯片输出的原始图像数据(一般是Bayer Pattern格式[3])重新转换成YUV格式或者RGB格式的标准图像点阵数据,并将它们打包成USB协议加以传输。
如果摄像头的数据量超过了USB带宽,这类芯片将负责进行视频编码压缩,将数据量降低。
另外这类芯片还有一个重要的功能,就是对感光芯片进行配置。比如设置感光芯片的曝光率、饱和度等参数。
对于涉足过直接驱动感光芯片的工作的人来说,会清楚对于这类芯片的初始化是一个繁琐的事情,基本上每种型号的芯片的配置参数都是不同的。而在这里,usb摄像头由于使用了图像处理和接口芯片,这类不同感光芯片的差异一般就被封装在这类芯片的固件逻辑里了(也有在Linux驱动部分的)。
因此对于usb另一头的主机驱动来说,直接与它打交道的并不是感光芯片,而是图像处理和接口芯片。换句话说,一个摄像头拥有如何的分辨率、画质,对我们并不重要。重要的只是他用了什么样的图像处理和接口芯片。
要了解某一个接口芯片是否具有Linux Kernel驱动,最简单的办法就是回到前文[1]提到的进行linux kernel编译的配置阶段。可以在menuconfig中查看是否列出了这款芯片:
图:V4L框架支持的芯片列表
不过在购买USB摄像头的时候是很难知道其中使用了什么样的接口芯片的。不过这里还有一个选择的依据:一般UVC(USB video device class)协议[4]的摄像头都会得到支持。
图:Linux Kernel中使用了同一个驱动处理所有符合UVC规范的设备
所谓UVC协议,是标准化了的USB视频设备类型所具有的usb传输协议。所有才有这个协议的USB摄像头(以及其他设备),都采用同一套协议进行传输数据。因此在主机上也使用同一个(同一种)驱动程序。这类摄像头其实就是目前常说的免驱动摄像头。因为在Windows上已经自带了对UVC类设备的支持了。
也正因为如此,对使用UVC标准的摄像头,理想情况下他们都是可以在Linux下使用的。不过实际Linux对UVC类设备的驱动支持并不完美,仍旧有一些符合UVC规范的摄像头不能很好的工作。但好消息是在Linux UVC驱动的开发者网站上有一份兼容性列表供大家参考[5]。
另外还可以参考OpenWRT项目[6]的网站,他们也维护了一份支持的USB摄像头列表[7]。虽然MK802并不使用OpenWRT,但是它们都是Linux系统。
目前中低端摄像头大多数采用的是中芯微[8]的接口,这类摄像头都可以在Linux下工作。
1.2. 判断摄像头驱动程序已经工作
将USB摄像头连接到MK802后,有一个快捷有效的办法判断这款摄像头是否已经被驱动支持:使用dmesg查看kernel log。
一般当摄像头接入设备后,对应的驱动的程序将打印出日志提示发现了该摄像头设备,并且显示出设备的路径供后续使用。如下图就是我使用的USB摄像头在接入设备后看到的日志。
在连接usb摄像头后不久在MK802执行如下命令:
图:通过dmesg输出判断摄像头是否已经被系统支持
当然,正如前文所说,光有Linux kernel驱动的支持还不能完全判断摄像头就能使用。因此我们需要通过预览摄像头的输出图像来做最终的判断。
1.3. 摄像头画面的预览和配置
这里介绍一些Linux下好用的小工具介绍如何预览摄像头画面以及进行配置。
GUVCViewer
这是一个运行在图形系统下面的工具,如果使用的是UVC摄像头,就可以用它完成画面的预览、摄像头参数的配置的操作。功能上很类似于微软在DirectX sdk中的amcap例子程序[9]
可以使用apt-get命令安装
随后输入命令guvcview来启动该程序(需要在图形界面的终端输入,如果在ssh下输入,请先执行一句:export DISPLAY=:0)
该程序将尝试打开目前连接在系统中的第一个摄像头,并开始预览,下面是其运行截图:
图:guvcview的工作界面
通过这个工具可以完成对摄像头各项参数的设置。
v4l2-ctl
这是一个纯命令行的工具,因此适用性很强,可以被脚本甚至程序调用对摄像头进行参数的配置。
使用apt-get安装此命令:
该命令的完整使用大家可以自行查阅文档。这里例举常用的命令
查看目前所有v4l设备:
将得到类似如下的输出:
列出摄像头的属性:
(如果摄像头不是/dev/video0这个设备,请更改上述命令)
将得到指定摄像头的各类信息,如下列输出:
Driver Info (not using libv4l2):
Driver name : uvcvideo
Card type : Altair USB2.0 Camera
Bus info : usb-sw-ehci-1.1
Driver version: 1.1.0
Capabilities : 0x04000001
Video Capture
Streaming
Format Video Capture:
Width/Height : 640/480
Pixel Format : 'YUYV'
Field : None
Bytes per Line: 1280
Size Image : 614400
Colorspace : SRGB
Crop Capability Video Capture:
Bounds : Left 0, Top 0, Width 640, Height 480
Default : Left 0, Top 0, Width 640, Height 480
Pixel Aspect: 1/1
Video input : 0 (Camera 1: ok)
Streaming Parameters Video Capture:
Capabilities : timeperframe
Frames per second: 30.000 (30/1)
Read buffers : 0
可以看到目前我使用的摄像头支持30fps,640x480 YUV2的输出格式。
列出对当前摄像头有效的配置选项:
(如果摄像头不是/dev/video0这个设备,请更改上述命令)
将得到类似如下的输出:
图:所有被当前摄像头所支持的配置选项
这个列表中的出现的项目都是可以设置的,比如上图所示,我目前的摄像头可以进行曝光率(exposure_absolute项目)的调节,在视觉处理里面,曝光率调节会比较多用。因为摄像头默认的自动曝光很多时候会干扰算法运行。
设置某一项摄像头参数
可以对上面提到的配置选项进行设置,这里以设置固定曝光值为-10为例:
v4l2-ctl -c exposure_absolute=-10 #设置固定曝光为-10
对于其他方面的设置,大家可以按照自身摄像头的情况进行尝试。
2. 将OpenCV库运行于MK802
在介绍基于OpenCV的程序开发前,需要让OpenCV这个库存在于MK802当中,对此我们有2种方式,他们各自有优缺点,大家按照自身情况选择。
2.1. 使用apt-get获取ARM版本的OpenCV库
在MK802上准备OpenCV库的最简单方法就是使用apt-get直接安装。使用如下命令即可:
接下来apt将会为MK802安装上2.3版本的OpenCV库。
不过简单归简单,这样做的不足在于:
暂不支持更高版本的OpenCV,如果需要高版本的功能,则仍旧需要自己编译
Apt仓库的OpenCV可能没有针对Cortex-A8的CPU进行优化(比如没有使用neon指令),性能上不如自己优化编译的
如果需要交叉编译,仍旧需要在PC上准备对应的OpenCV库
当然这些缺点并不是所有人都关心的,对于想快速在MK802上体验OpenCV的人,我比较推荐这样做。
2.2. 在PC上交叉编译OpenCV库
这是一种比较折腾的方式,好处就是定制的空间很大。一来可以把代码针对A8芯片的特性优化(主要是使用NEON指令集优化,它好比是x86用的SSE指令),另外就是可以把不需要的OpenCV组件排除,减小文件的体积。
2.2.1. 编译依赖库
这里假设我们的OpenCV程序不需要图形界面,因此可以省略对于图形库(QT/GTK)的依赖。同时不需要视频流的支持(排除gstreamer的依赖)
则最少需要如下的依赖库:
libjpeg
libpng
zlib
由于OpenCV依赖的是ARM平台版本的这些库文件,因此我们也需要下载他们的代码并完成交叉编译。
这里给出我交叉编译采用的库版本和下载地址:
库名 | 版本 | URL |
Zlib | 1.2.7 | |
libjpeg | 8d | |
libpng | 1.5.13 | http://sourceforge.net/projects/libpng/files/libpng15/1.5.13/ |
交叉编译各库是一件比较枯燥却tricky的事情,这里我直接给出编译上述代码的命令,它的具体原理就是使用使用configure/make编译流程的交叉编译方式。(由于环境差异,这些命令未必能在你的系统上直接工作)
这里我们将所有的依赖库编译结果存放在~/crosscompile_root的位置(prefix)。这个位置在后续编译OpenCV库以及编译我们自己的程序都会用到。
将上述各库的代码的压缩包保存在~/dl下边。而编译过程中将代码解压缩到~/buildpool下。
为了灵活性,先设置如下环境变量:
export INSTALL_PREFIX=`pwd`/crosscompile_root
export DL_FOLDER=`pwd`/dl
export BUILD_FOLDER=`pwd`/buildpool
export CC=${COMPILE_PREFIX}gcc
编译zlib:
tar xf $DL_FOLDER/zlib-1.2.7.tar.gz
pushd zlib-1.2.7
./configure --prefix=$INSTALL_PREFIX
make
make install
popd
编译libjpeg
pushd jpeg-8d
./configure --host=arm-linux-gnueabihf --prefix=$INSTALL_PREFIX
mkdir -p $INSTALL_PREFIX/bin
mkdir -p $INSTALL_PREFIX/man/man1
make
make install
popd
编译libpng
pushd libpng-1.5.13
./configure --host=arm-linux-gnueabihf --prefix=$INSTALL_PREFIX CPPFLAGS=-I$INSTALL_PREFIX/include LDFLAGS=-L$INSTALL_PREFIX/lib
make
make install
popd
完成上述过程后,可以在~/crosscompile_root目录下看到如下目录结构:
图:~/crosscompile_root包含的编译结果
2.2.2. 编译OpenCV本身
OpenCV的源代码可以在由WillowGarage推管的OpenCV项目网站[10]下载到。我使用的版本是2.3.1a (目前2.4的稳定版本已经发布)
编译OpenCV需要使用cmake工具,可以用apt-get下载安装。
随后解压缩下载过来的OpenCV源代码压缩包(OpenCV-2.3.1a.tar.bz2)。这里假设OpenCV的代码解压缩到了~/OpenCV-2.3.1
随后进行OpenCV的configure过程。可以在~/OpenCV-2.3.1目录下创建一个build目录,用于保存cmake产生的Makefile和中间编译结果:
mkdir build
随后,进入build目录进行cmake的配置。由于我们要进行交叉编译,而OpenCV的CMake脚本对交叉编译支持的并不好,因此这里要做比较多的修改。
编写Cmake Toolchain配置脚本:
将下列语句保存于文件toolchain.cmake,存放在build目录下:
set( CMAKE_SYSTEM_PROCESSOR arm )
set( CMAKE_C_COMPILER arm-linux-gnueabihf-gcc )
set( CMAKE_CXX_COMPILER arm-linux-gnueabihf-g++ )
set( CMAKE_LIBRARY_PATH ~/crosscompile_root/lib ${CMAKE_LIBRARY_PATH})
set( CMAKE_INCLUDE_PATH ~/crosscompile_root/include ${CMAKE_INCLUDE_PATH})
上述代码设置了使用armhf规范的gcc作为交叉编译工具,并且将库和头文件查找路径指向了~/crosscompile_root目录
随后执行命令:
接下来cmake将产生对应的Makefile并总结配置情况:
图:Cmake完成OpenCV的配置结果
这里我们还需要进行进一步设置,比如去取消对测试代码、python等的支持,可以使用ccmake这个工具(请使用apt-get安装):
在build目录下执行:
图:ccmake进行其他编译参数设置
这里可以按照每个人喜好做出一些微调,完成后按c键配置,并按q退出。
最后就使用传统的make和make install命令完成对OpenCV的交叉编译和发布。
OpenCV的编译需要一定时间,一般在十分钟左右。如果编译过程顺利,我们可以进入目录~/crosscompile_root/lib看到我们交叉编译的OpenCV库和它的依赖库:
图:交叉编译产生的各库
这些库将用于后面交叉编译我们开发的基于OpenCV库的程序。并且在发布程序的时候,需要将他们一起部署到MK802上。
3. 在程序中使用OpenCV库
3.1. 简单的验证程序
这里使用如下程序验证程序已经可以使用OpenCV的功能了。并且这个程序也可以用于在没有图形界面条件下验证摄像头是否可以工作。
#include <opencv2/opencv.hpp>
int main( int argc, char * argv[] ) {
// grab one frame from the camera specified via arg[1]
int camera_id = 0;
if (argc > 1) camera_id = atoi(argv[1]);
cv::VideoCapture cap(camera_id);
if(!cap.isOpened()) // check if we succeeded
{
printf("failed to open the camera with id %d.\n", camera_id);
return -1;
}
// capture one frame
cv::Mat frame;
cap >> frame; // get a new frame from camera
// save to file
imwrite("camera_captured.png", frame);
return 0;
}
这段程序的完整代码可以在本系列文章演示程序的github项目中找到:
程序本身逻辑是打开用户通过命令行参数输入的摄像头设备,并且捕获一帧画面,然后以png格式保存到当前目录下(camera_captured.png)。
3.2. 交叉编译
这里可以直接下载上面提到的github项目,使用git clone到本地:
随后进入mk802_demo目录,使用如下命令进行交叉编译配置:
如果你有看过上一篇文章的话,会发现这里多了prefix命令参数。该参数在会被我的编译脚本识别用于搜索OpenCV库头文件以及库文件的路径。
如果你按照上文交叉编译的办法编译了OpenCV,此时~/crosscompile_root已经包含了OpenCV的头文件和代码了,可以直接继续。如果你采用的是在MK802使用apt-get安装openCV库的做法,这里可以将MK802上openCV的库(参考上文的截图)以及头文件复制到~/crosscompile_root的lib以及include目录下即可。或者采用后文的本机编译办法。
在完成了配置后,可以直接在mk802_demo目录下输入make命令,此时所有的实例程序都会自动编译,并且结果存放在.output/armv7l下面。
随后使用scp命令可以把这些执行程序复制到MK802上,具体过程和[11]的描述一样,这里不再重复。
随后登录到MK802上,连接好摄像头,使用如下命令执行这里编译的程序(simple_opencv_validator):
由于是纯命令行程序,执行过程中并不会有什么输出画面。不过我们可以在本程序的根目录下找到保存好的摄像头画面:
图:执行测试程序后可以看到保存得到的图像文件
使用scp将camera_captured.png文件传回PC,可以看到摄像头采集到的画面了:
图:在pc上查看我们程序抓取的摄像头画面
3.3. 本机编译
本机编译过程其实与交叉编译一样,可以直接在MK802上使用git clone下载代码,并用
make
命令简单的完成所有的编译任务。这部分细节和交叉编译部分一样,就不在重复了。需要注意的是由于MK802性能相对PC较弱,本机编译将花费比PC上交叉编译长的多的时间。
4. 实例:在MK802上通过OpenCV捕捉摄像头视频,并显示在VFD显示屏上(cam2vfd)
这里我们结合前文[11]介绍的MK802通过串口与外部设备通讯的功能,介绍一个从摄像头捕获的图像经过OpenCV简单处理后,在VFD屏幕上显示的例子。
该实例的代码可以在github中找到:
他的运行效果可以参考如下视频:
4.1. 硬件构成
这个例子中用到了一个128x64分辨率的单色VFD屏幕。使用VFD屏幕只是为了好看,大家可以替换成其他类型的屏幕。
图:本实例使用的VFD屏幕
该屏幕使用一颗STM32 Cortex-M3的MCU驱动,我修改了他的固件,使得其能够通过串口按照我所设计的协议接受图像并且显示。
我将STM32的串口设置在230400bps上,这样对于128x64的单色图像,这里用到的VFD屏幕可以实现高达20fps的刷新率,可以满足比较流畅的画面显示。
该屏幕通过USB转串口适配器,连接到了MK802的USB口上。这样我可以编写程序将OpenCV的图像数据(CvMat)透过串口发送到屏幕。
4.2. 在VFD屏幕上显示图像
4.2.1. 串口通讯协议
包内偏移量 | 数据内容 | 描述 |
0 | 0xa5 0xa5 0xa5 0xa5 | 用于数据同步的起始标识 |
4 | 128x64 bit (1024byte)的帧数据 | 用于显示在128x64单色VFD上的画面数据 |
4.2.2. 通讯代码库
为了能够方便的将OpenCV的图像数据(CvMat)显示到VFD上,我为此编写了一个函数库,代码可以在如下地址获取:
该函数库接受一个128x64字节的uint8_t型数据,并且将它转化成1bit像素深度,并做出必要的行列对应映射,以符合我们的屏幕显示需要,最后将画面缓存到一个显示队列中并逐个通过串口提交到屏幕。
在后续的各例子中都会运用函数库。
图:用于VFD显示的函数库
4.3. 画面的处理
虽然这个例子看似很简单的将摄像头画面现在到VFD,但还需要做几个必要的图像处理:
1. 将摄像头捕捉到的图像缩放到128x64分辨率
由于采用的摄像头原始画面是640x480。图像的比例(4:3)与128x64(2:1)不服,因此这里的缩放操作要在保持比例的情况下进行画面的裁剪,将画面中部的部分保留下来。
2. 将RGB的彩色图像转化为8bit深度的灰度图
3. 将8bit的灰度图做二值化(Thresholding )[12]处理
由于VFD是单色屏幕,无法显示色彩的深浅程度(灰度),如果直接将第二步的灰度图像显示,将得到一片白的画面。所以需要进行二值化操作。
图:摄像头画面在MK802中经历的图像处理最终得以显示
经历了这些动作后,就得到了前面演示视频中的效果了。
这部分的代码可以见如下地址:
按照上文的过程完成对整个实例项目的编译后,使用如下命令就能看到演示效果:
图:本实例的运行效果图
在后续介绍的实例中,都会用到这里例子中采用的图像处理算法将处理结果在VFD屏幕上显示。
5. 实例:在MK802上进行前景提取视觉运算(cam2vfd_fg)
在前一个实例的基础上,我们稍微增加视觉计算的复杂量,看看MK802对于一些稍微复杂的算法的运行效率。
在前一个例子中我只是简单的将摄像头拍摄的画面经过二值化处理后显示在VFD屏幕上。但这样的效果并不是很理想,毕竟单色的屏幕表现力实在有限,很容易将前景和背景画面混合在一起(只有一种色彩)。这里我们使用OpenCV自带的称为BackgroundSubtractorMOG[13]的背景提取类来实现将背景画面剥离,仅显示前景的处理。算法的处理效果可以看下图的对比:
直接将摄像头画面显示在VFD上
采用前景提取后的效果
图:原始摄像头画面和采用前景提取后的效果对比
可以从上面的对比图中明显的感觉到在使用前景提取后,VFD显示的画面变得非常清爽直观。仅仅包含了画面中的前景部分(手臂)。
这类算法在实际应用中具有很高的实用价值,比如通过提取的前景画面做移动物体的跟踪和识别。并且我发现MK802运行该算法性能也不错,可以达到将近20fps的水平。下面是一段实际演示的录像:
程序的代码和使用
同样该程序的代码可以在github的项目中找到,他的项目目录在:
程序代码可以通过前文介绍的方式进行本机或者PC上的交叉编译。在编译完成并发布至MK802后可以使用如下命令执行:
程序将在启动的一开始将摄像头捕捉到的画面作为背景进行学习。此时将需要作为前景的物品从摄像头视野中移开。当学习过程完成后,就会出现类似上图效果图的画面。
图:进行背景学习的提示画面
图:利用前景提取,识别桌面上的物品
6. 小结
这篇文章中介绍了MK802对我们最具吸引力的能力:可以使用OpenCV配合摄像头画面进行计算机视觉相关的算法。并且我通过几个实例向大家做了示范。在下一篇文章中我将介绍更多的例子。
这里提到的方法其实比不只针对MK802,大家同样可以将他们运用到其他的MiniPC以及PC上。
7. 参考文献
[1] 基于MK802 MiniPC的扩展开发应用-系统自制
http://www.csksoft.net/blog/post/mk802_dev_sysbuild.html
[2] Video for Linux (V4L) framework
http://en.wikipedia.org/wiki/Video4Linux
[3] Bayer Pattern
http://en.wikipedia.org/wiki/Bayer_filter
[4] USB video device class
http://en.wikipedia.org/wiki/USB_video_device_class
[5] Linux UVC driver and tools
http://www.ideasonboard.org/uvc/
[6] OpenWRT- A GNU/Linux based firmware program for embedded devices such as residential gateways and routers.
https://openwrt.org/
[7] USB Video Support
http://wiki.openwrt.org/doc/howto/usb.video
[8] 中芯微
http://www.vimicro.com.cn/
[9] AmCap Sample (Windows)
http://msdn.microsoft.com/en-us/library/windows/desktop/dd373424(v=vs.85).aspx
[10] OpenCV Website
http://opencv.willowgarage.com/wiki/
[11] MK802与外部硬件设备的通讯
http://www.csksoft.net/blog/post/mk802_dev_communication.html
[12] Thresholding (image processing)
http://en.wikipedia.org/wiki/Thresholding_(image_processing)
[13] Gaussian Mixture-based Background/Foreground Segmentation Algorithm in OpenCV
http://docs.opencv.org/modules/video/doc/motion_analysis_and_object_tracking.html