基于不同色彩空间模型(YUV/RGB)的带宽分析

YUV

  YUV 是一种彩色编码系统,主要用在视频、图形处理流水线中(pipeline)。相对于 RGB 颜色空间,设计 YUV 的目的就是为了编码、传输的方便,减少带宽占用和信息出错。它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像,只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。

和RGB转换公式

Y = 0.298R + 0.612G + 0.117B;
U = -0.168R - 0.330G + 0.498B + 128;
V = 0.449R - 0.435G - 0.083B + 128;

R = Y + 1.4075( V - 128);
G = Y - 0.3455( U - 128) - 0.7169( V - 128);
B = Y + 1.779( U - 128);

位深度

  黑白二色的图像是数字图像中最简单的一种,它只有黑、白两种颜色,也就是说它的每个像素只有1位颜色,位深度是1,用2的一次幂来表示;考虑到位深度平均分给R, G, B和Alpha,而只有RGB可以相互组合成颜色。所以4位颜色的图,它的位深度是4,只有2的4次幂种颜色,即16种颜色或16种灰度等级 ) 。8位颜色的图,位深度就是8,用2的8次幂表示,它含有256种颜色 ( 或256种灰度等级 )。24位颜色可称之为真彩色,位深度是24,它能组合成2的24次幂种颜色,即:16777216种颜色 ( 或称千万种颜色 ),超过了人眼能够分辨的颜色数量。当我们用24位来记录颜色时,实际上是以2^(8×3),即红、绿、蓝 ( RGB ) 三基色各以2的8次幂,256种颜色而存在的,三色组合就形成一千六百万种颜色。

存储方式

  在生理学中,有一条规律,那就是人类视网膜上的视网膜杆细胞要多于视网膜锥细胞,说得通俗一些,视网膜杆细胞的作用就是识别亮度,而视网膜锥细胞的作用就是识别色度。所以,你的眼睛对于亮和暗的分辨要比对颜色的分辨精细一些。

  YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0,存储方式分俩种:平面格式(planar)和压缩格式(packed)。

  planar格式:先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。

  packed格式:每个像素点的Y,U,V是连续交*存储的。

       Semi-Planar格式:Y 分量单独存放,UV 分量交错存放

  用三个图来直观地表示采集的方式吧,以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量。

 
 

  YUV 4:4:4采样,每一个Y对应一组UV分量。
  YUV 4:2:2采样,每两个Y共用一组UV分量。
  YUV 4:2:0采样,每四个Y共用一组UV分量。
  Cb、Cr的含义等同于U、V。

 

 

 

因为YUV420比较常用, 在这里就重点介绍YUV420。YUV420细分为两类:YUV420p和YUV420sp,具体排列方式又可分以下四种。

I420: YYYYYYYY UU VV    =>YUV420P
YV12: YYYYYYYY VV UU    =>YUV420P
NV12: YYYYYYYY UVUV     =>YUV420SP
NV21: YYYYYYYY VUVU     =>YUV420SP

I420如下


 
 

NV12如下


 
 

提问:

【例1】根据前面的介绍,如果用 yuv420p 来表示分辨率为 1280 * 720 的图片,位深度为8,需要占用多少存储空间呢?

  每一个像素都需要一个y值。那么总共需要 1280 * 720 = 921600 bytes ; 每四个像素需要一个u 值,那么总共需要 1280 * 720 / 4 = 230400 bytes ; 每四个像素需要一个v 值,那么总共需要 1280 * 720 / 4 = 230400 bytes。
  把 y、u、v 三个 plane 加起来就是:921600 + 230400 + 230400 = 1382400 bytes。

常见算法

(1)分离YUV420P像素数据中的Y、U、V分量

int simplest_yuv420_split(char *url, int w, int h,int num){
FILE *fp=fopen(url,"rb+");
FILE *fp1=fopen("output_420_y.y","wb+");
FILE *fp2=fopen("output_420_u.y","wb+");
FILE *fp3=fopen("output_420_v.y","wb+");
unsigned char *pic=(unsigned char *)malloc(w*h*3/2);
for(int i=0;i<num;i++){
fread(pic,1,w*h*3/2,fp);
//Y
fwrite(pic,1,w*h,fp1);
//U
fwrite(pic+w*h,1,w*h/4,fp2);
//V
fwrite(pic+w*h*5/4,1,w*h/4,fp3);
}
free(pic);
fclose(fp);
fclose(fp1);
fclose(fp2);
fclose(fp3);
return 0;
}

调用方式:

simplest_yuv420_split("lena_256x256_yuv420p.yuv",256,256,1);

原图

 
 

YUV单独存储分量的三张图片

 
 

  算法分析:如果视频帧的宽和高分别为w和h,那么一帧YUV420P像素数据一共占用wh3/2 Byte的数据。其中前wh Byte存储Y,接着的wh1/4 Byte存储U,最后wh*1/4 Byte存储V。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件分离成为三个文件

output_420_y.y:纯Y数据,分辨率为256x256。
output_420_u.y:纯U数据,分辨率为128x128。
output_420_v.y:纯V数据,分辨率为128x128。




RGB

RGB888,每个颜色信息为8位,一个颜色就有也就是有2的8次方=256的数据信息,然后一个像素通过R G B 三个不同的占比从而显示了一个颜色,这个也是“美术里面的调色板”,用最基本的几个颜色可以调出各种颜色。


正常的RGB24是由24位即3个字节来描述一个像素,R、G、B各8位。而实际使用中为了减少图像数据的尺寸,如视频领域,对R、G、B所使用的位数进行的缩减,如你所说的RGB565和RGB555。
RGB565 就是R-5bit,G-6bit,B-5bit
RGB555 就是R-5bit,G-5bit,B-5bit
RGB888 就是R-8bit,G-8bit,B-8bit ;其实这就是RGB24位
至于BMP那是RGB的像素数据基础上增加位图头数据而成的文件格式。(有兴趣可以自己用Uedit打开一个BMP图,你就会发现图片的头几位是什么信息。)

RGB的存储空间很大,所以图片一般都不小
RGB565 是16位的,2个字节,5+6+5,第一字节的前5位是R,后三位+第二字节前三位是G,第二字节后5位是B。
RGB555 也是16位的,2个字节,RGB各5位,有1位未用。
RGB888 是24位的,3个字节。

 

参考:

https://www.jianshu.com/p/d2f9be9809ad

https://blog.csdn.net/lanxiaoke123/article/details/100558572

https://zhuanlan.zhihu.com/p/384455058

posted @ 2022-07-05 16:17  忘掉名字吧orz  阅读(646)  评论(0编辑  收藏  举报