Android中的图像格式
一、前言
在音视频开发过程中,熟悉图像格式(图像编码)是十分有帮助的。这属于音视频开发者的基本功,就像计算机组成原理、数据结构之于普通程序员。
本文主要面向在Android平台进行音视频开发的人员。当然,如果您是iOS、嵌入式设备或者其他平台的音视频开发者,本文也能起到一定的参考借鉴作用。
二、背景知识
2.1 图像编码和存储
我们所看到的图像,实际是光经过反射而来。根据光学理论,各种颜色的光是由红(R)、绿(G)、蓝(B)以不同的比例组成。我们知道,计算机世界是数字的、抽象的,那它是如何来描述一张图像,或者再具体点,如何描述一个像素的呢?
以RGB颜色模型为例,我们可以用分别占1字节大小的R、G、B组合起来描述一种颜色,这样一个像素需要花3字节的空间来存储;我们也可以用2字节大小的R、G、B来描述一种颜色,这样一个像素需要6字节存储。显然,不难推断:描述R、G、B用的比特位越多,所能描述的颜色也就越多,存储空间占用的也就越多。
考虑到实际的需求与资源限制,通常需要做trade-off,即找到一个平衡点。这就诞生了形形色色的编码、采样、存储方式。

这里本文以问答形式,对本文即将用的一些知识点作简单介绍,其余部分不作深入。感兴趣的读者可以与笔者交流或自行搜索资料。
Q:YUV和YCbCr是什么关系?
A:
Q:注意到部分YUV格式有后缀,比如YUV_420_888、YUV_422_888、YUV_444_888,它们有什么不同呢?
A:
:每四个像素点,共用4个Y分量、1个U分量、1个V分量表示。
:每四个像素点,共用4个Y分量、2个U分量、2个V分量表示。
:每四个像素点,共用4个Y分量、4个U分量、4个V分量表示。
注意到,其实只有UV分量的

Q:听说过planar、packed,semi-planar,这些又是什么?有什么不同。
A:这些是
planar:就是把整张图像的单个分量各自存储在一个数组中,每组分量紧挨在一起。
packed:就是把一个像素的Y、U、V分量“打包”放在一个数组,然后一个像素一个像素挨着存储。
semi-planar:是前两者的混合,一部分分量用planar方式存储,另一部分分量用packed分量存储。

2.2 图像传感器(Image Sensor)
图像传感器上分布了大量的感光单元,将接收到的光信号转换为电信号。众多感光单元一起,组成了色彩滤波阵列(Color Filter Array,简称)。
常见的感光单元可分为两大类:能够同时输出RGB三个分量的RGB感光单元、只能输出单个分量的感光单元。我们当然希望用前者作为Image Sensor的主材料,但遗憾的是,前者成本高,工艺复杂,所以在实际的市场上,后者流通更为主流。
如果一个像素点只能输出一种颜色的信息,那我们怎么做才能还原出完成的图像呢?比较容易想到的是邻近差值策略,即一个像素点输出一种颜色分量信息,它附近的其他像素点输出其他分量的信息,再将这些信息以某种策略汇合,从而得到某一点“完整”的所有分量信息。
这里比较出名的是拜耳滤波阵列(Bayer Filter),它的CFA排列如下:

这种CFA以nxn个像素矩阵为一个单元,每个单元由
为什么绿色占的比重高?这源自一个理论:人眼对绿色更敏感。具体原因还请自行查找相关资料。
比较常见的是以2x2像素矩阵为一个单元,即RGGB,也叫BGGR、RGBG、GRBG,它们指的是同一个东西的不同表现。
关于CFA,还有两个概念感兴趣的读者可以搜索下:QuadCFA和九合一CFA。(见参考资料2、3)
2.3 Android图像格式的两个类
Android上,表示图像格式的,主要有两个类:和。它们都位于包内,有一些重叠之处,前者用的更多一些,后者中的许多值已经被为废弃(Deprecated)。本文主要介绍中的图像格式。
下面将会大致按类别和使用频率介绍主要图像编码格式,每个格式尽可能的会用图来展示它的存储方式。
三、Android中的图像格式之
个人习惯将格式划分为:Raw、Yuv和其他格式(Jpeg、PNG等),这三大类。前两者主要用于图像传输与算法处理,后者更多用作呈现。
3.1 YUV
3.1.1
是

是
3.1.2
类似于,却别在于

3.1.3
是
值得注意的是,不同的安卓机器上,大概率会存在字节对齐现象,这点在处理时尤其要注意。
stride信息可以通过和获取到。
和和它类似,却别在于
3.1.4
是

3.2 Raw
3.2.1
的
这里的紧密排列注意一下。所谓紧密,是指像素与像素之间没有多余的元素。我们知道,计算机是以字节为基本存储单位,而每个像素又是10bit的,故而它是
前4字节 存储了每个像素的高8位 信息。第5个字节 存储了这四个像素的低2位 信息。
所以实际上是下面这样排列:

3.2.2
与类似,区别在于它的每个像素以
3个字节 存储2个像素 的信息。前两个字节 存储了每个像素的高8位 。第3个字节 存储了每个像素的低4位 。

3.2.3
跟Sensor密切相关,一般不会拿来使用(除了手机厂商或和手机厂商有相关合作),如果确实需要使用,则需要通过拿到相关属性后才能正确解析数据。操作十分复杂,且不具有通用性,不推荐使用。
格式的每个像素需要用
3.3 Others
3.3.1
是私有格式,和平台实现有关,
Camera API2的预览格式一般默认就是这种。
像高通会将这个实现为他们的私有格式,有的手机厂商出于某些目的和需求,又会将它的实现改为或者。
总而言之,对音视频开发人员来说,需要记住:
3.3.2
类似与,也是一种私有格式,厂商可能会用到,一般应用开发者用不到这个。
注意区别于,前者是无法通过现有公共API接口获取到的数据,去解析数据的一种格式;而后者,则是可以通过framework API拿到相关信息,进而做解析的一种图像格式。
四、结束语
各式各样的图像格式是进行图像处理所避不开的一道关卡,有时碰到的一些玄学问题可能正是因为其中的一两个大意导致的,例如未考虑某些格式的内存对齐导致图像显示异常。
当我们熟稔常见格式的特点后,后期进行编码设计时,遇到的问题、代码中留的隐患会更少。能够熟练、详尽地描述出各个格式的采样方式、存储方式、应用场景等特点,应是身为音视频开发者的一个基本功。
参考资料: