RGB ,YUV, YCbCr的定义

RGB ,YUV, YCbCr的定义

 

reference from:http://blog.163.com/fjm_1984/blog/static/1811445020073294227649/

 

YUV

视频编解码器功能 

视频编码器要求YUV4:2:0格式的视频输入,因此可能根据应用需要进行视频输入的预处理,即对YUV4:2:2隔行扫描(例如从摄像机)YUV 4:2:0非隔行扫描转换,仅抽取但不过滤UV分。对视频解码器而言,还需要进行后处理,以将解码的YUV 4:2:0数据转换为RGB进行显示,包括:YUV 4:2:0RGB转换;16位或12RGB显示格式;090度旋转,实现横向或纵向显示。此外,视频编解码器通常还要求具有以下功能和特性: 

支持MPEG-4简单类 0与 级; 

兼容H.263与 MPEG-4 编解码标准; 

MPEG-4视频解码器支持的可选项有:AC/DC预测、可逆可变长度编码(RVLC)、再同步标志(RM)、数据分割(DP)、错误隐藏专利技术、支持每个宏块4个运动矢量(4MV)、自由运动补偿、解码VOS层; 

MPEG-4视频编码器选项有:RVLCRMDP、支持每个宏块4个运动矢量(4MV)、报头扩展码、支持编码期间码率改变、支持编码期间编码帧率改变、插入或不插入可视对象序列起始码; 

支持编码期间序列中插入I帧; 

支持编码器自适应帧内刷新(AIR); 

支持多编解码器,可用相同代码运行多个编解码器实例。 

RGB

红绿蓝(RGB)是计算机显示的基色,RGB565支持的色深可编程至高达每像素16位,即 RGB565(红色5位,绿色6位,蓝色5)

YCbCr

DVD、摄像机、数字电视等消费类视频产品中,常用的色彩编码方案是YCbCr,其中Y是指亮度分量,Cb指蓝色色度分量,而Cr指红色色度分量。人的肉眼对视频的Y分量更敏感,因此在通过对色度分量进行子采样来减少色度分量后,肉眼将察觉不到的图像质量的变化。主要的子采样格式有YCbCr 4:2:0YCbCr 4:2:2 和 YCbCr 4:4:4。 

4:2:0表示每4个像素有4个亮度分量,2个色度分量(YYYYCbCr),仅采样奇数扫描线,是便携式视频设备(MPEG-4)以及电视会议(H.263)最常用格式;422表示每4个像素有4个亮度分量,4个色度分量 (YYYYCbCrCbCr),是DVD、数字电视、HDTV 以及其它消费类视频设备的最常用格式;444表示全像素点阵(YYYYCbCrCbCrCbCrCbCr),用于高质量视频应用、演播室以及专业视频产品。 

 

小知识:RGBYUV

计算机彩色显示器显示色彩的原理与彩色电视机一样,都是采用RRed)、Green)、BBlue)相加混色的原理:通过发射出三种不同强度的电子束,使屏幕内侧覆盖的红、绿、蓝磷光材料发光而产生色彩。这种色彩的表示方法称为RGB色彩空间表示(它也是多媒体计算机技术中用得最多的一种色彩空间表示方法)。

根据三基色原理,任意一种色光F都可以用不同分量的RGB三色相加混合而成。

F = r [ R ] + g [ G ] + b [ B ]

其中,rgb分别为三基色参与混合的系数。当三基色分量都为0(最弱)时混合为黑色光;而当三基色分量都为k(最强)时混合为白色光。调整rgb三个系数的值,可以混合出介于黑色光和白色光之间的各种各样的色光。

那么YUV又从何而来呢?在现代彩色电视系统中,通常采用三管彩色摄像机或彩色CCD摄像机进行摄像,然后把摄得的彩色图像信号经分色、分别放大校正后得到RGB,再经过矩阵变换电路得到亮度信号Y和两个色差信号RY(即U)、BY(即 V),最后发送端将亮度和色差三个信号分别进行编码,用同一信道发送出去。这种色彩的表示方法就是所谓的YUV色彩空间表示。

采用YUV色彩空间的重要性是它的亮度信号Y和色度信号UV是分离的。如果只有Y信号分量而没有UV分量,那么这样表示的图像就是黑白灰度图像。彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号。

YUVRGB相互转换的公式如下(RGB取值范围均为0-255):

Y = 0.299R + 0.587G + 0.114B

U = -0.147R - 0.289G + 0.436B

V = 0.615R - 0.515G - 0.100B

R = Y + 1.14V

G = Y - 0.39U - 0.58V

B = Y + 2.03U

DirectShow中,常见的RGB格式有RGB1RGB4RGB8、 RGB565RGB555RGB24RGB32ARGB32等;常见的YUV格式有YUY2YUYVYVYUUYVYAYUV、 Y41PY411Y211IF09IYUVYV12YVU9YUV411YUV420等。作为视频媒体类型的辅助说明类型(Subtype),它们对应的GUID见表2.3

