博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android: Image类浅析(结合YUV_420_888)
阅读量:2384 次
发布时间:2019-05-10

本文共 3757 字,大约阅读时间需要 12 分钟。

简介

Image类在API 19中引入,但真正开始发挥作用还是在API 21引入CameraDeviceMediaCodec的增强后。API 21引入了Camera2,deprecated掉了Camera,确立Image作为相机得到的原始帧数据的载体;硬件编解码的MediaCodec类加入了对ImageImage的封装ImageReader的全面支持。可以预见,Image将会用来统一Android内部混乱的中间图片数据(这里中间图片数据指如各式YUV格式数据,在处理过程中产生和销毁)管理。

本文主要介绍YUV_420_888格式的图片数据如何在Image中存储和管理。

从YUV420谈起

YUV即通过Y、U和V三个分量表示颜色空间,其中Y表示亮度,U和V表示色度。不同于RGB中每个像素点都有独立的R、G和B三个颜色分量值,YUV根据U和V采样数目的不同,分为如YUV444、YUV422和YUV420等,而YUV420表示的就是每个像素点有一个独立的亮度表示,即Y分量;而色度,即U和V分量则由每4个像素点共享一个。举例来说,对于4x4的图片,在YUV420下,有16个Y值,4个U值和4个V值。

YUV420根据颜色数据的存储顺序不同,又分为了多种不同的格式,如YUV420Planar、YUV420PackedPlanar、YUV420SemiPlanar和YUV420PackedSemiPlanar,这些格式实际存储的信息还是完全一致的。举例来说,对于4x4的图片,在YUV420下,任何格式都有16个Y值,4个U值和4个V值,不同格式只是Y、U和V的排列顺序变化。I420(YUV420Planar的一种)则为YYYYYYYYYYYYYYYYUUUUVVVV,NV21(YUV420SemiPlanar)则为YYYYYYYYYYYYYYYYUVUVUVUV。也就是说,YUV420是一类格式的集合,YUV420并不能完全确定颜色数据的存储顺序。

Image

这么多眼花缭乱的格式名字自然是不利于程序开发的,Image就这样横空出世了。

长和宽

对于YUV来说图片的宽和高是必不可少的,因为YUV本身只存储颜色信息,想要还原出图片,必须知道图片的长宽。Image保存有图片的宽和高,可以通过getWidth()getHeight()得到。

图片格式

每个Image当然有自己的格式,这个格式由ImageFormat确定。对于YUV420,ImageFormat在API 21中新加入了YUV_420_888类型,其表示YUV420格式的集合,888表示Y、U、V分量中每个颜色占8bit。既然只能指定YUV420这个格式集合,那怎么知道具体的格式呢?马上就来回答这个问题。

YUV分量

Y、U和V三个分量的数据分别保存在三个Plane类中,可以通过getPlanes()得到。Plane实际是对ByteBuffer的封装。Image保证了plane #0一定是Y,#1一定是U,#2一定是V。且对于plane #0,Y分量数据一定是连续存储的,中间不会有U或V数据穿插,也就是说我们一定能够一次性得到所有Y分量的值。

接下来看看U和V分量,我们考虑其中的三类格式:Planar,SemiPlanar和PackedSemiPlanar。

Planar

Planar下U和V分量是分开存放的,所以我们也应当能够一次性从plane #1和plane #2中获得所有的U和V分量值,事实也是如此。

下面是一段YUV420Planar格式Image解析的记录

image format: 35get data from 3 planespixelStride 1rowStride 1920width 1920height 1080buffer size 2088960Finished reading data from plane 0pixelStride 1rowStride 960width 1920height 1080buffer size 522240Finished reading data from plane 1pixelStride 1rowStride 960width 1920height 1080buffer size 522240Finished reading data from plane 2

Image中获得的图片格式是35,即YUV_420_888,一共有3个planes,图片分辨率为1920x1080,像素点个数为2073600;可以看到Y分量包含有全部的像素点,而U和V都只含有1/4的像素点,显然是YUV420。更为明显的是,Y分量中rowStride为1920,pixelStride代表行内颜色值间隔,取1表示无间隔,即对于一行1920个像素点每个都有独立的值,根据其buffer size可以得出共有1080行;而U分量中,一行1920个像素点只有960个值,即行内每两个像素点共用一个U值,根据其buffer size得出共有540行,即行间每两个像素点共用一个U值;这就是YUV420的采样了。

