颜色模型-YUV

[TOC]

简介

YUV是一种颜色编码方法。Y'UV, YUV, YCbCr,YPbPr等专有名词都可以称为YUV,彼此有重叠。

Y表示明亮度(Luminance、Luma)。U和V则是色度、浓度(Chrominance、Chroma),

可以理解为

  • U(Cb)代表蓝色色度分量
  • V(Cr)代表红色色度分量

组合在一起表示色彩。

U-V color plane示例,Y value = 0.5,代表RGB色域(color gamut)

将Y、U、V分量拆解,可得下图,自上而下为原图、Y、U、V分量

参考

格式

Packed formats 紧缩格式

将Y、U、V值存储成Macro Pixels数组,每个像素点的 Y,U,V 是连续交替存储的,类似RGB的存储方式

紧缩格式(packed format)中的YUV是混合在一起的,对于YUV4:4:4格式而言,用紧缩格式很合适的,因此就有了UYVY、YUYV等。

举例

  • UYVY
  • YUYV

Planar formats 平面格式

将Y、U、V的三个分量分别存放在不同的矩阵中。

平面格式(planar formats)是指每Y分量,U分量和V分量都是以独立的平面组织的,也就是说所有的U分量必须在Y分量后面,而V分量在所有的U分量后面,此一格式适用于采样(subsample)。平面格式(planar format)有I420(4:2:0)、YV12、IYUV等。

举例

  • I420(4:2:0)
  • YV12
  • IYUV

抽样方式

分类

  • 4:4:4表示完全取样。
    • 每一个Y对应一组UV分量。
  • 4:2:2表示2:1的水平取样,垂直完全采样。
    • 每两个Y共用一组UV分量。
    • YV16、NV16
  • 4:2:0表示2:1的水平取样,垂直2:1采样。
    • 每四个Y共用一组UV分量。
    • YUV4:2:0并不是说只有U(即Cb), V(即Cr)一定为0,而是指U:V互相援引,时见时隐,也就是说对于每一个行,只有一个U或者V分量,如果一行是4:2:0的话,下一行就是4:0:2,再下一行是4:2:0...以此类推
    • YV12,YU12、NV12、NV21、YUV420SP、I420
  • 4:1:1表示4:1的水平取样,垂直完全采样。

采样方式

色度抽样方式用J:A:B表示
J:最小水平抽样的的宽度,一般为4
A:最小水平抽样区域第一行的色度抽样
B:最小水平抽样区域第二行的色度抽样

  • 4:4:4表示完全取样。
  • 4:2:2表示2:1的水平取样,垂直完全采样。
  • 4:2:0表示2:1的水平取样,垂直2:1采样。
  • 4:1:1表示4:1的水平取样,垂直完全采样。

对比RGB数据量

YUV的数据量会比RGB小很多,例如:

  • RGB24 每个像素占用3字节
  • ARGB32 每个像素占用4字节

  • YUV444 每个像素占用3字节
  • YUV422 每个像素占用2字节
  • YUV420 每个像素占用3字节1.5字节

常见格式

NV21、NV12

NV12 is a biplanar format with a full sized Y plane followed by a single chroma plane with weaved U and V values. NV21 is the same but with weaved V and U values.
The 12 in NV12 refers to 12 bits per pixel. NV12 has a half width and half height chroma channel, and therefore is a 420 subsampling. NV16 is 16 bits per pixel, with half width and full height. aka 422. NV24 is 24 bits per pixel with full sized chroma channel. aka 444.

NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。

NV12

NV21

YV12、YU12

YV12,YU12格式(属于YUV420)是一种Plane模式

YV12

YU12

I420P

和YU12是一样的

YUV420SP、YUV420P

SP : Semi-Planar UV交错存放
NV12和NV21就是我们常见的YUV420SP、YV12和YU12都属于YUV420p

可参考What is difference between planar, semi planar and interleaved format.?

YUYV

YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y'00、Y'01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。

YUY2和YUYV类似,UYVY同理

推荐资料

Stride 跨距

我们都知道现在计算机的cpu都是32位或者64位的cpu,他们一次最少读取4、8个字节,如果少于这些,反而要做一些额外的工作,会花更长的时间。所有会有一个概念叫做内存对齐,将结构体的长度设为4、8的倍数。

跨距也是因为同样的理由出现的。因为图像的操作通常按行操作的,如果图像的所有数据都紧密排列,那么会发生非常多次的读取非对齐内存。会影响效率。而图像的处理本就是一个分秒必争的操作,所以为了性能的提高就引入了跨距这个概念。

跨距就是指图像中的一行图像数据所占的存储空间的长度,它是一个大于等于图像宽度的内存对齐的长度。这样每次以行为基准读取数据的时候就能内存对齐,虽然可能会有一点内存浪费,但是在内存充裕的今天已经无所谓了。

pixel stride

Camera2 ImageReader YUV420_888,PreviewSize设置为17001080,返回预览流stride为1600,Image的size为16001200,返回的ysize为1920000,等于1600*1200,如果直接调用下面的代码,

YuvImage yuv = new YuvImage(bytes, ImageFormat.NV21, 
       mPreviewSize.getWidth(), mPreviewSize.getHeight(), 
       new int[y_stride, uv_stride]);
yuv.compressToJpeg(new Rect(0, 0, 
   mPreviewSize.getWidth(), mPreviewSize.getHeight()), 90, fos);

保存的图片会大部分灰色,约1/3是绿色,因为实际上从CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP获得的rosolution是不支持17001080,所以系统自动选择了16001200,如果将PreviewSize设置为1600*1200,保存图片则能得到正确结果。

分离Y、U、V分量

以Camera2 ImageReader为例

ByteBuffer yData = image.getPlanes()[0].getBuffer();
ByteBuffer uData = image.getPlanes()[1].getBuffer();
ByteBuffer vData = image.getPlanes()[2].getBuffer();

int ySize = yData.remaining();
int uSize = uData.remaining();
int vSize = vData.remaining();

mCurrentImageData = new byte[ySize + ySize / 2];
yData.get(mCurrentImageData, 0, ySize);

for (int i = ySize; i < ySize + ySize / 2; i++) {
    mCurrentImageData[i] = (byte)128;
}

也就是除了y分量,uv全部赋值为128(0x80)

最后使用YUVImage编码成JPEG

YuvImage yuv = new YuvImage(bytes, ImageFormat.NV21, 
        mPreviewSize.getWidth(), mPreviewSize.getHeight(), 
        new int[y_stride, uv_stride]);
yuv.compressToJpeg(new Rect(0, 0, 
    mPreviewSize.getWidth(), mPreviewSize.getHeight()), 90, fos);

最终得到灰度图。