图像源格式(RGB,YUV)

一. 说明

在视频解码后,我们通常需要将它们显示出来,也就是Render;这个时候往往后发现有很多种图像格式,而这些格式名称似是而非,很容易被搞混,因此这里对它们进行一些介绍和分类:

名词解释:

  • 平面格式(planar formats):针对Y U V 三种元素,使用三个矩阵来进行存储

  • 打包格式(packed formats): YUV存储在同一个平面,Luma和chroma数据交错排列,类似RGB的排列方式

  • 半平面格式(semi-planar): 半平面格式与平面格式的区别是,luma和chroma使用不同的平面,就是说U V被存储在一个平面矩阵了

  • 灰度空间(luminance): Y

  • 色度空间(chrominance): U(Cb)和V(Cr)

  • 交错排列(interleaved)

  • 顺序排列(progressive)

二. 颜色空间:

常用的颜色空间有 RGB YUV HSV

其中YUV颜色模型是来源于RGB的, 而YCbCr模型来源于YUV,它是YUV颜色空间的缩放和偏移应用;

2.1 RGB介绍:

在对RGB进行渲染的时候,经常需要设备的参数有RGB.888和RGB.565两种,它们分别对应RGB24和RGB16

2.1.1. 通过内存位进行分类

  • RGB1 每像素用1位表示,需要调色板
  • RGB4 每像素用4位表示,需要调色板
  • RGB8 每像素用8位表示,需要调色板

  • RGB565 每像素用16位表示

  • RGB555 每像素用16位表示,空一位

  • RGB24 每像素用24位表示, 每个RGB分量8位

  • RGB32 每像素用32位表示 每个RGB分量8位,剩下8位为空

  • ARGB32 每像素用32位表示,每个RGB分量用8位表示,剩下8位表示alpha通道

2.1.2 调色板类RGB

上面的RGB1 RGB4 RGB8都是调色板类RGB格式,当表示实际的颜色的时候,它们通常需要配合一个调色板来进行转换;比如在JPEG中,对于这种格式,都有个定义的调色板;

使用这种模型的图像数据,它们的源数据就不是真正的颜色值,而是当前像素颜色值在调色板中的索引;

比如RGB1(黑白位图),在调色板中定义了黑白两种颜色分别为0X000000(黑色)和0XFFFFFF(白色),这样图像源数据中的:0101 对于的像素的实际颜色就是:黑白黑白

2.1.3 RGB565

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

高<—————-低

RRRRRGGGGGGBBBBB

编程时,可以通过位操作来完成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

2.1.4 RGB555

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

高<—————-低

XRRRRGGGGGBBBBB

编程时,可以通过位操作来完成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

2.1.5 RGB24

RGB24使用24位来表示一个像素,RGB分量都用8位表示,取值范围为0-255。注意在内存中RGB各分量的排列顺序为:BGR BGR BGR…

编程时,一般名称为RGB.888,通常可以使用RGBTRIPLE数据结构来操作一个像素,定义为

typedef struct tagRGBTRIPLE { 
BYTE rgbtBlue; // 蓝色分量
BYTE rgbtGreen; // 绿色分量
BYTE rgbtRed; // 红色分量
} RGBTRIPLE;

2.1.6 RGB32

RGB32使用32位来表示一个像素,RGB分量各用去8位,剩下的8位用作Alpha通道或者不用。(ARGB32就是带Alpha通道的 RGB32。)注意在内存中RGB各分量的排列顺序为:BGRA BGRA BGRA…

编程时,命名为ARGB 定义为:

typedef struct tagRGBQUAD {
    BYTE rgbBlue; // 蓝色分量
    BYTE rgbGreen; // 绿色分量
    BYTE rgbRed; // 红色分量
    BYTE rgbReserved; // 保留字节(用作Alpha通道或忽略)
} RGBQUAD;

2.2 YUV介绍:

YUV的种类非常多且繁杂,其分类方式也多种多样,我们将重点介绍YUV420.

2.2.1. 根据排列方式划分:

  • 平面格式(planar formats):针对Y U V 三种元素,使用三个矩阵来进行存储;
  • 打包格式(packed formats): YUV存储在同一个平面,Luma和chroma数据交错排列,类似RGB的排列方式;
  • 半平面格式(semi-planar): 半平面格式与平面格式的区别是,luma和chroma使用不同的平面,就是说U V被存储在一个平面矩阵了;

2.2.2. 根据采样方式划分:

YUV 采样方式

YUV444:每个Y对应一组UV分量;

YUV422:每两个Y对应一组UV分量;

