YUV,是一种颜色编码方法。Y表示明亮度(Luminance、Luma),也就是灰度值。U和V则是色度、浓度(Chrominance、Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。
与RGB格式相比,RGB格式用红绿蓝三个颜色分量来表示一个像素,YUV则是用一个亮度分量(Y)加两个色度分量来表示一个像素。YUV也经常被称为YCbCr,Cb为蓝色色度分量,对应U;Cr为红色色度分量,对应V。
YUV采样方式主要描述像素Y、U、V分量采样比例,即表达每个像素时,Y、U、V分量的数目,通常有三种方式:YUV4:4:4,YUV4:2:2,YUV4:2:0。
用三个图直观地表示采集的方式,以黑点表示采样该像点的Y分量,以空心圆圈表示采用该像素点的UV分量。
YUV4:4:4采样,每一个Y对应一组UV分量;YUV4:2:2采样,每两个Y共用一组UV分量;YUV4:2:0采样,每四个Y共用一组UV分量。
4:4:4表示没有色度通道的压缩采样。
4:2:2表示2:1水平压缩采样,无垂直压缩采样。
4:2:0表示2:1水平压缩采样,2:1垂直压缩采样。
YUV存储格式,主要描述像素的Y、U、V分量排列方式,分为两种格式:紧缩格式和平面格式。
紧缩格式(packed formats):将Y、U、V值储存成Macro Pixels阵列,和RGB的存放方式类似。每个像素点的Y,U,V是连续交差存储的。
这种YUV经常用在网络摄像机里,且大多是4:2:2的也就是只有在水平方向下采样。例如
UYVYUYVYUYVYUYVYUYVYUYVYUYVYUYVY
平面格式(planar formats):将Y、U、V的三个分量分别存放在不同的矩阵中。先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
planar的YUV是比较合适视频编码的一种格式。像下面这样的4x4的图像
YYYYYYYYYYYYYYYY UUUU VVVV
这个例子所示的YUV常被称为YUV420P,其水平和竖直方向上均为每两个亮度分量才有一个色度分量,也就是每四个Y才需要一个U和V。除这种水平和竖直方向的色度分量都下采样的4:2:0,还有只有水平方向下采样的4:2:2格式,以及没有下采样的4:4:4格式。
上面的例子是按Y、U、V(YCbCr)的顺序存储的,如果改为Y、V、U(YCrCb),则称为YV12格式。
Semi-planar格式
这是Planar和Packed两种格式的混合体:Y分量单独一个plane,U和V则交叉存储。这种YUV一般都是4:2:0的。例如:
YYYYYYYYYYYYYYYY UVUVUVUV
这个示例称为NV12格式。如果交换UV的顺序,就成了NV21格式。NV21是Android系统中摄像头预览图片的默认格式。
下面我用图的形式给出常见的YUV码流的存储方式,并在存储方式后面附有取样每个像素点的YUV数据的方法,其中,Cb、Cr的含义等同于U、V。
(1) YUYV 格式 (属于YUV422 Packed format)
Byte Order.Each cell is one byte.
start + 0: | Y’00 | Cb00 | Y’01 | Cr00 | Y’02 | Cb01 | Y’03 | Cr01 |
start + 8: | Y’10 | Cb10 | Y’11 | Cr10 | Y’12 | Cb11 | Y’13 | Cr11 |
start + 16: | Y’20 | Cb20 | Y’21 | Cr20 | Y’22 | Cb21 | Y’23 | Cr21 |
start + 24: | Y’30 | Cb30 | Y’31 | Cr30 | Y’32 | Cb31 | Y’33 | Cr31 |
Color Sample Location
0 | 1 | 2 | 3 | ||||
0 | Y | C | Y | Y | C | Y | |
1 | Y | C | Y | Y | C | Y | |
2 | Y | C | Y | Y | C | Y | |
3 | Y | C | Y | Y | C | Y |
Packed format with ½ horizontal chroma resolution, also known as YUV 4:2:2
1/2水平色度分辨率采样的打包格式,也被称为YUV 4:2:2
In this format each four bytes is two pixels. Each four bytes is two Y’s, a Cb and a Cr. Each Y goes to one of the pixels, and the Cb and Cr belong to both pixels. As you can see, the Cr and Cb components have half the horizontal resolution of the Y component. V4L2_PIX_FMT_YUYV is known in the Windows environment as YUY2.
在这种格式中,每4个字节是两个像素,每4个字节上有两个Y分量,一个U和一个V分量。没个像素都有一个Y分量,两个像素共用一个U和一个V分量。
U和V分量在水平方向上的采样只有Y的一半,V4L2_PIX_FMT_YUYV在Windows环境中被称为YUY2。
(YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y'00、Y'01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。)
(2) UYVY 格式(属于YUV422 Packed format)
Byte Order. Each cell is one byte.
start + 0: | Cb00 | Y’00 | Cr00 | Y’01 | Cb01 | Y’02 | Cr01 | Y’03 |
start + 8: | Cb10 | Y’10 | Cr10 | Y’11 | Cb11 | Y’12 | Cr11 | Y’13 |
start + 16: | Cb20 | Y’20 | Cr20 | Y’21 | Cb21 | Y’22 | Cr21 | Y’23 |
start + 24: | Cb30 | Y’30 | Cr30 | Y’31 | Cb31 | Y’32 | Cr31 | Y’33 |
Color Sample Location
0 | 1 | 2 | 3 | |||
0 | Y | C | Y | Y | C | Y |
1 | Y | C | Y | Y | C | Y |
2 | Y | C | Y | Y | C | Y |
3 | Y | C | Y | Y | C | Y |
Variation of V4L2_PIX_FMT_YUYV with different order of samples in memory
UYVY格式也是YUV422采样的存储格式中的一种,只不过与YUYV不同的是UV的排列顺序不一样而已,还原其每个像素点的YUV值的方法与上面一样。
(3) YUV422P(属于YUV422 Planar format)
Byte Order. Each cell is one byte.
start + 0: | Y’00 | Y’01 | Y’02 | Y’03 |
start + 4: | Y’10 | Y’11 | Y’12 | Y’13 |
start + 8: | Y’20 | Y’21 | Y’22 | Y’23 |
start + 12: | Y’30 | Y’31 | Y’32 | Y’33 |
start + 16: | Cb00 | Cb01 | ||
start + 18: | Cb10 | Cb11 | ||
start + 20: | Cb20 | Cb21 | ||
start + 22: | Cb30 | Cb31 | ||
start + 24: | Cr00 | Cr01 | ||
start + 26: | Cr10 | Cr11 | ||
start + 28: | Cr20 | Cr21 | ||
start + 30: | Cr30 | Cr31 |
Color Sample Location
0 | 1 | 2 | 3 | |||
0 | Y | C | Y | Y | C | Y |
1 | Y | C | Y | Y | C | Y |
2 | Y | C | Y | Y | C | Y |
3 | Y | C | Y | Y | C | Y |
Format with ½ horizontal chroma resolution, also known as YUV 4:2:2. Planar layout as opposed to V4L2_PIX_FMT_YUYV
1/2水平色度分辨率采样,也称为YUV 4:2:2。 和V4L2_PIX_FMT_YUYV不同的是,它是平面布局的
This is a planar version of the YUYV format. The three components are separated into three sub-images or planes. The Y plane is first. The Y plane has one byte per pixel. The Cb plane immediately follows the Y plane in memory. The Cb plane is half the width of the Y plane (and of the image). Each Cb belongs to two pixels. For example, Cb0 belongs to Y’00, Y’01. Following the Cb plane is the Cr plane, just like the Cb plane.
这是YUYV格式的平面版本。 三个分量被分成三个子图像或平面,分别存放在三个不同的矩阵中。 首先存放Y分量。 每一个像素都有一个Y分量。 Cb分量紧跟着Y分量存储。 Cb分量是Y分量的宽度的一半。 每个Cb分量属于两个像素。 例如,Cb0属于Y'00,Y'01。 Cb分量之后是Cr分量,它和Cb分量一样。
(YUV422P也属于YUV422的一种,它是一种Planar模式,即平面模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如上图所示。其每一个像素点的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即两个Y共用一个UV。比如,对于像素点Y'00、Y'01 而言,其Cb、Cr的值均为 Cb00、Cr00)
(4)YV12,YU12格式(属于YUV420 planar format)
Byte Order. Each cell is one byte.
start + 0: | Y’00 | Y’01 | Y’02 | Y’03 |
start + 4: | Y’10 | Y’11 | Y’12 | Y’13 |
start + 8: | Y’20 | Y’21 | Y’22 | Y’23 |
start + 12: | Y’30 | Y’31 | Y’32 | Y’33 |
start + 16: | Cr00 | Cr01 | ||
start + 18: | Cr10 | Cr11 | ||
start + 20: | Cb00 | Cb01 | ||
start + 22: | Cb10 | Cb11 |
Color Sample Location
0 | 1 | 2 | 3 | ||||
0 | Y | Y | Y | Y | |||
C | C | ||||||
1 | Y | Y | Y | Y | |||
2 | Y | Y | Y | Y | |||
C | C | ||||||
3 | Y | Y | Y | Y |
V4L2_PIX_FMT_YUV420 Planar formats with ½ horizontal and vertical chroma resolution, also known as YUV 4:2:0
V4L2_PIX_FMT_YUV420是1/2水平和垂直色度分辨率采样的平面格式,也称为YUV 4:2:0
V4L2_PIX_FMT_YVU420 (‘YV12’) and V4L2_PIX_FMT_YUV420 (‘YU12’) are planar formats, as opposed to a packed format. The three components are separated into three sub- images or planes. The Y plane is first. The Y plane has one byte per pixel. For V4L2_PIX_FMT_YVU420, the Cr plane immediately follows the Y plane in memory. The Cr plane is half the width and half the height of the Y plane (and of the image). Each Cr belongs to four pixels, a two-by-two square of the image. For example, Cr0 belongs to Y’00, Y’01, Y’10, and Y’11. Following the Cr plane is the Cb plane, just like the Cr plane. V4L2_PIX_FMT_YUV420 is the same except the Cb plane comes first, then the Cr plane.
V4L2_PIX_FMT_YVU420 (‘YV12’) 和 V4L2_PIX_FMT_YUV420 (‘YU12’),是planar模式,三个分量被分成三个子图像或平面,分别存放在三个不同的矩阵中。首先存放Y分量。 每一个像素都有一个Y分量,对于V4L2_PIX_FMT_YVU420格式,Cr分量紧跟着Y分量存储Cr分量的长度和宽度各是Y分量的一半,每个Cr分量属于4个像素(一个2x2的图像)例如,Cr0属于Y'00,Y'01,Y'10和Y'11。 Cr分量之后是Cb分量,它和Cr分量一样。V4L2_PIX_FMT_YUV420和V4L2_PIX_FMT_YVU420是相同的,只是在存储方式上Cb分量在前,然后是Cr分量。
(YU12和YV12属于YUV420格式,也是一种Planar模式,将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一组UV。注意,上图中,Y'00、Y'01、Y'10、Y'11共用Cr00、Cb00,其他依次类推。)
(5)NV12、NV21(属于YUV420)
Byte Order. Each cell is one byte.
start + 0: | Y’00 | Y’01 | Y’02 | Y’03 |
start + 4: | Y’10 | Y’11 | Y’12 | Y’13 |
start + 8: | Y’20 | Y’21 | Y’22 | Y’23 |
start + 12: | Y’30 | Y’31 | Y’32 | Y’33 |
start + 16: | Cb00 | Cr00 | Cb01 | Cr01 |
start + 20: | Cb10 | Cr10 | Cb11 | Cr11 |
Color Sample Location
0 | 1 | 2 | 3 | |||
0 | Y | Y | Y | Y | ||
C | C | |||||
1 | Y | Y | Y | Y | ||
2 | Y | Y | Y | Y | ||
C | C | |||||
3 | Y | Y | Y | Y |
V4L2_PIX_FMT_NV21 Formats with ½ horizontal and vertical chroma resolution, also known as YUV 4:2:0. One luminance and one chrominance plane with alternating chroma samples as opposed to V4L2_PIX_FMT_YVU420
V4L2_PIX_FMT_NV21是是1/2水平和垂直色度分辨率采样的平面格式,也称为YUV 4:2:0。与V4L2_PIX_FMT_YVU420不同的是,它具有交替的色度采样(即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane)
V4L2_PIX_FMT_NV12 (‘NV12’) and V4L2_PIX_FMT_NV21 (‘NV21’)are two-plane versions of the YUV 4:2:0 format. The three components are separated into two sub-images or planes. The Y plane is first. The Y plane has one byte per pixel. For V4L2_PIX_FMT_NV12, a combined CbCr plane immediately follows the Y plane in memory. The CbCr plane is the same width, in bytes, as the Y plane (and of the image), but is half as tall in pixels. Each CbCr pair belongs to four pixels. For example, Cb0/Cr0 belongs to Y’00, Y’01, Y’10, Y’11. V4L2_PIX_FMT_NV21 is the same except the Cb and Cr bytes are swapped, the CrCb plane starts with a Cr byte.
V4L2_PIX_FMT_NV12('NV12')和V4L2_PIX_FMT_NV21('NV21')是YUV 4:2:0 的two-plane 版,三个分量分成两个子图像或平面。首先存放Y分量。 每一个像素都有一个Y分量,对于V4L2_PIX_FMT_NV12格式,组合的CbCr分量紧跟着Y分量存储。CbCr分量与Y分量宽度相同(以字节为单位),但是像素的高度是Y分量的一半。 每个CbCr对都属于四个像素。 例如,Cb0 / Cr0属于Y'00,Y'01,Y'10,Y'11。 除了Cb和Cr字节被交换之外,V4L2_PIX_FMT_NV21是相同的,CrCb分量以Cr字节开头。
(NV12和NV21属于YUV420格式,是一种two-plane(Semi-planar)模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y'00、Y'01、Y'10、Y'11共用Cr00、Cb00)
void convertYUVpitchtoNV12(unsigned char *yuv_luma, unsigned char *yuv_cb, unsigned char *yuv_cr,
unsigned char *nv12_luma, unsigned char *nv12_chroma,
int width, int height, int srcStride, int dstStride)
{
int y;
int x;
if (srcStride == 0)
srcStride = width;
if (dstStride == 0)
dstStride = width;
//内存地址中,前width * height 存Y分量
//之后的width * height * 1/2 交叉着存U和V分量
//拷贝Y分量
for (y = 0; y < height; y++)
{
//第一次拷贝nv12_lume基地址,即第一行
//第二次拷贝第二行 。。。。
memcpy(nv12_luma + (dstStride*y), yuv_luma + (srcStride*y), width);
}
//拷贝UV分量
for (y = 0; y < height / 2; y++)
{
//每次步进两个位置
for (x = 0; x < width; x = x + 2)
{
//UV分量是交叉存的
//nv12_chroma[0]存yuv_cb[0],nv12_chroma[1]存yuv_cr[0]
//nv12_chroma[2]存yuv_cb[1],nv12_chroma[3]存yuv_cr[1]
// ....
nv12_chroma[(y*dstStride) + x] = yuv_cb[((srcStride / 2)*y) + (x >> 1)];
nv12_chroma[(y*dstStride) + (x + 1)] = yuv_cr[((srcStride / 2)*y) + (x >> 1)];
}
}
}
#define uint8_t BYTE
void YUY2toI420(int inWidth, int inHeight, uint8_t *pSrc, uint8_t *pDest)
{
int i, j;
//首先对I420的数据整体布局指定
uint8_t *u = pDest + (inWidth * inHeight);
uint8_t *v = u + (inWidth * inHeight) / 4;
for (i = 0; i < inHeight/2; i++)
{
/*采取的策略是:在外层循环里面,取两个相邻的行*/
uint8_t *src_l1 = pSrc + inWidth*2*2*i;//因为4:2:2的原因,所以占用内存,相当一个像素占2个字节,2个像素合成4个字节
uint8_t *src_l2 = src_l1 + inWidth*2;//YUY2的偶数行下一行
uint8_t *y_l1 = pDest + inWidth*2*i;//偶数行
uint8_t *y_l2 = y_l1 + inWidth;//偶数行的下一行
for (j = 0; j < inWidth/2; j++)//内层循环
{
// two pels in one go//一次合成两个像素
//偶数行,取完整像素;Y,U,V;偶数行的下一行,只取Y
*y_l1++ = src_l1[0];//Y
*u++ = src_l1[1];//U
*y_l1++ = src_l1[2];//Y
*v++ = src_l1[3];//V
//这里只有取Y
*y_l2++ = src_l2[0];
*y_l2++ = src_l2[2];
//YUY2,4个像素为一组
src_l1 += 4;
src_l2 += 4;
}
}
}