YUV,分为三个分量,“Y”表示明亮度(Luminance或Luma),也就是灰度值;
而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。

一、YUV 采样

有一种表示法可用来描述 U 和 V 与 Y 的采样频率比例,这个表示法称为 A:B:C 表示法:

例如4:2:0

×  ×  ×  ×
 。  。  。
×  ×  ×  ×

×  ×  ×  ×
 。  。  。
×  ×  ×  ×

YUV420(4:2:0)为每个像素点对应一个Y分量,每4个像素点共用一组UV分量。所以分辨率为width*height的YUV420格式图像的数据量为:

yBytes = width*height;
uBytes = width*height/4;    // width*height>>2;
vBytes = width*height/4;    // width*height>>2;
yuvBytes = width*height*3/2;// width*height*3>>1;

YUV420按照UV分量的存储方式分为YUV420pYUV420sp两类。

YUV420p为Y、U、V三平面依次存储,YUV420sp为Y和UV两平面,且UV分量交叉存储。

stride:

/*
 * YUV420p
 */
yStride = width;
uStride = width/2; // width>>1;
vStride = width/2; // width>>1;

/*
 * YUV420sp
 */
yStride = width;
uvStride = width;

stride(考虑字节对齐):

#define ALIGN(x, align) (x+(align-1))&~(align-1)

/*
 * YUV420p
 */
yStride = ALIGN(width, 16);
uStride = ALIGN(width>>1, 16);
vStride = ALIGN(width>>1, 16);

/*
 * YUV420sp
 */
yStride = ALIGN(width, 16);
uvStride = ALIGN(width, 16);

参考文档

YUV420p

YUV420p

YUV420sp

YUV420sp

YUV420p又分为I420YV12两类。

分辨率为4X2的图像,I420格式数据存储为:YYYY YYYY UU VV,YV12格式数据存储为:YYYY YYYY VV UU。

I420android.ImageFormat.YUV_420_888

YUV420sp又分为NV12NV21两类。

分辨率为4X2的图像,NV12格式数据存储为:YYYY YYYY UV UV,NV21格式数据存储为:YYYY YYYY VU VU。

参考文档

二、YUV与YCbCr

2.1 YUV与YCbCr的区别:

YUV色彩模型来源于RGB模型,该模型的特点是将亮度和色度分离开,适合于图像处理领域。

应用:模拟领域,basic color model used in analogue color TV broadcasting.

YCbCr模型来源于YUV模型。YCbCr is a scaled and offset version of the YUV color space.

应用:数字视频,ITU-R BT.601 recommendation

note:U和Cb对应,V和Cr对应。(通常接触到的数字图像像素格式为YCbCr,简单理解为YUV)

YCbCr分量图

YCbCr分量图

参考文档

2.2 YUV、YCbCr转RGB公式:

RGB -> YCbCr

Y’ = 0.257*R' + 0.504*G' + 0.098*B' + 16
Cb' = -0.148*R' - 0.291*G' + 0.439*B' + 128
Cr' = 0.439*R' - 0.368*G' - 0.071*B' + 128

RGB -> YCbCr 代码实现(参考Android加载图片小结->11. Bitmap转yuv420sp(NV21))

int R, G, B;
...
int Y = ((66 * R + 129 * G + 25 * B + 128) >> 8) + 16;
int Cb = ((-38 * R - 74 * G + 112 * B + 128) >> 8) + 128;
int Cr = ((112 * R - 94 * G - 18 * B + 128) >> 8) + 128;
Y = ((Y < 0) ? 0 : ((Y > 255) ? 255 : Y));
Cb = ((Cb < 0) ? 0 : ((Cb > 255) ? 255 : Cb));
Cr = ((Cr < 0) ? 0 : ((Cr > 255) ? 255 : Cr));

YCbCr -> RGB

R' = 1.164*(Y’-16) + 1.596*(Cr'-128)
G' = 1.164*(Y’-16) - 0.813*(Cr'-128) - 0.392*(Cb'-128)
B' = 1.164*(Y’-16) + 2.017*(Cb'-128)

参考文档

三、YUV420 旋转90

void turnRotation(int width, int height, byte[] src, byte[] dest) {
	final int SUM = width * height;
	int h = SUM;

	// Y
	for (int i = 0; i < width; i++) {
		for (int j = 0; j < height; j++) {
			dest[--h] = src[j * width + i];
		}
	}

	h = SUM * 3 / 2;
	// UV
	for (int i = 0; i < width; i += 2) {
		for (int j = 0; j < height / 2; j++) {
			dest[--h] = src[SUM + j * width + i + 1];
			dest[--h] = src[SUM + j * width + i];
		}
	}
}

void turnRotationBack(int width, int height, byte[] src, byte[] dest) {
	final int SUM = width * height;
	int h = SUM;

	// Y
	for (int i = 0; i < width; i++) {
		for (int j = 0; j < height; j++) {
				dest[j * width + i] = src[--h];
		}
	}

	h = SUM * 3 / 2;
	int x = SUM * 3 / 2;

	// UV
	for (int i = 0; i < width; i += 2) {
		for (int j = 0; j < height / 2; j++) {
				dest[--x] = src[--h];
				dest[--x] = src[--h];
		}
	}
}

参考网址