Android中常用图像格式说明

4,075 阅读9分钟

前言RGB565RGB24ARGB_8888I420 和 NV21灰阶值是什么?既然都是YUV420格式的,I420 和 NV21 到底有何区别?总结参考资料

前言

此篇文章针对 Android 中图像处理工具 ImageUtils 的解释篇,有兴趣的童鞋可以 点击此处 了解这款开源工具。

针对图像,存在各种各样的格式,每个格式都不一样,而在Android中,常用的图像格式无外乎也就几种,下面就Android中常用的图像格式做相关说明。

RGB565

Android中自带的一种图像格式,这个图像格式像素排布如下图:

image
image

RGB565 每个像素点都有红、绿、蓝三个原色,其中 R 原色占用 5 bitG 原色占用 6 bitB 原色占用 5 bit,也就是说一个像素点总占用 5 + 6 + 5 = 16 bit

一张 640 * 480 分辨率的 RGB565 图像,其占用的内存大小为:640 * 480 * 16 / 8 = 614400 byte

通常在处理一个图像数据时会涉及到步长,步长计算一般为下面的公式:

步长 = 图像的宽 * 每个像素点总 bit 数 / 8

因此,对于 640 * 480RGB565 图像而言,其步长为:640 * 16 / 8 = 1280


RGB24

image
image

如上图,RGB24 其真正的排序是 BGR BGR ... 这种排序的,而并非 RGB RGB ... 这种排序。

同样的,RGB24 每个像素点都有蓝、红、绿三个原色 BGR 三个原色各占用 8 bit,也就是说一个像素点总占用 24 bit

一张 640 * 480 分辨率的 RGB24 图像,其占用的内存大小为:640 * 480 * 24 / 8 = 921600 byte

同样的,对于 640 * 480RGB24 图像而言,其步长为:640 * 24 / 8 = 1920


ARGB_8888

image
image

如上图,ARGB_8888 作为在Android中我们最常用的一种图像格式,其实其真正的图像格式为 RGBA

ARGB_8888 除了包含 RGB 常用的三原色以外,还包含一个透明度 Alpha,而且一个像素点中的每个通道各占 8 bit,一个像素点总计: 8 * 4 = 32 bit

也就是说,对于一张 640 * 480 分辨率的 ARGB_8888 图像,其占用的内存大小为:640 * 480 * 32 / 8 = 1228800 byte
而其对应的步长为:640 * 32 / 8 = 2560


I420 和 NV21

I420NV21 都是属于 YUV 格式的数据。

所谓的 YUV 格式指的是图像的颜色编码采用的是 明亮度 和 色度来指定像素的颜色,而不是通常使用的三原色来指定。
例如下图:

YUV444
YUV444

上图是一个 YUV444 的图像格式。

  • Y 代表明亮度,也即灰阶值
  • UV 代表色度,是描述影像色彩及饱和度,用于指定像素的颜色
  • 关于 YUVRGB 是如何互相转换的,您可以 参见这里

灰阶值是什么?

R = B = G 时候,像素点的颜色就呈现黑白色调,这种像素点拼接起来的图像呈现为灰度图,R = B = G 的通道值就是灰阶。


通常情况下彩色像素点转灰阶值一般采用大致于 R:G:B=3:6:1 的算法计算灰阶值,实际上 RGB 转换成 YUV 时,Y 分量的计算公式为:

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



RGB 比例基本与 3 : 6 : 1 吻合【具体的可 点击参考此处 】。

继续说回 YUV,针对 YUV444 这种格式,其采样比例为 Y : U : V = 4 : 4 : 4 ,也即 1 : 1 : 1

例如上图,其采样流是这样的:


Y1 U1 V1 Y2 U2 V2 Y3 U3 V3 Y4 U4 V4 Y5 U5 V5 ...

也就是说采样时候每个像素的 Y U V 三个分量都是完整的,而在一个像素点中,一个完整的分量占用 8 bit 大小,
因此针对一个 640 * 480 大小的 YUV444 的图像,其真实的占用大小为:

640 * 480 * 8 * 3 = 921600 bit

RGB24 占用的大小是一致的;同样的针对 YUV444,其图像的步长一样跟 RGB24 一样,为 640 * 3 = 1920

针对这种完全采样的 YUV 格式,并没有给图像进行压缩,因此业界也很少使用 YUV444 这种格式对图像进程存储。

实际上,目前使用最多的 YUV 图像采集格式主要包含 YUV422YUV420 这两种采集方式,而 I420NV21 恰好是这种数据采集方式,YUV420 数据采集大概是下面这种方式:

YUV420
YUV420

