图像色彩格式
一、常见图像色彩储存模式
RGB、RGBA、ARGB、yuv444、yuv422、yuv420
二、RGB
RGB一般都比较熟悉,分表表示红、绿、蓝,图像的每个像素都可以用一组RGB值来表示, RGBA和GBRA与RGB大致相同,不同之处在于颜色排列不同和多出一个A(alpha值,用来表示RGB的色彩空间,即通俗的讲,透明度),大部分图片色彩空间都是用RGB表示的。
用16进制表示RGB或GBRA和ARGB即 #000000或#00000000,每两位代表一个颜色的色值。
例:
如果图像是ARGB,16进制色值为#99887765.
99代表alpha,为 (916+9)/255 = 0.6
88代表Red,为 816+8 = 136
77代表Green,为 716+7 = 119
65代表Blue,为 616+5 = 101
三、yuv
与RGB不同,yuv多用于流媒体图像色彩空间的表示。其优势在于可压缩性高,减少传输带宽,缩小媒体文件体积。
yuv分为yuv444、yuv422、yuv420,yuv与RGB的色彩储存方式完全不一样。
y:亮度
u(Cb):表示蓝色去掉亮度的色度
v(Cr):表示红色去掉亮度的色度
由于人眼对亮度的敏感度远大于对色度的敏感度,所以诞生了yuv422,yuv420。以前的黑白电视播放的画面,可以理解为没有uv分量只有y。
以下展示yuv图像的色彩表现方式。
yuv444:
yuv422: yuv420:
YUV 4:4:4采样,每一个Y对应一组UV分量,一个YUV占8+8+8 = 24bits 3个字节。
YUV 4:2:2采样,每两个Y共用一组UV分量,一个YUV占8+4+4 = 16bits 2个字节。
YUV 4:2:0采样,每四个Y共用一组UV分量,一个YUV占8+2+2 = 12bits 1.5个字节。
YUV420根据uv分量存储形式的不同,又分为不同的格式,对应YUV转RGB的方式也不同。几种常见格式以及YUV分量的排布如下:
I420: YYYYYYYY UU VV =>YUV420P
YV12: YYYYYYYY VV UU =>YUV420P
NV12: YYYYYYYY UVUV =>YUV420SP
NV21: YYYYYYYY VUVU =>YUV420SP
注:移动端视频采集编码大多使用yuv420
四、yuv与RGB的转换
开发中无法避免RGB与yuv的转换,比如使用GPUImage处理合成视频,并添加滤镜,必须把视频的CVPixelBuffer转位RGB,再由GPUImage去处理。。
一、三方库,推荐,libyuv:
https://github.com/yarrcc/libyuv-ios
https://github.com/illuspas/libyuv-android
二、使用shader
https://github.com/Alienchang/YUVConversion
三、自己写
void NV212RGBorBGR(const uint8_t *input, int width, int height, uint8_t *output,bool isRGB) {
int nv_off = width * height;
int i, j, y_index = 0;
int y, u, v;
int r, g, b, nv_index = 0;
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++,++y_index) {
nv_index = i / 2 * width + j - j % 2;
y = input[y_index];
u = input[nv_off + nv_index];
v = input[nv_off + nv_index + 1];
r = y + ((351 * (v - 128)) >> 8); //r
g = y - ((179 * (v - 128) + 86 * (u - 128)) >> 8); //g
b = y + ((443 * (u - 128)) >> 8); //b
r = ((r>255) ? 255 : (r<0) ? 0 : r);
g = ((g>255) ? 255 : (g<0) ? 0 : g);
b = ((b>255) ? 255 : (b<0) ? 0 : b);
if (isRGB) {
output[y_index * 3 + 0] = (uint8_t)b;
output[y_index * 3 + 1] = (uint8_t)g;
output[y_index * 3 + 2] = (uint8_t)r;
}
else {
output[y_index * 3 + 0] = (uint8_t)r;
output[y_index * 3 + 1] = (uint8_t)g;
output[y_index * 3 + 2] = (uint8_t)b;
}
}
}
}
参考:
https://blog.csdn.net/byhook/article/details/84037338
https://blog.csdn.net/qq_37833413/article/details/123940366