YUV 可以将亮度信息(Y)与色度信息(UV)分离,没有UV信息一样可以显示完整图像,只不过是黑白的,也是一种颜色编码方法,,YUV和RGB可以通过公式互相转换,图片中每一个像素的颜色信息,除了可以用RGB的方式表示,也可以用YUV的方式表示。
Y:表示亮度 占8bit
Cb Cr表示色度,
其中Cb(U) 蓝色色度分量,占8bit
Cr(V) 红色色度分量 占8bit
YUV和RGB对比:
如果使用RGB888 RGB每个颜色分量都是8bit,一个像素的颜色为24bit 也就是3字节
使用YUV 一个像素可以减少至平均只占用12bit 内存占用为RGB888的一半,是一种不影响视觉的压缩
色度的二次采样:
人眼对亮度的敏感程度要高于对色度的敏感程度,人眼对于亮度的分辨要比对颜色的分辨要精细一点,如果把图像的色度分量减少一点,人眼也是丝毫感觉不到变化和差异的。如果在色度分量上进行 较低分辨率的采样,也就是储存较多的亮度细节,较少的色度细节,这样就可以减小图像的体积,上述过程被称为 色度的二次采样
采样格式通常用A:B:C的形式来表示,比如4:4:4 (YUV的原格式) 4:2:2 4:2:0(最需要关注)Y 为全分辨率采集
A: 一块A * 2个像素的 概念区域
B:第一行的色度采样数目
C:第二行的色度采样数目(C的值要么等于B 要么等于0)
bpp(bits per pixel)每个像素占用多少位
YUV的存储格式:
YUV的存储格式,决定了YUV数据是如何排列和存储的。YUV的存储格式可以分为3大类:
Planer(平面) YUV分量分开单独存储 ,名称通常以字母p结尾(yuv420p yuv444p)
Semi-Planer(半平面)Y分量单独存储 UV分量交错存储 名称通常以字母sp结尾 采样格式多以NV开头
Packed(紧凑型) YUV分量交错存储
大多数视频解码器都是以I420来输出原始图片的:
Android摄像头采集的原始数据的编码格式:NV21 和 NV12:
ffmpeg -i in.png -s 分辨率 -pix_fmt 像素格式 out.yuv
ffplay -video_size 分辨率 -pixel_format 像素格式 out.yuv
ffmpeg -pix_fmts 查看ffmpeng 支持的像素格式
如果不设置此选项 默认会根据输入图片的格式像素
可以通过ffprobe 查看某图片的像素格式 比如 ffprobe in.png
// YUV 图不能直接用于显示,需要转换为 RGB 格式,而 YUV 转 RGB 是一个逐像素处理的耗时操作,
// 在 CPU 端进行转换效率过低,这时正好可以利用 GPU 强大的并行处理能力来实现 YUV 到 RGB 的转换。
// 只赋值x 则会出现黑白照片效果
yuv.x = texture(y_texture, v_texCoord).r;
// 因为YUV转RGB用的是Y、U-128和V-128,texture函数返回向量值的范围是0-1.0,128表示0.5, 所以要减去0.5
yuv.y = texture(uv_texture, v_texCoord).a-0.5;
yuv.z = texture(uv_texture, v_texCoord).r-0.5;
// RGB转YUV:
// Y = 0.299 R + 0.587 G + 0.114 B
// U = - 0.1687 R - 0.3313 G + 0.5 B + 128
// V = 0.5 R - 0.4187 G - 0.0813 B + 128
// YUV转RGB
// R = Y + 1.402 (V - 128)
// G = Y - 0.34414 (U - 128) - 0.71414 (V - 128)
// B = Y + 1.772 (U - 128)
// YUV 和 RGB 的转换矩阵
highp vec3 rgb = mat3( 1.0, 1.0, 1.0, //第一列
0.0, -0.34414, 1.772, //第二列
1.403, -0.71414, 0.0 //第三列
) * yuv;