针对 YUV420 这种采用方式,有以下几个特点:

  • 每个像素的 Y 分量必须采集
  • 采集时,每一行只扫描一种分量【或 UV】,而且采样比例为 Y : U【V】 = 2 : 1
  • 因为存在隔行采样,存在上下行像素的共用情况,因此,一般而言此类格式的图像宽和高值均为偶数

如上图,你会发现,每个像素原本均包含 Y U V三个分量,而在进行 YUV420 采样的时候,每个 Y 分量都进行了采集,而 UV 分量并非每一行都采集,而是先采集一行 U 分量在采集一行 V 分量,而且是每隔一个像素点采集一次的。上图第一行 对 Y 分量都采集了,而 U 分量只采集了 Y 分量的一半,V 分量没有采集;到第二行,Y 分量还是全部采集,此时 V 分量采集了,采集的数量是 Y 分量的一半,U 分量未采集。

也就是说其采样流是这样的:


Y1 U1 Y2 Y3 U3 Y4 Y5 V5 Y6 Y7 V7 Y8 Y9 U9 Y10 Y11 U11 Y12 Y13 V13 Y14 Y15 V15 Y16

同时映射成的像素点如上图蓝色虚线框中的方式进行映射,也即下面这种:

[Y1 U1 V5]    [Y2 U1 V5]     [Y3 U3 V7]      [Y4 U3 V7]

[Y5 U1 V5]    [Y6 U1 V5]     [Y7 U3 V7]      [Y8 U3 V7]

[Y9 U9 V13]  [Y10 U9 V13]  [Y11 U11 V15] [Y12 U11 V15]

[Y13 U9 V13] [Y14 U9 V13]  [Y15 U11 V15] [Y16 U11 V15]

针对 YUV420 这种采样的图像,你会发现这种方式对图片做了一定的压缩,我们可以根据上面的方式计算,

对于一个 640 * 480 大小的图像,其占用的内存为:

Y 分量:640 * 480 * 8 = 2457600 bit

UV 分量总占用为 :640 * 480 * 0.5 * 8 = 1228800 bit

因此总占用内存大小为:640 * 480 * 8 + 640 * 480 * 0.5 * 8 = 3686400 bit = 460800 byte

同时可以计算出对于的 YUV420 格式的大小为 640 * 480 图像的步长为:640 + 0.5 * 640 = 960

既然都是YUV420格式的,I420 和 NV21 到底有何区别?

针对基于 YUV 4:2:0 采样的格式,主要分为两种类型:

  • YUV420P
    • YU12,即I420
    • YV12
  • YUV420SP
    • NV12
    • NV21

也就是说 I420 是属于 YUV420P 这种类型的,这种类型的格式存储有以下特点:

  • 都是基于 Planar模式【平面模式】进行存储的
  • 在存储时,先存储所有的 Y 分量,然后在存储 UV 分量
  • 如果先存储的是 U 分量,再存储的是 V 分量,则这种格式即 YU12 格式,即我们所说的 I420 格式
  • 如果先存储的是 V 分量,再存储的是 U 分量,则这种格式即 YV12 格式

如下图,即为 一个分辨率为 8 * 4I420图像的存储格式图:

I420
I420

我们可以把这种存储方式理解成三层,其中第一层固定存储 Y 分量,第二和第三层根据实际格式分别存储 UV(或 VU

同样的,对应的 NV21 图像格式,它是属于 YUV420SP 这种类型的,此类型的存储格式有以下特点:

  • 同样都是属于Planar模式【平面模式】进行存储的,而严格上来说,是属于 biplanar 模式【双平面模式】
  • 在存储时,先存储所有的 Y 分量,然后再将 U V 两个分量交替连续存储
  • 如果以 UV 的循序交替存储时,则为 NV12 格式
  • 如果以 VU 的循序交替存储时,则为 NV21 格式

下图为一个分辨率为 8 * 4NV21 格式图像存储图:

NV21
NV21

至此,关于 I420NV21 这两种图像格式就介绍完了,有关更多的关于 YUV 的其他格式,可点击 此处 进行了解。

总结

  • 图像所占内存大小跟图像的实际格式及其相关
  • 每个格式的图像都有自己对应的步长【或步幅】值,从在存储器一行像素在存储器像素的下一行的字节数
  • RGB_565 格式图像步幅为:宽 * 2
  • RGB24 格式图像步幅为:宽 * 3
  • ARGB_8888 格式图像步幅为:宽 * 4
  • I420NV21 格式图像步幅为: 宽 * 1.5
  • 图像在内存中所占用的字节大小,通常为 图像的高 * 步长
  • 对于 I420NV21 两种格式的图像,因涉及到隔行采样,上下行像素共用问题,一般此类图像的宽和高均为偶数

参考资料