2.3 常见的RGBYUV格式

GUID    格式描述

MEDIASUBTYPE_RGB1    2色,每个像素用1位表示,需要调色板

MEDIASUBTYPE_RGB4    16色,每个像素用4位表示,需要调色板

MEDIASUBTYPE_RGB8    256色,每个像素用8位表示,需要调色板

MEDIASUBTYPE_RGB565    每个像素用16位表示,RGB分量分别使用5位、6位、5

MEDIASUBTYPE_RGB555    每个像素用16位表示,RGB分量都使用5位(剩下的1位不用)

MEDIASUBTYPE_RGB24    每个像素用24位表示,RGB分量各使用8

MEDIASUBTYPE_RGB32    每个像素用32位表示,RGB分量各使用8位(剩下的8位不用)

MEDIASUBTYPE_ARGB32    每个像素用32位表示,RGB分量各使用8位(剩下的8位用于表示Alpha通道值)

MEDIASUBTYPE_YUY2    YUY2格式,以4:2:2方式打包

MEDIASUBTYPE_YUYV    YUYV格式(实际格式与YUY2相同)

MEDIASUBTYPE_YVYU    YVYU格式,以4:2:2方式打包

MEDIASUBTYPE_UYVY    UYVY格式,以4:2:2方式打包

MEDIASUBTYPE_AYUV    Alpha通道的4:4:4 YUV格式

MEDIASUBTYPE_Y41P    Y41P格式,以4:1:1方式打包

MEDIASUBTYPE_Y411    Y411格式(实际格式与Y41P相同)

MEDIASUBTYPE_Y211    Y211格式

MEDIASUBTYPE_IF09    IF09格式

MEDIASUBTYPE_IYUV    IYUV格式

MEDIASUBTYPE_YV12    YV12格式

MEDIASUBTYPE_YVU9    YVU9格式

下面分别介绍各种RGB格式。

¨ RGB1RGB4RGB8都是调色板类型的RGB格式,在描述这些媒体类型的格式细节时,通常会在BITMAPINFOHEADER数据结构后面跟着一个调色板(定义一系列颜色)。它们的图像数据并不是真正的颜色值,而是当前像素颜色值在调色板中的索引。以RGB12色位图)为例,比如它的调色板中定义的两种颜色值依次为0x000000(黑色)和0xFFFFFF(白色),那么图像数据001101010111…(每个像素用1位表示)表示对应各像素的颜色为:黑黑白白黑白黑白黑白白白

¨ RGB565使用16位表示一个像素,这16位中的5位用于R6位用于G5位用于B。程序中通常使用一个字(WORD,一个字等于两个字节)来操作一个像素。当读出一个像素后,这个字的各个位意义如下:

     高字节              低字节

R R R R R G G G     G G G B B B B B

可以组合使用屏蔽字和移位操作来得到RGB各分量的值:

#define RGB565_MASK_RED    0xF800

#define RGB565_MASK_GREEN  0x07E0

#define RGB565_MASK_BLUE   0x001F

R = (wPixel & RGB565_MASK_RED) >> 11;   // 取值范围0-31

G = (wPixel & RGB565_MASK_GREEN) >> 5;  // 取值范围0-63

B =  wPixel & RGB565_MASK_BLUE;         // 取值范围0-31

¨ RGB555是另一种16位的RGB格式,RGB分量都用5位表示(剩下的1位不用)。使用一个字读出一个像素后,这个字的各个位意义如下:

     高字节             低字节

X R R R R G G       G G G B B B B B       X表示不用,可以忽略)

可以组合使用屏蔽字和移位操作来得到RGB各分量的值:

#define RGB555_MASK_RED    0x7C00

#define RGB555_MASK_GREEN  0x03E0

#define RGB555_MASK_BLUE   0x001F

R = (wPixel & RGB555_MASK_RED) >> 10;   // 取值范围0-31

G = (wPixel & RGB555_MASK_GREEN) >> 5;  // 取值范围0-31

B =  wPixel & RGB555_MASK_BLUE;         // 取值范围0-31

¨ RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…。通常可以使用RGBTRIPLE数据结构来操作一个像素,它的定义为:

typedef struct tagRGBTRIPLE { 

  BYTE rgbtBlue;    // 蓝色分量

  BYTE rgbtGreen;   // 绿色分量

  BYTE rgbtRed;     // 红色分量

} RGBTRIPLE;

¨ RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的 RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRA BGRA…。通常可以使用RGBQUAD数据结构来操作一个像素,它的定义为:

typedef struct tagRGBQUAD {

  BYTE    rgbBlue;      // 蓝色分量

  BYTE    rgbGreen;     // 绿色分量

  BYTE    rgbRed;       // 红色分量

  BYTE    rgbReserved;  // 保留字节(用作Alpha通道或忽略)

} RGBQUAD;