SemiPlanar

再来看看SemiPlanar,此格式下U和V分量交叉存储,Image并没有为我们将U和V分量分离出来

下面是一段YUV420SemiPlanar格式Image解析的记录

image format: 35get data from 3 planespixelStride 1rowStride 1920width 1920height 1080buffer size 2088960Finished reading data from plane 0pixelStride 2rowStride 1920width 1920height 1080buffer size 1044479Finished reading data from plane 1pixelStride 2rowStride 1920width 1920height 1080buffer size 1044479Finished reading data from plane 2

图片格式依然是YUV_420_888,Y分量与上述Planar中一样。但U和V分量出现了变化,buffer size是Y分量的1/2,如果说U分量只包含有U分量信息的话应当是1/4,多出来了1/4的内容,我们稍后再仔细看。注意到U中rowStride为1920,即U中每1920个数据代表一行,但pixelStride为2,代表行内颜色值间隔为1,就说是只有行内索引为0 2 4 6 ...才有U分量数据,这样来说还是行内每两个像素点共用一个U值,行间每两个像素点共用一个U值,即YUV420。

U和V的pixelStride都是2,我们从U和V中挑相同位置的20个byte值出来看看相互之间的关系。

124 -127 124 -127 123 -127 122 -127 122 -127 123 -127 123 -127 123 -127 122 -127 123 -127-127 124 -127 123 -127 122 -127 122 -127 123 -127 123 -127 123 -127 122 -127 123 -127 123

上面一行来自U,下面一行来自V,最前面一个byte的索引值相同,且为偶数。可以明显发现U和V分量只是进行了一次移位,而这个移位就保证了从索引0开始间隔取值就一定能取到自己分量的值。所以可以简单来说U和V分量就是复制的UV交叉的数据。

这样想要获取U分量值的话只需要以pixelStride为间隔获取就好了,V分量也是一样。虽然你也可以只从U或V分量得到U和V分量的信息,但毕竟官方并没有保证这一点,多少有些风险。另外如果想要知道更多的细节,也可以去翻Android源码。

PackedSemiPlanar

这个简单点说,不知为何,在我的设备上PackedSemiPlanar和SemiPlanar的表现是一致的,也就是说,可能Android已经帮我们解决了Packed的问题,只有Semi留给我们自己解决。

综上,我们只需要根据pixelStride和rowStride就能在对应的plane中获取到相应的颜色数据,而不必知道具体的YUV420格式。

关于CropRect

根据官方文档的介绍是说,CropRect指定了图片内的一个矩形区域,只有这个区域内的像素才是有效的,但鉴于我目前还没碰到这个问题,也不好详细解释。不过有两点要注意,首先是坐标系的变换,一定要弄清楚Rect和图片的长和宽的关系;其次是U和V的偏移量问题,U和V中颜色点是Y的1/4,在Rect中要计算好U和V中数据的范围,避免发生错位等。

小结

本篇主要介绍YUV_420_888格式的图片数据如在Image中的存储和管理,其中重点又放在U和V分量的管理上。本篇算作对官方文档的一点补充,如果想要深入理解,还需从源码入手。

参考

转载地址:http://fkdab.baihongyu.com/

你可能感兴趣的文章
MongoDB 地理位置索引的实现原理
查看>>
MongoDB与MySQL的插入、查询性能测试
查看>>
深入理解OAuth2.0协议
查看>>
https原理:证书传递、验证和数据加密、解密过程解析
查看>>
MySQL在大型网站的应用架构演变
查看>>
sphinx教程1__mysql sphinx引擎插件式热安装
查看>>
sphinx教程2__安装、配置和使用
查看>>
ttserver 缓存使用和过期设置
查看>>
php pconnect 长连接原理
查看>>
php memcached使用中的坑
查看>>
php变量引用和计数_refcount_gc和is_ref_gc
查看>>
windows环境下php和Php扩展编译,扩展dll文件编译
查看>>
magento 验证码
查看>>
magento性能优化系列二:db篇
查看>>
Discuz!$_G变量的使用方法
查看>>
magento memcache缓存配置
查看>>
PHP json_encode中文乱码解决方法
查看>>
mysql服务启动、关闭
查看>>
php获取中文字符串的首字符拼音字母
查看>>
php curl通过代理获取数据
查看>>