YUV420:每四个Y对应一组UV分量;

2.2.3. 根据 FOURCC 命名来划分:

YUV444

4:4:4 每像素32位

i.FOURCC: AYUV:A为alpha值(透明度参数)

内存布局(从低到高) V0U0Y0A0 V1U1Y1A1 V2U2Y2A2

ii.FOURCC:IYU2: ( YUV444, U-Y-V, progressive, packed)


YUV422

4:2:2 每像素16位

i. FOURCC: UYVY (YUV422, U-Y-V-Y, progressive, packed)

内存布局: U0Y0V0Y1 U1Y2V1Y3 U2Y4V2Y5

ii.FOURCC: YUY2 (same as YUYV)

内存布局: Y0U0Y1V0 Y2U1Y3V1 Y4U2Y5V2

下面的不再介绍内存布局,使用时查找
* UYNV (same as UYVY )
* Y422 (same as UYVY )
* IUYV ( YUV422, U-Y-V-Y, interlaced, packed)
* YUYV (YUV422, Y-U-Y-V, progressive, packed)
* YUNV (same as YUYV)
* V422 (same as YUYV)
* YVYU (YUV422, Y-V-Y-U, progressive, packed)
* YV16 (YUV422, Y-U-V, progressive, planar)
* YV12 (YUV420, Y-V-U, progressive, planar)
* IYUV (YUV420, Y-U-V, progressive, planar)
* I420 (same as IYUV)


YUV420

4:2:0 每像素有不同的位表示:

每像素16位表示

i. FOURCC:IMC1

内存布局:

IMC1 内存布局

ii.FOURCC:IMC3

内存布局:

IMC3 内存布局

每像素12位表示

i. FOURCC:IMC2

内存布局:

IMC2 内存布局

ii.FOURCC:YV12

内存布局:
所有 Y 样例都会作为不带正负号的 char 值组成的数组首先显示在内存中。此数组后面紧接着所有 V (Cr) 样例。V 平面的跨距为 Y 平面跨距的一半,V 平面包含的行为 Y 平面包含行的一半。V 平面后面紧接着所有 U (Cb) 样例,它的跨距和行数与 V 平面相同

YV12 内存布局

iii.FOURCC:NV12

内存布局:
所有 Y 样例都会作为由不带正负号的 char 值组成的数组首先显示在内存中,并且行数为偶数。Y 平面后面紧接着一个由不带正负号的 char 值组成的数组,其中包含了打包的 U (Cb) 和 V (Cr) 样例,如图所示。当组合的 U-V 数组被视为一个由 little-endian WORD 值组成的数组时,LSB 包含 U 值,MSB 包含 V 值。NV12 是用于 DirectX VA 的首选 4:2:0 像素格式。

NV12 内存布局

2.2.4. 编程常用描述:

在代码中,我们经常会看到YUV420P,YUV420SP,YV12,NV21,I420等表示,这里对其进行一些说明:

  1. I420 与 YV12 类似,它们的区别UV的顺序不同;I420按 YYYY U V 排列; YV12按 YYYY V U 排列;

  2. yuv420p 是I420的别名,它们等同,排列图如下

yuv420p 内存布局

  1. yuv420sp 是 NV12 的别名, 它们等同,排列图如下

yuv420sp 内存布局

  1. 总结

    • I420: YYYYYYYY UU VV =>YUV420P
    • YV12: YYYYYYYY VV UU =>YUV420P
    • NV12: YYYYYYYY UVUV =>YUV420SP
    • NV21: YYYYYYYY VUVU =>YUV420SP

旋转

public static void rotateYUV240SP(byte[] src,byte[] des,int width,int height){
  int wh = width * height;
  //旋转Y
  int k = 0;
  for(int i=0;i<width;i++) {
   for(int j=0;j<height;j++) 
   {
         des[k] = src[width*j + i];   
         k++;
   }
  }
  // 旋转UV
  for(int i=0;i<width;i+=2) {
   for(int j=0;j<height/2;j++) 
   { 
               des[k] = src[wh+ width*j + i]; 
               des[k+1]=src[wh + width*j + i+1];
         k+=2;
   }
  } 
 }

三. 测试方法:

如何用VLC播放YUV图像:

eg: demux=rawvideo :rawvid-width=704 :rawvid-height=576 :rawvid-chroma=UYVY :rawvid-fps=5

如何使用ffplayer播放YUV图像:

eg: ffplay -f rawvideo -video_size 1920x1080 a.yuv

参考文档:

《使用 8 位 YUV 格式的视频呈现》

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值