下面介绍各种YUV格式。YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。表2.3中的YUY2Y211都是打包格式,而IF09YVU9都是平面格式。(注意:在介绍各种具体格式时,YUV各分量都会带有下标,如Y0U0V0表示第一个像素的YUV分量,Y1U1V1表示第二个像素的YUV分量,以此类推。)

¨ YUY2(和YUYV)格式为每个像素保留Y分量,而UV分量在水平方向上每两个像素采样一次。一个宏像素为4个字节,实际表示2个像素。(4:2:2的意思为一个宏像素中有4Y分量、2U分量和2V分量。)图像数据中YUV分量排列顺序如下:

Y0 U0 Y1 V0    Y2 U2 Y3 V2 …

¨ YVYU格式跟YUY2类似,只是图像数据中YUV分量的排列顺序有所不同:

Y0 V0 Y1 U0    Y2 V2 Y3 U2 …

¨ UYVY格式跟YUY2类似,只是图像数据中YUV分量的排列顺序有所不同:

U0 Y0 V0 Y1    U2 Y2 V2 Y3 …

¨ AYUV格式带有一个Alpha通道,并且为每个像素都提取YUV分量,图像数据格式如下:

A0 Y0 U0 V0    A1 Y1 U1 V1 …

¨ Y41P(和Y411)格式为每个像素保留Y分量,而UV分量在水平方向上每4个像素采样一次。一个宏像素为12个字节,实际表示8个像素。图像数据中YUV分量排列顺序如下:

U0 Y0 V0 Y1    U4 Y2 V4 Y3    Y4 Y5 Y6 Y8 … 

¨ Y211格式在水平方向上Y分量每2个像素采样一次,而UV分量每4个像素采样一次。一个宏像素为4个字节,实际表示4个像素。图像数据中YUV分量排列顺序如下:

Y0 U0 Y2 V0    Y4 U4 Y6 V4 …

¨ YVU9格式为每个像素都提取Y分量,而在UV分量的提取时,首先将图像分成若干个4 x 4的宏块,然后每个宏块提取一个U分量和一个V分量。图像数据存储时,首先是整幅图像的Y分量数组,然后就跟着U分量数组,以及V分量数组。IF09格式与YVU9类似。

¨ IYUV格式为每个像素都提取Y分量,而在UV分量的提取时,首先将图像分成若干个2 x 2的宏块,然后每个宏块提取一个U分量和一个V分量。YV12格式与IYUV类似。

¨ YUV411YUV420格式多见于DV数据中,前者用于NTSC制,后者用于PAL制。YUV411为每个像素都提取Y分量,而UV分量在水平方向上每4个像素采样一次。YUV420并非V分量采样为0,而是跟YUV411相比,在水平方向上提高一倍色差采样频率,在垂直方向上以U/V间隔的方式减小一半色差采样,如图2.12所示。

http://img.ogg.cn:8080/1308.jpg

 

 

YUV转换为RGB的公式

第一个公式是YUV转换RGB(范围0-255)时用的,第二个公式是用在YUV(601)也成为YCbCr转换RGB(范围0-255)时用的。 

1.Y =   0.299R + 0.587G + 0.114B

   U = -0.147R - 0.289G + 0.436B

   V =  0.615R - 0.515G - 0.100B

   R = Y             + 1.14V

   G = Y - 0.39U - 0.58V

   B = Y + 2.03U

2.B= 1.164 * (Y - 16) + 2.018 * (U - 128)

   G= 1.164 * (Y - 16) -   0.38 * (U - 128) - 0.813 * (V - 128)

   R= 1.164 * (Y - 16)                             + 1.159 * (V - 128)

 

 

程序读出来显现的不正确,源代码大概是这样的:

         Mywidth = 176;

Myheight = 144;

tmp = (uchar *)malloc(Mywidth * Myheight *3);

buffer = (uchar *)malloc(Mywidth * Myheight *4);

device_fd = open("/dev/video0", O_RDONLY);

static struct video_window vidwin;

vidwin.width = Mywidth;

vidwin.height = Myheight;

ioctl(device_fd, VIDIOCSWIN, &vidwin);

read(device_fd, tmp, Mywidth*Myheight*3);

for(int i = 0; i < 176 * 144; ++i)

{

  buffer[4*i] = tmp[3*i];//first bit is blue

  buffer[4*i + 1] = tmp[3*i + 1];//second bit is green

  buffer[4*i + 2] = tmp[3*i + 2] ;//third bit is red

  buffer[4*i + 3] = 130;//forth bit

}

//后面这此是用QT库写的,意思是将buffer的内容转为image再转为pixmap,然后显示出来

QImage img(buffer, Mywidth, Myheight, 32, NULL, 0, QImage::LittleEndian); 

QPixmap pic;

pic.convertFromImage(img);

PixmapVideo->setPixmap(pic);

 

