精华内容
参与话题
问答
  • YUV 详解

    千次阅读 2018-09-27 13:24:14
    YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很多种具体...

    YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大。YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很多种具体的格式。转载一篇对yuv格式解释的比较清楚地文章,也可以直接参考微软的那篇文章。

    对于YUV格式,比较原始的讲解是MPEG-2 VIDEO部分的解释,当然后来微软有一个比较经典的解释,中文的大多是翻译这篇文章的。文章来源:http://msdn.microsoft.com/en-us/library/aa904813(VS.80).aspx

    这里转载有人已经翻译过的,个人认为已经翻译的很不错了,遂放弃翻译。

    http://hondrif82q.spaces.live.com/blog/cns!776E82726DE60562!177.entry

    http://hondrif82q.spaces.live.com/blog/cns!776E82726DE60562!178.entry

    YUV格式解析1(播放器——project2)

    根据板卡api设计实现yuv420格式的视频播放器

    打开*.mp4;*.264类型的文件,实现其播放。

    使用的视频格式是YUV420格式

     

    YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。表2.3中的YUY2到Y211都是打包格式,而IF09到YVU9都是平面格式。(注意:在介绍各种具体格式时,YUV各分量都会带有下标,如Y0、U0、V0表示第一个像素的YUV分量,Y1、U1、V1表示第二个像素的YUV分量,以此类推。)

    MEDIASUBTYPE_YUY2 YUY2格式,以4:2:2方式打包

    MEDIASUBTYPE_YUYV YUYV格式(实际格式与YUY2相同)

    MEDIASUBTYPE_YVYU YVYU格式,以4:2:2方式打包

    MEDIASUBTYPE_UYVY UYVY格式,以4:2:2方式打包

    MEDIASUBTYPE_AYUV 带Alpha通道的4:4:4 YUV格式

    MEDIASUBTYPE_Y41P Y41P格式,以4:1:1方式打包

    MEDIASUBTYPE_Y411 Y411格式(实际格式与Y41P相同)

     MEDIASUBTYPE_Y211 Y211格式

    MEDIASUBTYPE_IF09 IF09格式

    MEDIASUBTYPE_IYUV IYUV格式

    MEDIASUBTYPE_YV12 YV12格式

     MEDIASUBTYPE_YVU9 YVU9格式

                   表2.3

     

    YUV 采样

    YUV 的优点之一是,色度频道的采样率可比 Y 频道低,同时不会明显降低视觉质量。有一种表示法可用来描述 U 和 V 与 Y 的采样频率比例,这个表示法称为 A:B:C 表示法:

    4:4:4 表示色度频道没有下采样。

    4:2:2 表示 2:1 的水平下采样,没有垂直下采样。对于每两个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。

    4:2:0 表示 2:1 的水平下采样,2:1 的垂直下采样。

    4:1:1 表示 4:1 的水平下采样,没有垂直下采样。对于每个 U 样例或 V 样例,每个扫描行都包含四个 Y 样例。与其他格式相比,4:1:1 采样不太常用,本文不对其进行详细讨论。

    图 1 显示了 4:4:4 图片中使用的采样网格。灯光样例用叉来表示,色度样例则用圈表示。

    图 1. YUV 4:4:4 样例位置

    4:2:2 采样的这种主要形式在 ITU-R Recommendation BT.601 中进行了定义。图 2 显示了此标准定义的采样网格。

    图 2. YUV 4:2:2 样例位置

    4:2:0 采样有两种常见的变化形式。其中一种形式用于 MPEG-2 视频,另一种形式用于 MPEG-1 以及 ITU-T recommendations H.261 和 H.263。图 3 显示了 MPEG-1 方案中使用的采样网格,图 4 显示了 MPEG-2 方案中使用的采样网格。

    图 3. YUV 4:2:0 样例位置(MPEG-1 方案)

    图 4. YUV 4:2:0 样例位置(MPEG-2 方案)

    与 MPEG-1 方案相比,在 MPEG-2 方案与为 4:2:2 和 4:4:4 格式定义的采样网格之间进行转换更简单一些。因此,在 Windows 中首选 MPEG-2 方案,应该考虑将其作为 4:2:0 格式的默认转换方案。

     

    表面定义

    本节讲述推荐用于视频呈现的 8 位 YUV 格式。这些格式可以分为几个类别:

     

    4:4:4 格式,每像素 32 位

    4:2:2 格式,每像素 16 位

    4:2:0 格式,每像素 16 位

    4:2:0 格式,每像素 12 位

    首先,您应该理解下列概念,这样才能理解接下来的内容:

     

    表面原点。对于本文讲述的 YUV 格式,原点 (0,0) 总是位于表面的左上角。

    跨距。表面的跨距,有时也称为间距,指的是表面的宽度,以字节数表示。对于一个表面原点位于左上角的表面来说,跨距总是正数。

    对齐。表面的对齐是根据图形显示驱动程序的不同而定的。表面始终应该 DWORD 对齐,就是说,表面中的各个行肯定都是从 32 位 (DWORD) 边界开始的。对齐可以大于 32 位,但具体取决于硬件的需求。

    打包格式与平面格式。YUV 格式可以分为打包 格式和平面 格式。在打包格式中,Y、U 和 V 组件存储在一个数组中。像素被组织到了一些巨像素组中,巨像素组的布局取决于格式。在平面格式中,Y、U 和 V 组件作为三个单独的平面进行存储。

    4:4:4 格式,每像素 32 位

    推荐一个 4:4:4 格式,FOURCC 码为 AYUV。这是一个打包格式,其中每个像素都被编码为四个连续字节,其组织顺序如下所示。

    图 5. AYUV 内存布局

    标记了 A 的字节包含 alpha 的值。

    4:2:2 格式,每像素 16 位

    支持两个 4:2:2 格式,FOURCC 码如下:

     

    YUY2

    UYVY

    两个都是打包格式,其中每个巨像素都是编码为四个连续字节的两个像素。这样会使得色度水平下采样乘以系数 2。

    YUY2

    在 YUY2 格式中,数据可被视为一个不带正负号的 char 值组成的数组,其中第一个字节包含第一个 Y 样例,第二个字节包含第一个 U (Cb) 样例,第三个字节包含第二个 Y 样例,第四个字节包含第一个 V (Cr) 样例,如图 6 所示。

    图 6. YUY2 内存布局

    如果该图像被看作由两个 little-endian WORD 值组成的数组,则第一个 WORD 在最低有效位 (LSB) 中包含 Y0,在最高有效位 (MSB) 中包含 U。第二个WORD 在 LSB 中包含 Y1,在 MSB 中包含 V。

    YUY2 是用于 Microsoft DirectX® Video Acceleration (DirectX VA) 的首选 4:2:2 像素格式。预期它会成为支持 4:2:2 视频的 DirectX VA 加速器的中期要求。

    UYVY

    此格式与 YUY2 相同,只是字节顺序是与之相反的 — 就是说,色度字节和灯光字节是翻转的(图 7)。如果该图像被看作由两个 little-endian WORD 值组成的数组,则第一个 WORD 在 LSB 中包含 U,在 MSB 中包含 Y0,第二个 WORD 在 LSB 中包含 V,在 MSB 中包含 Y1。

    图 7. UYVY 内存布局

    4:2:0 格式,每像素 16 位

    推荐两个 4:2:0 每像素 16 位格式,FOURCC 码如下:

     

    IMC1

    IMC3

    两个 FOURCC 码都是平面格式。色度频道在水平方向和垂直方向上都要以系数 2 来进行再次采样。

    IMC1

    所有 Y 样例都会作为不带正负号的 char 值组成的数组首先显示在内存中。后面跟着所有 V (Cr) 样例,然后是所有 U (Cb) 样例。V 和 U 平面与 Y 平面具有相同的跨距,从而生成如图 8 所示的内存的未使用区域。

    图 8. IMC1 内存布局

    IMC3

    此格式与 IMC1 相同,只是 U 和 V 平面进行了交换:

    图 9. IMC3 内存布局

    4:2:0 格式,每像素 12 位

    推荐四个 4:2:0 每像素 12 位格式,FOURCC 码如下:

     

    IMC2

    IMC4

    YV12

    NV12

    在所有这些格式中,色度频道在水平方向和垂直方向上都要以系数 2 来进行再次采样。

    IMC2

    此格式与 IMC1 相同,只是 V (Cr) 和 U (Cb) 行在半跨距边界处进行了交错。换句话说,就是色度区域中的每个完整跨距行都以一行 V 样例开始,然后是一行在下一个半跨距边界处开始的 U 样例(图 10)。此布局与 IMC1 相比,能够更加高效地利用地址空间。它的色度地址空间缩小了一半,因此整体地址空间缩小了 25%。在各个 4:2:0 格式中,IMC2 是第二首选格式,排在 NV12 之后。

    图 10. IMC2 内存布局

    IMC4

    此格式与 IMC2 相同,只是 U (Cb) 和 V (Cr) 行进行了交换:

    图 11. IMC4 内存布局

    YV12

    所有 Y 样例都会作为不带正负号的 char 值组成的数组首先显示在内存中。此数组后面紧接着所有 V (Cr) 样例。V 平面的跨距为 Y 平面跨距的一半,V 平面包含的行为 Y 平面包含行的一半。V 平面后面紧接着所有 U (Cb) 样例,它的跨距和行数与 V 平面相同(图 12)。

    图 12. YV12 内存布局

    NV12

    所有 Y 样例都会作为由不带正负号的 char 值组成的数组首先显示在内存中,并且行数为偶数。Y 平面后面紧接着一个由不带正负号的char 值组成的数组,其中包含了打包的 U (Cb) 和 V (Cr) 样例,如图 13 所示。当组合的 U-V 数组被视为一个由 little-endianWORD 值组成的数组时,LSB 包含 U 值,MSB 包含 V 值。NV12 是用于 DirectX VA 的首选 4:2:0 像素格式。预期它会成为支持 4:2:0 视频的 DirectX VA 加速器的中期要求。

     

    YUV格式解析2

    又确认了一下H264的视频格式——H264支持4:2:0的连续或隔行视频的编码和解码

     

    YUV(亦称YCrCb)是被欧洲电视系统所采用的一种颜色编码方法(属于PAL)。YUV主要用于优化彩色视频信号的传输,使其向后兼容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需占用极少的带宽(RGB要求三个独立的视频信号同时传输)。其中“Y”表示明亮度(Luminance或Luma),也就是灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于指定像素的颜色。“亮度”是通过RGB输入信号来创建的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面—色调与饱和度,分别用Cr和CB来表示。其中,Cr反映了GB输入信号红色部分与RGB信号亮度值之间的差异。而CB反映的是RGB输入信号蓝色部分与RGB信号亮度值之同的差异。  

    补充一下场的概念——

    场的概念不是从DV才开始有的,电视系统已经有了(当然,DV和电视的关系大家都知道)归根结底还是扫描的问题,具体到PAL制式是:
    每秒25帧,每帧两场,扫描线(包括电视机的电子束)自上而下先扫描一场,然后再自上而下扫描第二场
    之所以引入场的概念,我的理解是主要为了在有限的带宽和成本内使画面运动更加平滑和消除闪烁感。
    这两个场的扫描线是一条一条互相间隔开的,比如说对于一个帧来讲,最上面一条线编号为0,紧挨着的是1,再下来是2,3,4,5,6。。。。那么第一场也许是0,2,4,6;也许是1,3,5,7——这就是隔行扫描
    在逐行扫描模式下,就是扫描线按照0,1,2,3,4,5的顺序依次扫描,很明显,这时候就不存在场的概念了。

     

     

    下面区分一下YUV和YCbCr

    YUV色彩模型来源于RGB模型,

    该模型的特点是将亮度和色度分离开,从而适合于图像处理领域。

    应用:模拟领域

    Y'= 0.299*R' + 0.587*G' + 0.114*B'

    U'= -0.147*R' - 0.289*G' + 0.436*B' = 0.492*(B'- Y')

    V'= 0.615*R' - 0.515*G' - 0.100*B' = 0.877*(R'- Y')

    R' = Y' + 1.140*V'

    G' = Y' - 0.394*U' - 0.581*V'

    B' = Y' + 2.032*U'

    YCbCr模型来源于YUV模型。YCbCr是 YUV 颜色空间的偏移版本.

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

    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

    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)

    PS: 上面各个符号都带了一撇,表示该符号在原值基础上进行了伽马校正,伽马校正有助于弥补在抗锯齿的过程中,线性分配伽马值所带来的细节损失,使图像细节更加丰富。在没有采用伽马校正的情况下,暗部细节不容易显现出来,而采用了这一图像增强技术以后,图像的层次更加明晰了。

    所以说H264里面的YUV应属于YCbCr.
     

    下面再仔细谈谈YUV格式, YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组分开存放YUV三个分量,就像是一个三维平面一样。

    我们常说得YUV420属于planar格式的YUV,颜色比例如下:

    Y0U0V0             Y1                 Y2U2V2                      Y3

    Y4                 Y5                 Y6                          Y7

    Y8U8V8             Y9                 Y10U10V10                   Y11

    Y12                Y13                Y14                         Y15

    其他格式YUV可以点这里查看详细内容, 而在YUV文件中YUV420又是怎么存储的呢? 在常见H264测试的YUV序列中,例如CIF图像大小的YUV序列(352*288),在文件开始并没有文件头,直接就是YUV数据,先存第一帧的Y信息,长度为352*288个byte, 然后是第一帧U信息长度是352*288/4个byte, 最后是第一帧的V信息,长度是352*288/4个byte, 因此可以算出第一帧数据总长度是352*288*1.5,即152064个byte, 如果这个序列是300帧的话, 那么序列总长度即为152064*300=44550KB,这也就是为什么常见的300帧CIF序列总是44M的原因.

     

     

    4:4:4采样就是说三种元素Y,Cb,Cr有同样的分辨率,这样的话,在每一个像素点上都对这三种元素进行采样.数字4是指在水平方向上对于各种元素的采样率,比如说,每四个亮度采样点就有四个Cb的Cr采样值.4:4:4采样完整地保留了所有的信息值.4:2:2采样中(有时记为YUY2),色度元素在纵向与亮度值有同样的分辨率,而在横向则是亮度分辨率的一半(4:2:2表示每四个亮度值就有两个Cb和Cr采样.)4:2:2视频用来构造高品质的视频彩色信号.

    在流行的4:2:0采样格式中(常记为YV12)Cb和Cr在水平和垂直方向上有Y分辨率的一半.4:2:0有些不同,因为它并不是指在实际采样中使用4:2:0,而是在编码史中定义这种编码方法是用来区别于4:4:4和4:2:2方法的).4:2:0采样被广泛地应用于消费应用中,比如视频会议,数字电视和DVD存储中。因为每个颜色差别元素中包含了四分之一的Y采样元素量,那么4:2:0YCbCr视频需要刚好4: 4:4或RGB视频中采样量的一半。

    4:2:0采样有时被描述是一个"每像素12位"的方法。这么说的原因可以从对四个像素的采样中看出. 使用4:4:4采样,一共要进行12次采样,对每一个Y,Cb和Cr,就需要12*8=96位,平均下来要96/4=24位。使用4:2:0就需要6*8 =48位,平均每个像素48/4=12位。

    在一个4:2:0隔行扫描的视频序列中,对应于一个完整的视频帧的Y,Cb,Cr采样分配到两个场中。可以得到,隔行扫描的总采样数跟渐进式扫描中使用的采样数目是相同的。

    对比一下:

    Y41P(和Y411)(packed格式)格式为每个像素保留Y分量,而UV分量在水平方向上每4个像素采样一次。一个宏像素为12个字节,实际表示8个像素。图像数据中YUV分量排列顺序如下: U0 Y0 V0 Y1 U4 Y2 V4 Y3 Y4 Y5 Y6 Y8 …

     

    IYUV格式(planar)为每个像素都提取Y分量,而在UV分量的提取时,首先将图像分成若干个2 x 2的宏块,然后每个宏块提取一个U分量和一个V分量。YV12格式与IYUV类似,但仍然是平面模式。

     

    YUV411、YUV420格式多见于DV数据中,前者用于NTSC制,后者用于PAL制。YUV411为每个像素都提取Y分量,而UV分量在水平方向上每4个像素采样一次。YUV420并非V分量采样为0,而是跟YUV411相比,在水平方向上提高一倍色差采样频率,在垂直方向上以U/V间隔的方式减小一半色差采样,如下图所示。

    (好像显示不出来突下图像)

     

     

    各种格式的具体使用位数的需求(使用4:2:0采样,对于每个元素用8个位大小表示):

    格式: Sub-QCIF 亮度分辨率: 128*96  每帧使用的位: 147456
    格式: QCIF  亮度分辨率: 176*144  每帧使用的位: 304128
    格式: CIF  亮度分辨率: 352*288  每帧使用的位: 1216512
    格式:  4CIF  亮度分辨率: 704*576  每帧使用的位: 4866048

    --------------------- 本文来自 book_zhouqingjun216 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/book_zhouqingjun216/article/details/51706133?utm_source=copy

    展开全文
  • 对颜色空间YUV、RGB的理解

    万次阅读 多人点赞 2018-06-08 23:57:45
    http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html https://www.jianshu.com/p/a91502c00fb0

    接触到了一些yuv相关的信息。从Camera中拿到的每一帧,它的默认格式是NV21,它是一种yuv格式,然后转成OpenCV所需的BGR。Camera的每一帧的数据格式还可以指定成别的格式。因此开始关注了yuv这个名词,后面还有yuv的各种衍生,因此仔细地梳理一下自己的理解,以及与RGB对比。

    什么是RGB

    对RGB,并不陌生,从初中开始接触的色光的三原色,告诉我们我们可以看到的光可以由这三种颜色按一定的比例去混合得到;后来在HTML以及Android开发中设置元素/控件的颜色时,可以通过一串数字,得到某个特定的颜色。这就是RGB的应用。
    这里写图片描述

    RGB 模型是目前常用的一种彩色信息表达方式,它使用红、绿、蓝三原色的亮度来定量表示颜色。该模型也称为加色混色模型,是以RGB三色光互相叠加来实现混色的方法,因而适合于显示器等发光体的显示。

    RGB 颜色模型可以看做三维直角坐标颜色系统中的一个单位正方体。任何一种颜色在RGB 颜色空间中都可以用三维空间中的一个点来表示。在RGB 颜色空间上,当任何一个基色的亮度值为零时,即在原点处,就显示为黑色。当三种基色都达到最高亮度时,就表现为白色。在连接黑色与白色的对角线上,是亮度等量的三基色混合而成的灰色,该线称为灰色线。

    什么是BGR

    与RGB类似,只是存储时B位与R位的位置进行调换。

    什么是YCbCr

    Y表示亮度,CbCr表示颜色。怎么表示颜色,可以看下面这幅坐标图:
    这里写图片描述
    Y要如何表示亮度呢,下面是Y在不同的情况下的表现:
    这里写图片描述
    因此可以这样理解,同样是使用三个数来表示某个像素点的颜色,但是这三个数的意义变了,与RGB相比。然后接下来是各种yuv的衍生物。

    The scope of the terms Y′UV, YUV, YCbCr, YPbPr, etc., is sometimes ambiguous and overlapping. Historically, the terms YUV and Y′UV were used for a specific analog encoding of color information in television systems, while YCbCr was used for digital encoding of color information suited for video and still-image compression and transmission such as MPEG and JPEG. Today, the term YUV is commonly used in the computer industry to describe file-formats that are encoded using YCbCr.

    上面的意思是,这些术语有时真的很难区分,因为定义也是模糊不清。不过重要的是最后面那一句话:现在的YUV是通常用于计算机领域用来表示使用YCbCr编码的文件。所以可以粗浅地视YUV为YCbCr。

    不过我在Camera预览中的每一帧中,除默认格式NV21外,还发现了其它的格式如YV12。去搜一些关于他们的资料时,发现都是yuv420系列的。具体有什么差异呢?


    膜拜一下大佬的博客(稍作编辑与修改):

    YUV分类与意义

    planar和packed
    对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。
    对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。

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

    与我们熟知的RGB类似,YUV也是一种颜色编码方法,主要用于电视系统以及模拟视频领域,它将亮度信息(Y)与色彩信息(UV)分离,没有UV信息一样可以显示完整的图像(是不是写错了),只不过是黑白的,这样的设计很好地解决了彩色电视机与黑白电视的兼容问题。并且,YUV不像RGB那样要求三个独立的视频信号同时传输,所以用YUV方式传送占用极少的频宽。

    YUV码流的存储格式其实与其采样的方式密切相关,主流的采样方式有三种,YUV4:4:4,YUV4:2:2,YUV4:2:0,关于其详细原理,可以通过网上其它文章了解,这里我想强调的是如何根据其采样格式来从码流中还原每个像素点的YUV值,因为只有正确地还原了每个像素点的YUV值,才能通过YUV与RGB的转换公式提取出每个像素点的RGB值,然后显示出来。

    存储方式

    用三个图来直观地表示采集的方式吧,以黑点表示采样该像素点的Y分量,以空心圆圈表示采用该像素点的UV分量。
    这里写图片描述
    先记住下面这段话,以后提取每个像素的YUV分量会用到。

    YUV 4:4:4采样,每一个Y对应一组UV分量。
    YUV 4:2:2采样,每两个Y共用一组UV分量。
    YUV 4:2:0采样,每四个Y共用一组UV分量。

    下面我用图的形式给出常见的YUV码流的存储方式,并在存储方式后面附有取样每个像素点的YUV数据的方法,其中,Cb、Cr的含义等同于U、V。

    YUVY 格式 (属于YUV422)

    这里写图片描述
    YUYV为YUV422采样的存储格式中的一种,相邻的两个Y共用其相邻的两个Cb、Cr,分析,对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00,其他的像素点的YUV取值依次类推。

    UYVY 格式 (属于YUV422)

    这里写图片描述
    UYVY格式也是YUV422采样的存储格式中的一种,只不过与YUYV不同的是UV的排列顺序不一样而已,还原其每个像素点的YUV值的方法与上面一样。

    YUV422P(属于YUV422)

    这里写图片描述
    YUV422P也属于YUV422的一种,它是一种Plane模式,即平面模式,并不是将YUV数据交错存储,而是先存放所有的Y分量,然后存储所有的U(Cb)分量,最后存储所有的V(Cr)分量,如上图所示。其每一个像素点的YUV值提取方法也是遵循YUV422格式的最基本提取方法,即两个Y共用一个UV。比如,对于像素点Y’00、Y’01 而言,其Cb、Cr的值均为 Cb00、Cr00。

    YV12,YU12格式(属于YUV420)

    这里写图片描述
    YU12和YV12属于YUV420格式,也是一种Plane模式,将Y、U、V分量分别打包,依次存储。其每一个像素点的YUV数据提取遵循YUV420格式的提取方式,即4个Y分量共用一组UV。注意,上图中,Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00,其他依次类推。

    NV12、NV21(属于YUV420)

    这里写图片描述

    NV12和NV21属于YUV420格式,是一种two-plane模式,即Y和UV分为两个Plane,但是UV(CbCr)为交错存储,而不是分为三个plane。其提取方式与上一种类似,即Y’00、Y’01、Y’10、Y’11共用Cr00、Cb00

    YUV文件大小计算

    以720×488大小图象YUV420 planar为例,其存储格式是: 共大小为(720×480×3>>1)字节,

    分为三个部分:Y,U和V

    Y分量: (720×480)个字节
    U(Cb)分量:(720×480>>2)个字节
    V(Cr)分量:(720×480>>2)个字节

    三个部分内部均是行优先存储,三个部分之间是Y,U,V 顺序存储。

    0--720×480字节是Y分量值,
    720×480--720×480×5/4字节是U分量
    720×480×5/4 --720×480×3/2字节是V分量。

    4 :2: 2 和4:2:0 转换

    最简单的方式:

    YUV4:2:2 —> YUV4:2:0 Y不变,将U和V信号值在行(垂直方向)在进行一次隔行抽样。 YUV4:2:0 —> YUV4:2:2 Y不变,将U和V信号值的每一行分别拷贝一份形成连续两行数据。

    在YUV420中,一个像素点对应一个Y,一个4X4的小方块对应一个U和V。对于所有YUV420图像,它们的Y值排列是完全相同的,因为只有Y的图像就是灰度图像。YUV420sp与YUV420p的数据格式它们的UV排列在原理上是完全不同的。420p它是先把U存放完后,再存放V,也就是说UV它们是连续的。而420sp它是UV、UV这样交替存放的。(见下图) 有了上面的理论,我就可以准确的计算出一个YUV420在内存中存放的大小。 width * hight =Y(总和) U = Y / 4 V = Y / 4。所以YUV420 数据在内存中的长度是 width * hight * 3 / 2,

    假设一个分辨率为8X4的YUV图像,它们的格式如下图:
    这里写图片描述
    YUV420p数据格式如下图
    这里写图片描述

    旋转90度的算法:

    public static void rotateYUV240SP(byte[] src,byte[] des,int width,int height){  
        int wh = width * height;
        //旋转Y
        int k = 0;
        for(int i=0;i<width;i++) {
            for(int j=0;j<height;j++) {
                des[k] = src[width*j + i];   
                k++;
            }
        }
        for(int i=0;i<width;i+=2) {
            for(int j=0;j<height/2;j++) { 
                des[k] = src[wh+ width*j + i]; 
                des[k+1]=src[wh + width*j + i+1];
                k+=2;
            }
        }
    }

    YV12和I420的区别

    一般来说,直接采集到的视频数据是RGB24的格式,RGB24一帧的大小size=width×heigth×3 Bit,RGB32的size=width×heigth×4,如果是I420(即YUV标准格式4:2:0)的数据量是 size=width×heigth×1.5 Bit。 在采集到RGB24数据后,需要对这个格式的数据进行第一次压缩。即将图像的颜色空间由RGB2YUV。因为,X264在进行编码的时候需要标准的YUV(4:2:0)。但是这里需要注意的是,虽然YV12也是(4:2:0),但是YV12和I420的却是不同的,在存储空间上面有些区别。如下: YV12 : 亮度(行×列) + U(行×列/4) + V(行×列/4)

    I420 : 亮度(行×列) + V(行×列/4) + U(行×列/4)

    可以看出,YV12和I420基本上是一样的,就是UV的顺序不同

    继续我们的话题,经过第一次数据压缩后RGB24->YUV(I420)。这样,数据量将减少一半,为什么呢?呵呵,这个就太基础了,我就不多写了。同样,如果是RGB24->YUV(YV12),也是减少一半。但是,虽然都是一半,如果是YV12的话效果就有很大损失。然后,经过X264编码后,数据量将大大减少。将编码后的数据打包,通过RTP实时传送。到达目的地后,将数据取出,进行解码。完成解码后,数据仍然是YUV格式的,所以,还需要一次转换,这样windows的驱动才可以处理,就是YUV2RGB24。

    YUV420P和 YUV420SP的区别

    YUV420P,Y,U,V三个分量都是平面格式,分为I420和YV12。I420格式和YV12格式的不同处在U平面和V平面的位置不同。在I420格式中,U平面紧跟在Y平面之后,然后才是V平面(即:YUV);但YV12则是相反(即:YVU)。
    YUV420SP, Y分量平面格式,UV打包格式, 即NV12。 NV12与NV21类似,U 和 V 交错排列,不同在于UV顺序。

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


    Y′UV420p (and Y′V12 or YV12) to RGB888 conversion

    Y′UV420p is a planar format, meaning that the Y′, U, and V values are grouped together instead of interspersed. The reason for this is that by grouping the U and V values together, the image becomes much more compressible. When given an array of an image in the Y′UV420p format, all the Y′ values come first, followed by all the U values, followed finally by all the V values.

    The Y′V12 format is essentially the same as Y′UV420p, but it has the U and V data switched: the Y′ values are followed by the V values, with the U values last. As long as care is taken to extract U and V values from the proper locations, both Y′UV420p and Y′V12 can be processed using the same algorithm.

    As with most Y′UV formats, there are as many Y′ values as there are pixels. Where X equals the height multiplied by the width, the first X indices in the array are Y′ values that correspond to each individual pixel. However, there are only one fourth as many U and V values. The U and V values correspond to each 2 by 2 block of the image, meaning each U and V entry applies to four pixels. After the Y′ values, the next X/4 indices are the U values for each 2 by 2 block, and the next X/4 indices after that are the V values that also apply to each 2 by 2 block.

    Translating Y′UV420p to RGB is a more involved process compared to the previous formats. Lookup of the Y′, U and V values can be done using the following method:

    size.total = size.width * size.height;
    y = yuv[position.y * size.width + position.x];
    u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
    v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total + (size.total / 4)];
    rgb = Y′UV420toRGB888(y, u, v);

    这里写图片描述
    As shown in the above image, the Y′, U and V components in Y′UV420 are encoded separately in sequential blocks. A Y′ value is stored for every pixel, followed by a U value for each 2×2 square block of pixels, and finally a V value for each 2×2 block. Corresponding Y′, U and V values are shown using the same color in the diagram above. Read line-by-line as a byte stream from a device, the Y′ block would be found at position 0, the U block at position x×y (6×4 = 24 in this example) and the V block at position x×y + (x×y)/4 (here, 6×4 + (6×4)/4 = 30).

    Y′UV420sp (NV21) to RGB conversion (Android)

    This format (NV21) is the standard picture format on Android camera preview. YUV 4:2:0 planar image, with 8 bit Y samples, followed by interleaved V/U plane with 8bit 2x2 subsampled chroma samples.
    C++ code used on Android to convert pixels of YUVImage:

    void YUVImage::yuv2rgb(uint8_t yValue, uint8_t uValue, uint8_t vValue,
            uint8_t *r, uint8_t *g, uint8_t *b) const {
        int rTmp = yValue + (1.370705 * (vValue-128));
        int gTmp = yValue - (0.698001 * (vValue-128)) - (0.337633 * (uValue-128));
        int bTmp = yValue + (1.732446 * (uValue-128));
        *r = clamp(rTmp, 0, 255);
        *g = clamp(gTmp, 0, 255);
        *b = clamp(bTmp, 0, 255);
    }

    参考:
    http://www.cnblogs.com/azraelly/archive/2013/01/01/2841269.html
    https://www.jianshu.com/p/a91502c00fb0
    https://en.wikipedia.org/wiki/YUV

    展开全文
  • 视音频数据处理入门:RGB、YUV像素数据处理

    万次阅读 多人点赞 2016-01-29 17:01:12
    有段时间没有写博客了,这两天写起博客来竟然感觉有些兴奋,仿佛找回了原来的感觉。前一阵子在梳理以前文章的时候,发现自己虽然总结了各种视音频应用程序,却还缺少一个适合无视音频背景人员学习的“最基础”的程序...

    =====================================================

    视音频数据处理入门系列文章:

    视音频数据处理入门:RGB、YUV像素数据处理

    视音频数据处理入门:PCM音频采样数据处理

    视音频数据处理入门:H.264视频码流解析

    视音频数据处理入门:AAC音频码流解析

    视音频数据处理入门:FLV封装格式解析

    视音频数据处理入门:UDP-RTP协议解析

    =====================================================


    有段时间没有写博客了,这两天写起博客来竟然感觉有些兴奋,仿佛找回了原来的感觉。前一阵子在梳理以前文章的时候,发现自己虽然总结了各种视音频应用程序,却还缺少一个适合无视音频背景人员学习的“最基础”的程序。因此抽时间将以前写过的代码整理成了一个小项目。这个小项目里面包含了一系列简单的函数,可以对RGB/YUV视频像素数据、PCM音频采样数据、H.264视频码流、AAC音频码流、FLV封装格式数据、UDP/RTP协议数据进行简单处理。这个项目的一大特点就是没有使用任何的第三方类库,完全借助于C语言的基本函数实现了功能。通过对这些代码的学习,可以让初学者迅速掌握视音频数据的基本格式。有关上述几种格式的介绍可以参考文章《[总结]视音频编解码技术零基础学习方法》。

    从这篇文章开始打算写6篇文章分别记录上述6种不同类型的视音频数据的处理方法。本文首先记录第一部分即RGB/YUV视频像素数据的处理方法。视频像素数据在视频播放器的解码流程中的位置如下图所示。


    本文分别介绍如下几个RGB/YUV视频像素数据处理函数:
    分离YUV420P像素数据中的Y、U、V分量
    分离YUV444P像素数据中的Y、U、V分量
    将YUV420P像素数据去掉颜色(变成灰度图)
    将YUV420P像素数据的亮度减半
    将YUV420P像素数据的周围加上边框
    生成YUV420P格式的灰阶测试图
    计算两个YUV420P像素数据的PSNR
    分离RGB24像素数据中的R、G、B分量
    将RGB24格式像素数据封装为BMP图像
    将RGB24格式像素数据转换为YUV420P格式像素数据
    生成RGB24格式的彩条测试图

    本文中的RGB/YUV文件需要使用RGB/YUV播放器才能查看。YUV播放器种类比较多,例如YUV Player Deluxe,或者开源播放器(参考文章《修改了一个YUV/RGB播放器》)等。



    函数列表


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

    本程序中的函数可以将YUV420P数据中的Y、U、V三个分量分离开来并保存成三个文件。函数的代码如下所示。
    /**
     * Split Y, U, V planes in YUV420P file.
     * @param url  Location of Input YUV file.
     * @param w    Width of Input YUV file.
     * @param h    Height of Input YUV file.
     * @param num  Number of frames to process.
     *
     */
    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);

    从代码可以看出,如果视频帧的宽和高分别为w和h,那么一帧YUV420P像素数据一共占用w*h*3/2 Byte的数据。其中前w*h Byte存储Y,接着的w*h*1/4 Byte存储U,最后w*h*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。

    注:本文中像素的采样位数一律为8bit。由于1Byte=8bit,所以一个像素的一个分量的采样值占用1Byte。


    程序输入的原图如下所示。

    lena_256x256_yuv420p.yuv

    程序输出的三个文件的截图如下图所示。在这里需要注意输出的U、V分量在YUV播放器中也是当做Y分量进行播放的。

     

    output_420_y.y

               

    output_420_u.y和output_420_v.y


    (2)分离YUV444P像素数据中的Y、U、V分量

    本程序中的函数可以将YUV444P数据中的Y、U、V三个分量分离开来并保存成三个文件。函数的代码如下所示。
    /**
     * Split Y, U, V planes in YUV444P file.
     * @param url  Location of YUV file.
     * @param w    Width of Input YUV file.
     * @param h    Height of Input YUV file.
     * @param num  Number of frames to process.
     *
     */
    int simplest_yuv444_split(char *url, int w, int h,int num){
    	FILE *fp=fopen(url,"rb+");
    	FILE *fp1=fopen("output_444_y.y","wb+");
    	FILE *fp2=fopen("output_444_u.y","wb+");
    	FILE *fp3=fopen("output_444_v.y","wb+");
    	unsigned char *pic=(unsigned char *)malloc(w*h*3);
    
    	for(int i=0;i<num;i++){
    		fread(pic,1,w*h*3,fp);
    		//Y
    		fwrite(pic,1,w*h,fp1);
    		//U
    		fwrite(pic+w*h,1,w*h,fp2);
    		//V
    		fwrite(pic+w*h*2,1,w*h,fp3);
    	}
    
    	free(pic);
    	fclose(fp);
    	fclose(fp1);
    	fclose(fp2);
    	fclose(fp3);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_yuv444_split("lena_256x256_yuv444p.yuv",256,256,1);
    从代码可以看出,如果视频帧的宽和高分别为w和h,那么一帧YUV444P像素数据一共占用w*h*3 Byte的数据。其中前w*h Byte存储Y,接着的w*h Byte存储U,最后w*h Byte存储V。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv444p.yuv的YUV444P格式的像素数据文件分离成为三个文件:
    output_444_y.y:纯Y数据,分辨率为256x256。
    output_444_u.y:纯U数据,分辨率为256x256。
    output_444_v.y:纯V数据,分辨率为256x256。

    输入的原图如下所示。


    输出的三个文件的截图如下图所示。

     

    output_444_y.y

     

    output_444_u.y

     

    output_444_v.y

    (3) 将YUV420P像素数据去掉颜色(变成灰度图)

    本程序中的函数可以将YUV420P格式像素数据的彩色去掉,变成纯粹的灰度图。函数的代码如下。
    /**
     * Convert YUV420P file to gray picture
     * @param url     Location of Input YUV file.
     * @param w       Width of Input YUV file.
     * @param h       Height of Input YUV file.
     * @param num     Number of frames to process.
     */
    int simplest_yuv420_gray(char *url, int w, int h,int num){
    	FILE *fp=fopen(url,"rb+");
    	FILE *fp1=fopen("output_gray.yuv","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);
    		//Gray
    		memset(pic+w*h,128,w*h/2);
    		fwrite(pic,1,w*h*3/2,fp1);
    	}
    
    	free(pic);
    	fclose(fp);
    	fclose(fp1);
    	return 0;
    }


    调用上面函数的方法如下所示。

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

    从代码可以看出,如果想把YUV格式像素数据变成灰度图像,只需要将U、V分量设置成128即可。这是因为U、V是图像中的经过偏置处理的色度分量。色度分量在偏置处理前的取值范围是-128至127,这时候的无色对应的是“0”值。经过偏置后色度分量取值变成了0至255,因而此时的无色对应的就是128了。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件处理成名称为output_gray.yuv的YUV420P格式的像素数据文件。输入的原图如下所示。
     
    处理后的图像如下所示。
     


    (4)将YUV420P像素数据的亮度减半

    本程序中的函数可以通过将YUV数据中的亮度分量Y的数值减半的方法,降低图像的亮度。函数代码如下所示。
    /**
     * Halve Y value of YUV420P file
     * @param url     Location of Input YUV file.
     * @param w       Width of Input YUV file.
     * @param h       Height of Input YUV file.
     * @param num     Number of frames to process.
     */
    int simplest_yuv420_halfy(char *url, int w, int h,int num){
    	FILE *fp=fopen(url,"rb+");
    	FILE *fp1=fopen("output_half.yuv","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);
    		//Half
    		for(int j=0;j<w*h;j++){
    			unsigned char temp=pic[j]/2;
    			//printf("%d,\n",temp);
    			pic[j]=temp;
    		}
    		fwrite(pic,1,w*h*3/2,fp1);
    	}
    
    	free(pic);
    	fclose(fp);
    	fclose(fp1);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_yuv420_halfy("lena_256x256_yuv420p.yuv",256,256,1);

    从代码可以看出,如果打算将图像的亮度减半,只要将图像的每个像素的Y值取出来分别进行除以2的工作就可以了。图像的每个Y值占用1 Byte,取值范围是0至255,对应C语言中的unsigned char数据类型。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件处理成名称为output_half.yuv的YUV420P格式的像素数据文件。输入的原图如下所示。


    处理后的图像如下所示。
     

    (5)将YUV420P像素数据的周围加上边框

    本程序中的函数可以通过修改YUV数据中特定位置的亮度分量Y的数值,给图像添加一个“边框”的效果。函数代码如下所示。
    /**
     * Add border for YUV420P file
     * @param url     Location of Input YUV file.
     * @param w       Width of Input YUV file.
     * @param h       Height of Input YUV file.
     * @param border  Width of Border.
     * @param num     Number of frames to process.
     */
    int simplest_yuv420_border(char *url, int w, int h,int border,int num){
    	FILE *fp=fopen(url,"rb+");
    	FILE *fp1=fopen("output_border.yuv","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
    		for(int j=0;j<h;j++){
    			for(int k=0;k<w;k++){
    				if(k<border||k>(w-border)||j<border||j>(h-border)){
    					pic[j*w+k]=255;
    					//pic[j*w+k]=0;
    				}
    			}
    		}
    		fwrite(pic,1,w*h*3/2,fp1);
    	}
    
    	free(pic);
    	fclose(fp);
    	fclose(fp1);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_yuv420_border("lena_256x256_yuv420p.yuv",256,256,20,1);

    从代码可以看出,图像的边框的宽度为border,本程序将距离图像边缘border范围内的像素的亮度分量Y的取值设置成了亮度最大值255。上述调用函数的代码运行后,将会把一张分辨率为256x256的名称为lena_256x256_yuv420p.yuv的YUV420P格式的像素数据文件处理成名称为output_border.yuv的YUV420P格式的像素数据文件。输入的原图如下所示。


    处理后的图像如下所示。



    (6) 生成YUV420P格式的灰阶测试图

    本程序中的函数可以生成一张YUV420P格式的灰阶测试图。函数代码如下所示。
    /**
     * Generate YUV420P gray scale bar.
     * @param width    Width of Output YUV file.
     * @param height   Height of Output YUV file.
     * @param ymin     Max value of Y
     * @param ymax     Min value of Y
     * @param barnum   Number of bars
     * @param url_out  Location of Output YUV file.
     */
    int simplest_yuv420_graybar(int width, int height,int ymin,int ymax,int barnum,char *url_out){
    	int barwidth;
    	float lum_inc;
    	unsigned char lum_temp;
    	int uv_width,uv_height;
    	FILE *fp=NULL;
    	unsigned char *data_y=NULL;
    	unsigned char *data_u=NULL;
    	unsigned char *data_v=NULL;
    	int t=0,i=0,j=0;
    
    	barwidth=width/barnum;
    	lum_inc=((float)(ymax-ymin))/((float)(barnum-1));
    	uv_width=width/2;
    	uv_height=height/2;
    
    	data_y=(unsigned char *)malloc(width*height);
    	data_u=(unsigned char *)malloc(uv_width*uv_height);
    	data_v=(unsigned char *)malloc(uv_width*uv_height);
    
    	if((fp=fopen(url_out,"wb+"))==NULL){
    		printf("Error: Cannot create file!");
    		return -1;
    	}
    
    	//Output Info
    	printf("Y, U, V value from picture's left to right:\n");
    	for(t=0;t<(width/barwidth);t++){
    		lum_temp=ymin+(char)(t*lum_inc);
    		printf("%3d, 128, 128\n",lum_temp);
    	}
    	//Gen Data
    	for(j=0;j<height;j++){
    		for(i=0;i<width;i++){
    			t=i/barwidth;
    			lum_temp=ymin+(char)(t*lum_inc);
    			data_y[j*width+i]=lum_temp;
    		}
    	}
    	for(j=0;j<uv_height;j++){
    		for(i=0;i<uv_width;i++){
    			data_u[j*uv_width+i]=128;
    		}
    	}
    	for(j=0;j<uv_height;j++){
    		for(i=0;i<uv_width;i++){
    			data_v[j*uv_width+i]=128;
    		}
    	}
    	fwrite(data_y,width*height,1,fp);
    	fwrite(data_u,uv_width*uv_height,1,fp);
    	fwrite(data_v,uv_width*uv_height,1,fp);
    	fclose(fp);
    	free(data_y);
    	free(data_u);
    	free(data_v);
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_yuv420_graybar(640, 360,0,255,10,"graybar_640x360.yuv");

    从源代码可以看出,本程序一方面通过灰阶测试图的亮度最小值ymin,亮度最大值ymax,灰阶数量barnum确定每一个灰度条中像素的亮度分量Y的取值。另一方面还要根据图像的宽度width和图像的高度height以及灰阶数量barnum确定每一个灰度条的宽度。有了这两方面信息之后,就可以生成相应的图片了。上述调用函数的代码运行后,会生成一个取值范围从0-255,一共包含10个灰度条的YUV420P格式的测试图。测试图的内容如下所示。
     
    从程序也可以得到从左到右10个灰度条的Y、U、V取值,如下所示。

    Y

    U

    V

      0

    128

    128

     28

    128

    128

     56

    128

    128

     85

    128

    128

    113

    128

    128

    141

    128

    128

    170

    128

    128

    198

    128

    128

    226

    128

    128

    255

    128

    128


    (7)计算两个YUV420P像素数据的PSNR

    PSNR是最基本的视频质量评价方法。本程序中的函数可以对比两张YUV图片中亮度分量Y的PSNR。函数的代码如下所示。
    /**
     * Calculate PSNR between 2 YUV420P file
     * @param url1     Location of first Input YUV file.
     * @param url2     Location of another Input YUV file.
     * @param w        Width of Input YUV file.
     * @param h        Height of Input YUV file.
     * @param num      Number of frames to process.
     */
    int simplest_yuv420_psnr(char *url1,char *url2,int w,int h,int num){
    	FILE *fp1=fopen(url1,"rb+");
    	FILE *fp2=fopen(url2,"rb+");
    	unsigned char *pic1=(unsigned char *)malloc(w*h);
    	unsigned char *pic2=(unsigned char *)malloc(w*h);
    
    	for(int i=0;i<num;i++){
    		fread(pic1,1,w*h,fp1);
    		fread(pic2,1,w*h,fp2);
    
    		double mse_sum=0,mse=0,psnr=0;
    		for(int j=0;j<w*h;j++){
    			mse_sum+=pow((double)(pic1[j]-pic2[j]),2);
    		}
    		mse=mse_sum/(w*h);
    		psnr=10*log10(255.0*255.0/mse);
    		printf("%5.3f\n",psnr);
    
    		fseek(fp1,w*h/2,SEEK_CUR);
    		fseek(fp2,w*h/2,SEEK_CUR);
    
    	}
    
    	free(pic1);
    	free(pic2);
    	fclose(fp1);
    	fclose(fp2);
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_yuv420_psnr("lena_256x256_yuv420p.yuv","lena_distort_256x256_yuv420p.yuv",256,256,1);

    对于8bit量化的像素数据来说,PSNR的计算公式如下所示。

    上述公式中mse的计算公式如下所示。


    其中M,N分别为图像的宽高,xij和yij分别为两张图像的每一个像素值。PSNR通常用于质量评价,就是计算受损图像与原始图像之间的差别,以此来评价受损图像的质量。本程序输入的两张图像的对比图如下图所示。其中左边的图像为原始图像,右边的图像为受损图像。


    经过程序计算后得到的PSNR取值为26.693。PSNR取值通常情况下都在20-50的范围内,取值越高,代表两张图像越接近,反映出受损图像质量越好。

    (8) 分离RGB24像素数据中的R、G、B分量

    本程序中的函数可以将RGB24数据中的R、G、B三个分量分离开来并保存成三个文件。函数的代码如下所示。
    /**
     * Split R, G, B planes in RGB24 file.
     * @param url  Location of Input RGB file.
     * @param w    Width of Input RGB file.
     * @param h    Height of Input RGB file.
     * @param num  Number of frames to process.
     *
     */
    int simplest_rgb24_split(char *url, int w, int h,int num){
    	FILE *fp=fopen(url,"rb+");
    	FILE *fp1=fopen("output_r.y","wb+");
    	FILE *fp2=fopen("output_g.y","wb+");
    	FILE *fp3=fopen("output_b.y","wb+");
    
    	unsigned char *pic=(unsigned char *)malloc(w*h*3);
    
    	for(int i=0;i<num;i++){
    
    		fread(pic,1,w*h*3,fp);
    
    		for(int j=0;j<w*h*3;j=j+3){
    			//R
    			fwrite(pic+j,1,1,fp1);
    			//G
    			fwrite(pic+j+1,1,1,fp2);
    			//B
    			fwrite(pic+j+2,1,1,fp3);
    		}
    	}
    
    	free(pic);
    	fclose(fp);
    	fclose(fp1);
    	fclose(fp2);
    	fclose(fp3);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_rgb24_split("cie1931_500x500.rgb", 500, 500,1);

    从代码可以看出,与YUV420P三个分量分开存储不同,RGB24格式的每个像素的三个分量是连续存储的。一帧宽高分别为w、h的RGB24图像一共占用w*h*3 Byte的存储空间。RGB24格式规定首先存储第一个像素的R、G、B,然后存储第二个像素的R、G、B…以此类推。类似于YUV420P的存储方式称为Planar方式,而类似于RGB24的存储方式称为Packed方式。上述调用函数的代码运行后,将会把一张分辨率为500x500的名称为cie1931_500x500.rgb的RGB24格式的像素数据文件分离成为三个文件:

    output_r.y:R数据,分辨率为256x256。
    output_g.y:G数据,分辨率为256x256。

    output_b.y:B数据,分辨率为256x256。

    输入的原图是一张标准的CIE 1931色度图。该色度图右下为红色,上方为绿色,左下为蓝色,如下所示。


    R数据图像如下所示。


    G数据图像如下所示。


    B数据图像如下所示。



    (9)将RGB24格式像素数据封装为BMP图像

    BMP图像内部实际上存储的就是RGB数据。本程序实现了对RGB像素数据的封装处理。通过本程序中的函数,可以将RGB数据封装成为一张BMP图像。
    /**
     * Convert RGB24 file to BMP file
     * @param rgb24path    Location of input RGB file.
     * @param width        Width of input RGB file.
     * @param height       Height of input RGB file.
     * @param url_out      Location of Output BMP file.
     */
    int simplest_rgb24_to_bmp(const char *rgb24path,int width,int height,const char *bmppath){
    	typedef struct 
    	{  
    		long imageSize;
    		long blank;
    		long startPosition;
    	}BmpHead;
    
    	typedef struct
    	{
    		long  Length;
    		long  width;
    		long  height;
    		unsigned short  colorPlane;
    		unsigned short  bitColor;
    		long  zipFormat;
    		long  realSize;
    		long  xPels;
    		long  yPels;
    		long  colorUse;
    		long  colorImportant;
    	}InfoHead;
    
    	int i=0,j=0;
    	BmpHead m_BMPHeader={0};
    	InfoHead  m_BMPInfoHeader={0};
    	char bfType[2]={'B','M'};
    	int header_size=sizeof(bfType)+sizeof(BmpHead)+sizeof(InfoHead);
    	unsigned char *rgb24_buffer=NULL;
    	FILE *fp_rgb24=NULL,*fp_bmp=NULL;
    
    	if((fp_rgb24=fopen(rgb24path,"rb"))==NULL){
    		printf("Error: Cannot open input RGB24 file.\n");
    		return -1;
    	}
    	if((fp_bmp=fopen(bmppath,"wb"))==NULL){
    		printf("Error: Cannot open output BMP file.\n");
    		return -1;
    	}
    
    	rgb24_buffer=(unsigned char *)malloc(width*height*3);
    	fread(rgb24_buffer,1,width*height*3,fp_rgb24);
    
    	m_BMPHeader.imageSize=3*width*height+header_size;
    	m_BMPHeader.startPosition=header_size;
    
    	m_BMPInfoHeader.Length=sizeof(InfoHead); 
    	m_BMPInfoHeader.width=width;
    	//BMP storage pixel data in opposite direction of Y-axis (from bottom to top).
    	m_BMPInfoHeader.height=-height;
    	m_BMPInfoHeader.colorPlane=1;
    	m_BMPInfoHeader.bitColor=24;
    	m_BMPInfoHeader.realSize=3*width*height;
    
    	fwrite(bfType,1,sizeof(bfType),fp_bmp);
    	fwrite(&m_BMPHeader,1,sizeof(m_BMPHeader),fp_bmp);
    	fwrite(&m_BMPInfoHeader,1,sizeof(m_BMPInfoHeader),fp_bmp);
    
    	//BMP save R1|G1|B1,R2|G2|B2 as B1|G1|R1,B2|G2|R2
    	//It saves pixel data in Little Endian
    	//So we change 'R' and 'B'
    	for(j =0;j<height;j++){
    		for(i=0;i<width;i++){
    			char temp=rgb24_buffer[(j*width+i)*3+2];
    			rgb24_buffer[(j*width+i)*3+2]=rgb24_buffer[(j*width+i)*3+0];
    			rgb24_buffer[(j*width+i)*3+0]=temp;
    		}
    	}
    	fwrite(rgb24_buffer,3*width*height,1,fp_bmp);
    	fclose(fp_rgb24);
    	fclose(fp_bmp);
    	free(rgb24_buffer);
    	printf("Finish generate %s!\n",bmppath);
    	return 0;
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_rgb24_to_bmp("lena_256x256_rgb24.rgb",256,256,"output_lena.bmp");

    通过代码可以看出,改程序完成了主要完成了两个工作:
    1)将RGB数据前面加上文件头。
    2)将RGB数据中每个像素的“B”和“R”的位置互换。

    BMP文件是由BITMAPFILEHEADER、BITMAPINFOHEADER、RGB像素数据共3个部分构成,它的结构如下图所示。

    BITMAPFILEHEADER

    BITMAPINFOHEADER

    RGB像素数据


    其中前两部分的结构如下所示。在写入BMP文件头的时候给其中的每个字段赋上合适的值就可以了。
    typedef  struct  tagBITMAPFILEHEADER
    { 
    unsigned short int  bfType;       //位图文件的类型,必须为BM 
    unsigned long       bfSize;       //文件大小,以字节为单位
    unsigned short int  bfReserverd1; //位图文件保留字,必须为0 
    unsigned short int  bfReserverd2; //位图文件保留字,必须为0 
    unsigned long       bfbfOffBits;  //位图文件头到数据的偏移量,以字节为单位
    }BITMAPFILEHEADER; 
    typedef  struct  tagBITMAPINFOHEADER 
    { 
    long biSize;                        //该结构大小,字节为单位
    long  biWidth;                     //图形宽度以象素为单位
    long  biHeight;                     //图形高度以象素为单位
    short int  biPlanes;               //目标设备的级别,必须为1 
    short int  biBitcount;             //颜色深度,每个象素所需要的位数
    short int  biCompression;        //位图的压缩类型
    long  biSizeImage;              //位图的大小,以字节为单位
    long  biXPelsPermeter;       //位图水平分辨率,每米像素数
    long  biYPelsPermeter;       //位图垂直分辨率,每米像素数
    long  biClrUsed;            //位图实际使用的颜色表中的颜色数
    long  biClrImportant;       //位图显示过程中重要的颜色数
    }BITMAPINFOHEADER;
    

    BMP采用的是小端(Little Endian)存储方式。这种存储方式中“RGB24”格式的像素的分量存储的先后顺序为B、G、R。由于RGB24格式存储的顺序是R、G、B,所以需要将“R”和“B”顺序作一个调换再进行存储。

    下图为输入的RGB24格式的图像lena_256x256_rgb24.rgb。


    下图分封装为BMP格式后的图像output_lena.bmp。封装后的图像使用普通的看图软件就可以查看。



    (10)将RGB24格式像素数据转换为YUV420P格式像素数据

    本程序中的函数可以将RGB24格式的像素数据转换为YUV420P格式的像素数据。函数的代码如下所示。
    unsigned char clip_value(unsigned char x,unsigned char min_val,unsigned char  max_val){
    	if(x>max_val){
    		return max_val;
    	}else if(x<min_val){
    		return min_val;
    	}else{
    		return x;
    	}
    }
    
    //RGB to YUV420
    bool RGB24_TO_YUV420(unsigned char *RgbBuf,int w,int h,unsigned char *yuvBuf)
    {
    	unsigned char*ptrY, *ptrU, *ptrV, *ptrRGB;
    	memset(yuvBuf,0,w*h*3/2);
    	ptrY = yuvBuf;
    	ptrU = yuvBuf + w*h;
    	ptrV = ptrU + (w*h*1/4);
    	unsigned char y, u, v, r, g, b;
    	for (int j = 0; j<h;j++){
    		ptrRGB = RgbBuf + w*j*3 ;
    		for (int i = 0;i<w;i++){
    			
    			r = *(ptrRGB++);
    			g = *(ptrRGB++);
    			b = *(ptrRGB++);
    			y = (unsigned char)( ( 66 * r + 129 * g +  25 * b + 128) >> 8) + 16  ;          
    			u = (unsigned char)( ( -38 * r -  74 * g + 112 * b + 128) >> 8) + 128 ;          
    			v = (unsigned char)( ( 112 * r -  94 * g -  18 * b + 128) >> 8) + 128 ;
    			*(ptrY++) = clip_value(y,0,255);
    			if (j%2==0&&i%2 ==0){
    				*(ptrU++) =clip_value(u,0,255);
    			}
    			else{
    				if (i%2==0){
    				*(ptrV++) =clip_value(v,0,255);
    				}
    			}
    		}
    	}
    	return true;
    }
    
    /**
     * Convert RGB24 file to YUV420P file
     * @param url_in  Location of Input RGB file.
     * @param w       Width of Input RGB file.
     * @param h       Height of Input RGB file.
     * @param num     Number of frames to process.
     * @param url_out Location of Output YUV file.
     */
    int simplest_rgb24_to_yuv420(char *url_in, int w, int h,int num,char *url_out){
    	FILE *fp=fopen(url_in,"rb+");
    	FILE *fp1=fopen(url_out,"wb+");
    
    	unsigned char *pic_rgb24=(unsigned char *)malloc(w*h*3);
    	unsigned char *pic_yuv420=(unsigned char *)malloc(w*h*3/2);
    
    	for(int i=0;i<num;i++){
    		fread(pic_rgb24,1,w*h*3,fp);
    		RGB24_TO_YUV420(pic_rgb24,w,h,pic_yuv420);
    		fwrite(pic_yuv420,1,w*h*3/2,fp1);
    	}
    
    	free(pic_rgb24);
    	free(pic_yuv420);
    	fclose(fp);
    	fclose(fp1);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_rgb24_to_yuv420("lena_256x256_rgb24.rgb",256,256,1,"output_lena.yuv");

    从源代码可以看出,本程序实现了RGB到YUV的转换公式:

    Y= 0.299*R+0.587*G+0.114*B

    U=-0.147*R-0.289*G+0.463*B

    V= 0.615*R-0.515*G-0.100*B

    在转换的过程中有以下几点需要注意:
    1) RGB24存储方式是Packed,YUV420P存储方式是Packed。
    2) U,V在水平和垂直方向的取样数是Y的一半

    转换前的RGB24格式像素数据lena_256x256_rgb24.rgb的内容如下所示。


    转换后的YUV420P格式的像素数据output_lena.yuv的内容如下所示。



    (11)生成RGB24格式的彩条测试图

    本程序中的函数可以生成一张RGB24格式的彩条测试图。函数代码如下所示。
    /**
     * Generate RGB24 colorbar.
     * @param width    Width of Output RGB file.
     * @param height   Height of Output RGB file.
     * @param url_out  Location of Output RGB file.
     */
    int simplest_rgb24_colorbar(int width, int height,char *url_out){
    
    	unsigned char *data=NULL;
    	int barwidth;
    	char filename[100]={0};
    	FILE *fp=NULL;
    	int i=0,j=0;
    
    	data=(unsigned char *)malloc(width*height*3);
    	barwidth=width/8;
    
    	if((fp=fopen(url_out,"wb+"))==NULL){
    		printf("Error: Cannot create file!");
    		return -1;
    	}
    
    	for(j=0;j<height;j++){
    		for(i=0;i<width;i++){
    			int barnum=i/barwidth;
    			switch(barnum){
    			case 0:{
    				data[(j*width+i)*3+0]=255;
    				data[(j*width+i)*3+1]=255;
    				data[(j*width+i)*3+2]=255;
    				break;
    				   }
    			case 1:{
    				data[(j*width+i)*3+0]=255;
    				data[(j*width+i)*3+1]=255;
    				data[(j*width+i)*3+2]=0;
    				break;
    				   }
    			case 2:{
    				data[(j*width+i)*3+0]=0;
    				data[(j*width+i)*3+1]=255;
    				data[(j*width+i)*3+2]=255;
    				break;
    				   }
    			case 3:{
    				data[(j*width+i)*3+0]=0;
    				data[(j*width+i)*3+1]=255;
    				data[(j*width+i)*3+2]=0;
    				break;
    				   }
    			case 4:{
    				data[(j*width+i)*3+0]=255;
    				data[(j*width+i)*3+1]=0;
    				data[(j*width+i)*3+2]=255;
    				break;
    				   }
    			case 5:{
    				data[(j*width+i)*3+0]=255;
    				data[(j*width+i)*3+1]=0;
    				data[(j*width+i)*3+2]=0;
    				break;
    				   }
    			case 6:{
    				data[(j*width+i)*3+0]=0;
    				data[(j*width+i)*3+1]=0;
    				data[(j*width+i)*3+2]=255;
    
    				break;
    				   }
    			case 7:{
    				data[(j*width+i)*3+0]=0;
    				data[(j*width+i)*3+1]=0;
    				data[(j*width+i)*3+2]=0;
    				break;
    				   }
    			}
    
    		}
    	}
    	fwrite(data,width*height*3,1,fp);
    	fclose(fp);
    	free(data);
    
    	return 0;
    }
    

    调用上面函数的方法如下所示。
    simplest_rgb24_colorbar(640, 360,"colorbar_640x360.rgb");

    从源代码可以看出,本程序循环输出“白黄青绿品红蓝黑”8种颜色的彩条。这8种颜色的彩条的R、G、B取值如下所示。

    颜色

    (R, G, B)

    (255, 255, 255)

    (255, 255,   0)

    (  0, 255, 255)

    绿

    (  0, 255,   0)

    (255,   0, 255)

    (255,   0,   0)

    (  0,   0, 255)

    (  0,   0,   0)


    生成的图像截图如下所示。
     


    下载


    Simplest mediadata test


    项目主页

    SourceForge:https://sourceforge.net/projects/simplest-mediadata-test/

    Github:https://github.com/leixiaohua1020/simplest_mediadata_test

    开源中国:http://git.oschina.net/leixiaohua1020/simplest_mediadata_test


    CSDN下载地址:http://download.csdn.net/detail/leixiaohua1020/9422409

    本项目包含如下几种视音频数据解析示例:
     (1)像素数据处理程序。包含RGB和YUV像素格式处理的函数。
     (2)音频采样数据处理程序。包含PCM音频采样格式处理的函数。
     (3)H.264码流分析程序。可以分离并解析NALU。
     (4)AAC码流分析程序。可以分离并解析ADTS帧。
     (5)FLV封装格式分析程序。可以将FLV中的MP3音频码流分离出来。

     (6)UDP-RTP协议分析程序。可以将分析UDP/RTP/MPEG-TS数据包。



    雷霄骅 (Lei Xiaohua)
    leixiaohua1020@126.com
    http://blog.csdn.net/leixiaohua1020



    展开全文
  • YUV介绍

    千次阅读 2018-09-05 09:40:45
    YUV表示的含义 人们常用RGB表示三基色,而且RGB也可以表示出所有颜色。但视觉心理学研究表明,人眼主要是对光的感知,人的视觉系统对光的感知程度用亮度(luminance)和色度(chrominance)两个属性表示,也就是...

    YUV表示的含义
    人们常用RGB表示三基色,而且RGB也可以表示出所有颜色。但视觉心理学研究表明,人眼主要是对光的感知,人的视觉系统对光的感知程度用亮度(luminance)和色度(chrominance)两个属性表示,也就是我们常说的YUV。Y就是亮度感知,而色度感知分为两个属性:色相(hue)和色饱和度(saturation)。色相也就是U,是由光波的峰值定义的,描述的是光的颜色;色饱和度V是光波的谱宽定义的,描述的是光的纯度。
    采用YUV色度空间比采用RGB颜色空间更利于视频的压缩,也能更有效的表示彩色视频图像。
    YUV和RGB的转换
    YUV和GBD之间的转换关系是(ITU=T, 1995):
    这里写图片描述
    需注意的是对于不同标准,YUV和RGB之间的转换有不同之处。
    YUV采样
    我们常用的采样比率分为三种。分别是4:4:4、4:2:2、4:2:0。

    4:2:0格式是色度水平和垂直方向都是亮度的一半。
    4:2:0

    4:4:4格式是色度和亮度在水平和垂直方向都是一样的。
    4:4:4

    4:2:2格式是色度水平方向上是亮度的一半,垂直方向相同。
    4:2:2

    展开全文
  • YUV格式详解

    千次阅读 2018-11-13 21:49:58
    1、什么是YUVYUV是指亮度参量和色度参量分开表示的像素格式,其中“Y”表示明亮度(Luminance或Luma),也就是灰度值;而“U”和“V”表示的则是色度(Chrominance或Chroma),作用是描述影像色彩及饱和度,用于...
  • YUV格式分析详解

    万次阅读 2013-10-28 16:32:35
    YUV格式分析详解     一,YUV含义   YUV格式通常有两大类:打包(packed)格式和平面(planar)格式。前者将YUV分量存放在同一个数组中,通常是几个相邻的像素组成一个宏像素(macro-pixel);而后者使用三个数组...
  • YUV格式有两大类:planar和packed。 对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。 对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。   YUV,分为...
  • YUV

    2019-04-26 09:09:00
    YUV也叫YCbCr,Y表示明亮度(Luminance、Luma),U和V则是色度、浓度(Chrominance、Chroma)。Y、U和V三个分量的数据分别保存在三个Plane类中,可以通过getPlanes()得到。Plane实际是对ByteBuffer的封装。Image保证...
  • YUV - 简介

    2017-07-16 16:08:22
    YUV格式解析1播放器project2YUV 采样表面定义 YUV格式解析2 转载自:http://blog.sina.com.cn/s/blog_693301190100xtbi.html YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免...
  • 理解YUV

    千次阅读 2018-12-05 18:59:28
    YUV是一种颜色空间,基于YUV的颜色编码是流媒体的常用编码方式。Y表示流明,U、V表示色度、浓度,这种表达方式起初是为了彩色电视与黑白电视之间的信号兼容。 对于图像每一点,Y确定其亮度,UV确认其彩度。 Y’CbCr...
  • YUVRGB格式转换

    万次阅读 2017-12-24 11:13:12
    YUVRGB格式转换 转载 2015年11月26日 12:24:43 标签:
  • Opengl ES中YUV420转RGB

    千次阅读 2017-05-22 10:50:49
    Opengl ES中YUV420转RGB一、先了解一个概念“灰度图”1、灰度图的定义:把白色与黑色之间按对数关系分为若干等级,称为灰度。灰度分为256阶。2、举例:老式黑白电视机的图像,即灰度图像3、灰度值与RGB的计算公式:Y ...
  • YUVRGB的相互转换实验

    千次阅读 2019-08-25 22:57:08
    对于RGBYUV的过程,我们要首先拿到RGB文件的数据,再通过上图的YUV计算公式对其做运算,得到YUV数据,从而实现转换。而对于YUVRGB则要首先获得YUV数据,用第二组RGB公式计算得到RGB数据。在本实验中,转换公式...
  • RGBYUV

    千次阅读 2015-09-02 17:39:02
    YUV格式有两大类:planar和packed。 对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。 对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。   YUV,分为三...
  • YUV420转RGB

    千次阅读 2018-05-16 11:10:04
    一、YUV420数据存储 YUV格式有两大类:planar和packed。对于planar的YUV格式,先连续存储所有像素点的Y,紧接着存储所有像素点的U,随后是所有像素点的V。对于packed的YUV格式,每个像素点的Y,U,V是连续交*存储的。...
  • FFMPEG中的swscale提供了视频原始数据(YUV420,YUV422,YUV444,RGB24...)之间的转换,分辨率变换等操作,使用起来十分方便,在这里记录一下它的用法。 swscale主要用于在2个AVFrame之间进行转换。 下面来看一个...
  • YUV420和RGB转换存储为BMP和JPG以及PNG图片
  • YUV422 YUV420 RGB24相互转换

    千次阅读 2014-08-20 14:18:23
    直接上可用的代码
  • YUV2RGB Opencv

    万次阅读 2017-04-20 21:04:38
    YUV2RGB OpenCV(C/C++/Python)参考:百度百科:YUV 维基百科:YUV YUV Colorspace:http://softpixel.com/~cwright/programming/colorspace/yuv/ YUV420P格式分析:...
  • YUVRGB快速算法

    千次阅读 2015-01-29 10:16:36
     转自 ... 1 前言  自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用 的过程,所以在不同的应用领域中...
  • YUV420P转RGB32

    2017-10-27 20:51:16
    上一节讲解了YUV420P格式的内容。 我说过,我们不是为了做研究。 平白无故讲了YUV420P的理论知识,要是不做点什么总说不过去吧。 那么,我们就练练刀,写个...之前做播放器的时候,是将YUV420P转换成RGB32,然后放到QI
  • rawRGB 图像采集的过程为:光照在成像物体被反射 -> 镜头汇聚 -> Sensor光电转换-> ADC转换为rawRGB 因为sensor上每个像素只采集特定颜色的光的强度,因此sensor每个像素只能为R或G或B,形成的数据就...
  • RGB & YUV

    2019-05-06 21:13:30
    RGB颜色空间 R、G、B三个分量,每个分量各占8位即一个字节,三个分量总共是3个字节,即24bit,三个分量可以组合出不同的颜色,即2^24 种 每个RGB分量其实都是表示成亮度,当三个相同时,就退化成我们所说的灰度图了...
  • YUV格式详解及 YUVRGB转换

    千次阅读 2013-10-24 15:36:24
    转自:... Microsoft Digital Media Division 适用于: Microsoft® Windows®, Microsoft DirectShow® 摘要:本文讲述了在 Microsoft Windows 操作系统中呈现视频时推荐使用的 8 位 YU
  • RGBYUV420

    千次阅读 2016-02-03 17:02:17
    转载自:http://blog.csdn.net/frankiewang008/article/details/6854616 RGB TO YUV转换原理及代码示例   RGB TO YUV转换原理及代码示例 YUV 与 YIQ YcrCb  对于YUV模型,实际上很多时候,我们是把它和YI
  • YUVRGB编码

    千次阅读 2019-08-29 21:54:52
    文章目录一、编码介绍1.1 RGB 颜色编码1.2 YUV 颜色编码二、RGBYUV 的互相转换三、采样3.1 YUV 采样格式3.1 YUV 4:4:4 采样3.2 YUV 4:2:2 采样3.3 YUV 4:2:0 采样四、YUV 存储格式4.1 基于 YUV 4:2:2 采样的格式...
  • RGB YUV 转换工具

    热门讨论 2012-02-21 21:22:17
    提供一种RGBYUV值的转换工具,可很方便直观的查阅这这两者的对应关系,在需要查找这两种数值对比的用户会很好用。
  • 常用YUVRGB代码

    万次阅读 多人点赞 2013-12-15 15:10:12
    常用YUVRGB java代码 public class YuvToRGB { private static int R = 0; private static int G = 1; private static int B = 2; //I420是yuv420格式,是3个plane,排列方式为(Y)(U)(V) public static ...
  • Unity 工具之 YUVYUV420 :I420,YV12,NV12,NV21)使用 shader 转为 RGB 显示 封装 YUV420ToRGBWrapper 1、首先根据 YUV 对应格式的 YUV 的排列方式,拆分 YUV; 2、然后,在通过 YUVRGB 转换对应公式,进行...
  • BMP 转 RGB YUV 工具

    热门讨论 2010-07-30 20:17:18
    RGB32 RGB24 RGB16 GRAY RGB4444 RGB5551 YUV422 YUV444COM YUV444SEP YUV420 Y_UV22 Y_UV20 YUV422SEP 等格式的二进制文件 是制作UI和测试LCDC的好工具 Y_UV20 为simi planar 即YUV420格式,Y单独放,UV packed...

空空如也

1 2 3 4 5 ... 20
收藏数 410,501
精华内容 164,200
关键字:

yuv