FillEllips 函数填充指定的椭圆。椭圆心为(sx, sy),轴半径为 rx轴半径为 ry。 

  FillSector 函数填充由圆弧和两条半径形成的扇形。圆心为(x, y),半径为 r,起始弧度为 ang1,终止弧度为 ang2。 

  FillPolygon 函数填充多边形。pts 表示多边形各个顶点,vertices 表示多边形顶点个数。 

  FloodFill 从指定点(x, y)开始填注。 

  需要注意的是,所有填充函数使用当前画刷属性(颜色),并且受当前光栅操作的影响。

  

  下面的例子说明了如何使用 FillCircle 和 FillEllipse 函数填充圆或者椭圆。假定给定了两个点,pts[0] 和 pts[1],其中 pts[0] 是圆心或者椭圆心,而 pts[1] 是圆或者椭圆外切矩形的一个顶点。

  

        int rx = ABS (pts[1].x - pts[0].x);

        int ry = ABS (pts[1].y - pts[0].y);

  

        if (rx == ry)

          FillCircle (hdc, pts[0].x, pts[0].y, rx);

        else

          FillEllipse (hdc, pts[0].x, pts[0].y, rx, ry);

  

  建立复杂区域

  

  除了利用填充生成器进行填充绘制以外,我们还可以使用填充生成器建立由封闭曲线包围的复杂区域。我们知道,MiniGUI 当中的区域是由互不相交的矩形组成的,并且满足 x-y-banned 的分布规则。利用上述的多边形或者封闭曲线生成器,可以将每条扫描线看成是组成区域的高度为 的一个矩形,这样,我们可以利用这些生成器建立复杂区域。MiniGUI 利用现有的封闭曲线生成器,实现了如下的复杂区域生成函数:

  

  BOOL GUIAPI InitCircleRegion (PCLIPRGN dst, int x, int y, int r);

  BOOL GUIAPI InitEllipseRegion (PCLIPRGN dst, int x, int y, int rx, int ry);

  BOOL GUIAPI InitPolygonRegion (PCLIPRGN dst, const POINT* pts, int vertices);

  BOOL GUIAPI InitSectorRegion (PCLIPRGN dst, const POINT* pts, int vertices);

  

  利用这些函数,我们可以将某个区域分别初始化为圆、椭圆、多边形和扇形区域。然后,可以利用这些区域进行点击测试(PtInRegion 和 RectInRegion),或者选择到 DC 当中作为剪切域,从而获得特殊显示效果。

  

  直接访问显示缓冲区

  

  在新的 GDI 接口中,我们添加了用来直接访问显示缓冲区的函数,原型如下:

  

  Uint8* GUIAPI LockDC (HDC hdc, const RECT* rw_rc, int* width, int* height, int* pitch);

  void GUIAPI UnlockDC (HDC hdc);

  

  LockDC 函数锁定给定 HDC 的指定矩形区域(由矩形 rw_rc指定,设备坐标),然后返回缓冲区头指针。当 widthheightpitch 三个指针不为空时,该函数将返回锁定之后的矩形有效宽度、有效高度和每扫描线所占的字节数。 

  UnlockDC 函数解开已锁定的 HDC。 

  锁定一个 HDC 意味着 MiniGUI 进入以互斥方式访问显示缓冲区的状态。如果被锁定的 HDC 是一个屏幕 DC(即非内存 DC),则该函数将在必要时隐藏鼠标光标,并锁定 HDC 对应的全局剪切域。在锁定一个 HDC 之后,程序可通过该函数返回的指针对锁定区域进行访问。需要注意的是,不能长时间锁定一个 HDC,也不应该在锁定一个 HDC 时进行其他额外的系统调用。

  

  假定以锁定矩形左上角为原点建立坐标系,轴水平向右,轴垂直向下,则可以通过如下的公式计算该坐标系中(x, y)点对应的缓冲区地址(假定该函数返回的指针值为 frame_buffer):

  

    Uint8* pixel_add = frame_buffer + y * (*pitch) + x * GetGDCapability (hdc, GDCAP_BPP);

  

  根据该 HDC 的颜色深度,就可以对该象素进行读写操作。作为示例,下面的程序段随机填充锁定区域:

  

    int i, width, height, pitch;

    RECT rc = {0, 0, 200, 200};

    int bpp = GetGDCapability (hdc, GDCAP_BPP);

    Uint8* frame_buffer = LockDC (hdc, &rc, &width, &height, &pitch);

    Uint8* row = frame_buffer;

  

    for (i = 0; i < *height; i++) {

      memset (row, rand ()%0x100, *width * bpp);

      row += *pitch;

    }

  

    UnlockDC (hdc);

  

  

  7 YUV 覆盖和 Gamma 校正

  

  为了增强 MiniGUI 对多媒体的支持,我们增加了对 YUV 覆盖(Overlay)和 Gamma 校正的支持。

  

  7.1 YUV 覆盖(Overlay

  

  多媒体领域中,尤其在涉及到 MPEG 播放时,通常使用 YUV 颜色空间来表示颜色,如果要在屏幕上显示一副 MPEG 解压之后的图片,则需要进行 YUV 颜色空间到 RGB 颜色空间的转换。YUV 覆盖最初来自一些显示芯片的加速功能。这种显示芯片能够在硬件基础上完成 YUV 到 RGB 的转换,免去软件转换带来的性能损失。在这种显示芯片上建立了 YUV 覆盖之后,可以直接将 YUV 信息写入缓冲区,硬件能够自动完成 YUV 到 RGB 的转换,从而在 RGB 显示器上显示出来。在不支持 YUV 覆盖的显示芯片上,MiniGUI 也能够通过软件实现 YUV 覆盖,这时,需要调用 DisplayYUVOverlay 函数将 YUV 信息转换并缩放显示在建立 YUV 覆盖的 DC 设备上。

  

  MiniGUI 提供的 YUV 覆盖操作函数原型如下:

  

  /***************************** YUV overlay support ***************************/

  /* 最常见的视频覆盖格式.

  */

  #define GAL_YV12_OVERLAY0x32315659/* Planar mode: Y + V + U(3 planes) */

  #define GAL_IYUV_OVERLAY0x56555949/* Planar mode: Y + U + V(3 planes) */

  #define GAL_YUY2_OVERLAY0x32595559/* Packed mode: Y0+U0+Y1+V0 (1 plane) */

  #define GAL_UYVY_OVERLAY0x59565955/* Packed mode: U0+Y0+V0+Y1 (1 plane) */

  #define GAL_YVYU_OVERLAY0x55595659/* Packed mode: Y0+V0+Y1+U0 (1 plane) */

  

  /* 该函数创建一个视频输出覆盖

  */

  GAL_Overlay* GUIAPI CreateYUVOverlay (int width, int height,

          Uint32 format, HDC hdc);

  

  /* 锁定覆盖进行直接的缓冲区读写,结束后解锁 */

  int GAL_LockYUVOverlay (GAL_Overlay *overlay);

  void GAL_UnlockYUVOverlay (GAL_Overlay *overlay);

  

  #define LockYUVOverlay GAL_LockYUVOverlay

  #define UnlockYUVOverlay GAL_UnlockYUVOverlay

  

  /* 释放视频覆盖 */

  void GAL_FreeYUVOverlay (GAL_Overlay *overlay);

  #define FreeYUVOverlay GAL_FreeYUVOverlay

  

  /* 将视频覆盖传送到指定 DC 设备上。该函数能够进行 维缩放

  */

  void GUIAPI DisplayYUVOverlay (GAL_Overlay* overlay, const RECT* dstrect);

  

  有关视频格式的信息,可参见:

  

  http://www.webartz.com/fourcc/indexyuv.htm

  

  有关颜色空间的相互关系的息,可参见:

  

  http://www.neuro.sfc.keio.ac.jp/~aly/polygon/info/color-space-faq.html

  

  7.2 Gamma 校正

  

  Gamma 校正通过为 RGB 颜色空间的每个颜色通道设置 Gamma 因子,来动态调整 RGB 显示器上的实际 RGB 效果。需要注意的是,Gamma 校正需要显示芯片的硬件支持。

  

  应用程序可以通过 SetGamma 函数设置 RGB 三个颜色通道的 Gamma 校正值。该函数原型如下:

  

  int GAL_SetGamma (float red, float green, float blue);

  #define SetGamma GAL_SetGamma

  

  线性 Gamma 校正值的范围在 0.1 到 10.0 之间。如果硬件不支持 Gamma 校正,该函数将返回 -1

  

  应用程序也可以通过 SetGammaRamp 函数设置 RGB 三个颜色通道的非线性 Gamma 校正值。该函数原型如下:

  

  int GAL_SetGammaRamp (Uint16 *red, Uint16 *green, Uint16 *blue);

  #define SetGammaRamp GAL_SetGammaRamp

  

  int GAL_GetGammaRamp (Uint16 *red, Uint16 *green, Uint16 *blue);

  #define GetGammaRamp GAL_GetGammaRamp

  

  函数 SetGammaRamp 实际设置的是每个颜色通道的 Gamma 转换表,每个表由 256 个值组成,表示设置值和实际值之间的对应关系。当设置屏幕上某个象素的 RGB 分别为 RG时,实际在显示器上获得的象素 RGB 值分别为:red[R]green[G]blue[B]。如果硬件不支持 Gamma 校正,该函数将返回 -1

  

  函数 GetGammaRamp 获得当前的 Gamma 转换表。

  

  Gamma 校正的最初目的,是为了能够在显示器上精确还原一副图片。Gamma 值在某种程度上表示的是某个颜色通道的对比度变化。但 Gamma 在多媒体和游戏程序中有一些特殊用途――通过 Gamma 校正,可以方便地获得对比度渐进效果。

  

  小结

  

  本文描述了自 MiniGUI 1.1.0Pre4 版本发布以来新增的 GDI 接口。这些接口涉及到曲线和填充生成器、复杂曲线的绘制、封闭曲线填充、复杂区域的创建、直接访问 FrameBufferYUV 覆盖和 Gamma 校正等等。通过本文的介绍,相信读者能够对 MiniGUI 的新 GDI 接口有一个更加全面的认识。

  

Content 

1.驱动 

2.应用程序书写 

 

1.驱动 

   Linux-2.4.18默认带有ov511摄像头的驱动,在USB设备中选中,并激活video选项,即可对ov511支持。 

 

2.应用程序书写 

   这是一个在MiniGui下的程序,可以用QVFB模拟,可以可以在板子上跑,效果还可以。 

 

v4l.h 

/* 

* w3v4l.h 

* Copyright (C) 1998 - 2000 Rasca, Berlin 

* EMail: [email protected] 

* This program is free software; you can redistribute it and/or modify 

* it under the terms of the GNU General Public License as published by 

* the Free Software Foundation; either version 2 of the License, or 

* (at your option) any later version. 

* This program is distributed in the hope that it will be useful, 

* but WITHOUT ANY WARRANTY; without even the implied warranty of 

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 

* GNU General Public License for more details. 

* You should have received a copy of the GNU General Public License 

* along with this program; if not, write to the Free Software 

* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 

*/ 

 

#ifndef __W3V4L_H__ 

#define __W3V4L_H__ 

 

class CV4L{ 

public: 

CV4L(); 

CV4L(char *szDevName); 

~CV4L(); 

 

bool init(int channel, int width, int height); 

unsigned char *Read(); 

void destroy(); 

private: 

char *szDevName; 

bool initialized; 

unsigned char *m_Buff; 

int m_BuffSize; 

int fdVideo; 

int m_Width, m_Height; 

int m_MapSize; 

}; 

 

#endif 

 

v4l.cpp 

 

/* 

* v4l.c 

* This program is free software; you can redistribute it and/or modify 

* it under the terms of the GNU General Public License as published by 

* the Free Software Foundation; either version 2 of the License, or 

* (at your option) any later version. 

* This program is distributed in the hope that it will be useful, 

* but WITHOUT ANY WARRANTY; without even the implied warranty of 

* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 

* GNU General Public License for more details. 

* You should have received a copy of the GNU General Public License 

* along with this program; if not, write to the Free Software 

* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 

*/ 

 

#include <stdio.h> 

#include <stdlib.h> 

#include <unistd.h> 

#include <sys/types.h> 

#include <sys/stat.h> 

#include <fcntl.h> 

#include <sys/ioctl.h> 

#include <sys/mman.h> 

#include <linux/types.h> 

#include <string.h> 

 

#include <linux/videodev.h> 

#include "v4l.h" 

 

/* v4l_init() 

* function: init the video device 

* references: 

*     dev: device name. 

*     input: channel number of video_channel structure. 

*     width: width value of video_window structure 

*     height: height value of video_window structure 

*/ 

bool CV4L::init(int channel, int width, int height) 

int fd; 

struct video_capability vid_caps; 

struct video_mbuf vid_mbuf; 

struct video_channel vid_chnl; 

 

// open the video device 

fd = open (szDevName, O_RDWR); 

if (fd == -1) { 

perror (szDevName); 

return false; 

fdVideo = fd; 

 

// get video_capability structrue 

if (ioctl (fd, VIDIOCGCAP, &vid_caps) == -1) { 

perror ("ioctl (VIDIOCGCAP)"); 

return false; 

 

// get the buffer information in video_mbuf structure 

// if can't use mmap() 

if (ioctl (fd, VIDIOCGMBUF, &vid_mbuf) == -1) { 

struct video_window vid_win; 

m_MapSize = 0; 

 

// set video window information 

if (ioctl(fd, VIDIOCGWIN, &vid_win) != -1) { 

vid_win.width = width; 

vid_win.height= height; 

ioctl (fd, VIDIOCSWIN, &vid_win); 

} else { 

m_MapSize = vid_mbuf.size; 

m_BuffSize = m_MapSize; 

#ifdef DEBUG 

printf ("%s: mbuf.size=%d\n", __FILE__, vid_mbuf.size); 

#endif 

 

if (channel > -1) { 

vid_chnl.channel = channel; 

if (ioctl (fd, VIDIOCGCHAN, &vid_chnl) == -1) { 

perror ("ioctl (VIDIOCGCHAN)"); 

} else { 

vid_chnl.channel = channel; 

if (ioctl (fd, VIDIOCSCHAN, &vid_chnl) == -1) { 

perror ("ioctl (VIDIOCSCHAN)"); 

if (m_MapSize > 0) { 

m_Buff = (unsigned char *)mmap (0,m_MapSize, PROT_READ|PROT_WRITE,MAP_SHARED,fd,0); 

if ((unsigned char *) -1 == (unsigned char *)m_Buff) { 

perror ("mmap()"); 

close (fd); 

return false; 

} else { 

m_BuffSize = width * height * 3; 

m_Buff = (unsigned char *)malloc (m_BuffSize); 

m_Width = width; 

m_Height = height; 

 

return true; 

 

unsigned char 

*CV4L::Read() 

struct video_mmap vid_mmap; 

 

if (m_MapSize == 0) { 

printf (__FILE__": reading image .. \n"); 

if (read (fdVideo, (void *)m_Buff, m_BuffSize) <= 0) { 

free (m_Buff); 

return (0); 

} else { 

vid_mmap.format = VIDEO_PALETTE_RGB565;   //VIDEO_PALETTE_RGB24; 

vid_mmap.frame = 0; 

vid_mmap.width = m_Width; 

vid_mmap.height= m_Height; 

if (ioctl (fdVideo, VIDIOCMCAPTURE, &vid_mmap) == -1) { 

perror ("ioctl (VIDIOCMCAPTURE)"); 

return (0); 

if (ioctl (fdVideo, VIDIOCSYNC, &vid_mmap) == -1) { 

perror ("ioctl (VIDIOCSYNC)"); 

return (0); 

return m_Buff; 

 

void CV4L::destroy() 

if (fdVideo >= 0) { 

if (m_MapSize == 0) 

free (m_Buff); 

else 

munmap (m_Buff, m_MapSize); 

close (fdVideo); 

 

CV4L::CV4L() 

// 

 

CV4L::CV4L(char *_szDevName) 

szDevName = (char *)malloc(strlen(_szDevName)+1); 

strcpy(szDevName, _szDevName); 

//init(0, int width, int height); 

// 

 

CV4L::~CV4L() 

destroy(); 

 

video.cpp 

/* 

** $Id: helloworld.c,v 1.7 2003/06/13 07:15:49 weiym Exp $ 

** 

** Listing 2.1 

** 

** helloworld.c: Sample program for MiniGUI Programming Guide 

**      The first MiniGUI application. 

** 

** Copyright (C) 2003 Feynman Software. 

** 

** License: GPL 

*/ 

 

#include <stdio.h> 

 

#include <minigui/common.h> 

#include <minigui/minigui.h> 

#include <minigui/gdi.h> 

#include <minigui/window.h> 

#include <string.h> 

#include <malloc.h> 

 

#include "v4l.h" 

 

#define VID_W 320 

#define VID_H 240 

 

static BITMAP bmp; 

 

CV4L *cVid;  //"/dev/video0" 

unsigned char *buf; 

 

   static int count = 0; 

   static int xdir = -3; 

   static int ydir = -3; 

   static int x = 1; 

   static int y = 11; 

 

/*bool SwitchBuf24ToBmp16(unsigned char *buf24, PBITMAP pBmp) 

myBmp.bits = buf24; 

//ExpandMyBitmap (HDC_SCREEN, &bmp, &myBmp, rgb, 0); 

 

printf ("bmp.bmType = %i\n", bmp.bmType); 

printf ("bmp.bmBitsPerPixel = %i\n", bmp.bmBitsPerPixel); 

printf ("bmp.bmBytesPerPixel = %i\n", bmp.bmBytesPerPixel); 

printf ("bmp.bmAlpha = %i\n", bmp.bmAlpha); 

printf ("bmp.bmColorKey = %i\n", bmp.bmColorKey); 

printf ("bmp.bmWidth = %i\n", bmp.bmWidth); 

printf ("bmp.bmHeight = %i\n", bmp.bmHeight); 

printf ("bmp.bmPitch = %i\n", bmp.bmPitch); 

printf ("bmp.bmBits = %i\n", bmp.bmBits); 

printf ("bmp.bmAlphaPixelFormat = %i\n", bmp.bmAlphaPixelFormat); 

return true; 

}*/ 

 

void FillBitmap(BITMAP *bmp) 

bmp->bmType = 0; 

bmp->bmBitsPerPixel = 16; 

bmp->bmBytesPerPixel = 2; 

bmp->bmAlpha = 0; 

bmp->bmColorKey = 0; 

bmp->bmWidth = VID_W; 

bmp->bmHeight = VID_H; 

bmp->bmPitch = VID_W*2; 

bmp->bmBits = NULL; 

bmp->bmAlphaPixelFormat = NULL; 

 

void FillMyBitmap(PMYBITMAP my_bmp) 

my_bmp->flags = MYBMP_RGBSIZE_3 | MYBMP_TYPE_BGR | MYBMP_FLOW_DOWN; 

my_bmp->frames = 1; 

my_bmp->depth = 24; 

my_bmp->alpha = 0; 

my_bmp->reserved[0] = 0; 

my_bmp->reserved[1] = 0; 

my_bmp->transparent = 0; 

my_bmp->w = 240; 

my_bmp->h = 180; 

my_bmp->pitch = 240*3; 

my_bmp->size = 240*180*3; 

my_bmp->bits = NULL; 

 

static int HelloWinProc(HWND hWnd, int message, WPARAM wParam, LPARAM lParam) 

   HDC hdc; 

   RECT rc; 

 

   switch (message) { 

       case MSG_PAINT: 

           hdc = BeginPaint (hWnd); 

 

           if (bmp.bmBits) 

               FillBoxWithBitmap (hdc, 0, 0, bmp.bmWidth, bmp.bmHeight, &bmp); 

 

           SetBkColor (hdc, RGB2Pixel (hdc, 0xFF, 0xFF, 0xFF)); 

           SetBkMode (hdc, BM_TRANSPARENT); 

           SetTextColor (hdc, RGB2Pixel (hdc, 0xFF, 0x00, 0x00)); 

           rc.left = 0; 

           rc.top = 0; 

           rc.right = 300; 

           rc.bottom = 60; 

           TextOut (hdc, 0, 0, "??????"); 

 

   if (x >= VID_W || x <=0) 

   { 

               xdir = 0 - xdir; 

   } 

   if (y >= VID_W || y <=10) 

   { 

               ydir = 0 - ydir; 

   } 

    

   x += xdir; 

   y += ydir; 

   TextOut (hdc, x, y, "kdf"); 

           Rectangle (hdc, 0, 0, bmp.bmWidth, bmp.bmHeight); 

 

           /*FillBoxWithBitmap (hdc, 100, 0, 200, 200, &bmp); 

           Rectangle (hdc, 100, 0, 300, 200); 

 

           FillBoxWithBitmapPart (hdc, 0, 200, 400, 200, 0, 0, &bmp, 10, 10); 

           Rectangle (hdc, 0, 200, 400, 400);*/ 

 

           EndPaint (hWnd, hdc); 

           return 0; 

 

       case MSG_CREATE: 

           /*if (LoadBitmap (HDC_SCREEN, &bmp, "bkgnd.bmp")) 

               return -1;*/ 

           return 0; 

 

       case MSG_CLOSE: 

           UnloadBitmap (&bmp); 

           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; 

 

#ifdef _LITE_VERSION 

   SetDesktopRect(0, 0, 1024, 768); 

#endif 

 

   CreateInfo.dwStyle = WS_VISIBLE | WS_BORDER | WS_CAPTION; 

   CreateInfo.dwExStyle = WS_EX_NONE; 

   CreateInfo.spCaption = "Hello, world"; 

   CreateInfo.hMenu = 0; 

   CreateInfo.hCursor = GetSystemCursor(0); 

   CreateInfo.hIcon = 0; 

   CreateInfo.MainWindowProc = HelloWinProc; 

   CreateInfo.lx = 0; 

   CreateInfo.ty = 0; 

   CreateInfo.rx = VID_W; 

   CreateInfo.by = VID_H; 

   CreateInfo.iBkColor = COLOR_lightwhite; 

   CreateInfo.dwAddData = 0; 

   CreateInfo.hHosting = HWND_DESKTOP; 

    

   hMainWnd = CreateMainWindow (&CreateInfo); 

    

   if (hMainWnd == HWND_INVALID) 

       return -1; 

 

   ShowWindow(hMainWnd, SW_SHOWNORMAL); 

 

   ////////////////////////////////////////////////////////////// 

   // 1. Create my video class CV4L. 

   cVid = new CV4L("/dev/video0"); 

    

   ////////////////////////////////////////////////////////////// 

   // 2. Init the video device with channel and map size. 

   if (cVid->init(0, VID_W, VID_H) == false) 

       return -1; 

 

   //FillMyBitmap(&myBmp); 

   FillBitmap(&bmp); 

   ////////////////////////////////////////////////////////////// 

   // 3. Read the data from video device. 

   if (buf = cVid->Read ()) 

   { 

       bmp.bmBits = buf; 

       //InvalidateRect (); 

       SendMessage (hMainWnd, MSG_PAINT, 0, 0); 

   } 

 

   while (true) 

   { 

       if (!HavePendingMessage (hMainWnd)) 

       { 

           if (!GetMessage (&Msg, hMainWnd)) 

               break; 

           TranslateMessage (&Msg); 

           DispatchMessage (&Msg); 

       } else { 

           ////////////////////////////////////////////////////////////// 

           // 3. Read the data from video device. 

           if (buf = cVid->Read ()) 

           { 

               bmp.bmBits = buf; 

               SendMessage (hMainWnd, MSG_PAINT, 0, 0); 

           } else { 

               // if Buffer is Null, vedeo device have pluged out. 

               PostQuitMessage (hMainWnd); 

           } /* end of read video buffer */ 

       } /* end of HavePendingMessage() */ 

   } /* end of while */ 

 

   ////////////////////////////////////////////////////////////// 

   // 4. destroy the CV4L class, and release resources. 

   cVid->destroy (); 

   UnloadBitmap (&bmp); 

   //free (bmp.bmBits); 

 

   MainWindowThreadCleanup (hMainWnd); 

 

   return 0; 

 

#ifndef _LITE_VERSION 

#include <minigui/dti.c> 

#endif 

 

把这些代码添加到miniugi-1.3.3helloworld程序中去编译一下就可以了,也可以用如下命令 

g++ -o video -I/minigui/include -L/minigui/lib video.cpp v4l.cpp 

 

你可能感兴趣的:(图像处理)