Android 图片编码之必备技能

在进行 Android 开发时,不可避免地会接触到许多图片格式,例如 JPEG、PNG 等。就以 JPEG 格式为例,它是一种有损压缩模式,使用 YCbCr 的颜色空间来保存色彩信息。当需要在屏幕上显示图片时,会将 JPEG 数据解码成 RGB 进行显示。本篇文章可能对初学者来说略显复杂。因此,建议读者具备一定的图像处理和 Android 开发基础知识。下面,一起来看看在 Android 中,如何使用图片编码以及对它们进行操作和处理。

NV21 中图片数据编码

首先,让我们来谈谈 NV21。在 Android 中,相机返回的图像格式默认使用的是 NV21,它属于 YUV420SP。YUV 是一种常见的颜色编码方法,经常用于影像处理的逻辑中。其中,Y 表示明亮度,UV 表示色度和浓度。YUV 模型有很多种编码方式,其中 YUV420P 和 YUV420SP 最为常见。YUV420P 采用平面存储方式,即将 Y、U、V 三个分量分开存储,处理起来较为方便。而 YUV420SP 则采用分离存储方式,即将 Y 分量存储在一块连续的内存中,而 U 和 V 分量则交替存储在另一块连续内存中,有关这两种编码方式的区别,请参见下图:

1f22ff0e631417c2c98228681d9d7d75.png
YUV420P 与 YUV420SP 的区别

YUV420P 与 YUV420SP 主要在 UV 的编码方式上。但是采样都是一样的数据。名字中的 PSP 代表如下含义:

  • P:指将 YUV 数据分为 3 个平面,Y/U/V 各占一个平面

  • SP: Semi Planar二维平面,指 YUV 数据分为 2 个平面,Y 数据一个平面,UV 数据合用一个平面

YUV 的发明,是由于彩色电视与黑白电视的过渡时期。黑白电视中只有 Y,也就是只有灰阶值。而彩色电视中,把 UV 处理成彩度,如果忽略 UV,就只剩下 Y,这就和之前黑白电视信号相同,从而解决兼容问题。并且 YUV 在传输中只需要占极少的带宽。

讲了半天的 YUV,那么这个 YUV 和 RGB 编码的 bitmap 有什么关系呢?

ae1a809731593e13f22c76ce76965d06.jpeg
摸不着头脑

Bitmap 的编码格式

做过 Android 应该都体会过 OOM 带来的痛苦吧?在处理图片时,都会使用 SampleSize 进行缩放,来减少图片加载过程中占用的内存大小。图片在内存中按像素点进行加载,每个像素点中又包含着 A、R、G、B 四个通道,因此一张图的大小就相当于需要计算出像素点的个数,再乘以每个像素点所需要的内存大小。因此,一张图加载到内存中所占大小按如下方式进行计算:

width * height * size(ARGB)

前面提到的 SampleSize 进行缩放,就是修改了 width 和 height 的大小,来减小内存的大小。还有一种方式,就是减少每一个像素点所占的内存大小,来降低内存占用的总大小。

在 Android 中,RGB_565 、ARGB_8888、ARGB_4444 等编码方式,在这里,我介绍常用的前两个:

  • RGB_565:总共只占两个字节,Red 占 5 个 Bit,Green 占 6 个 Bit,Blue 占 5 个  Bit。

  • ARGB_8888:总共占四个字节,ARGB和占 1 个 Byte。

因此,如果图片使用的是 ARGB_8888 的方式加载,那么到内存中的大小为 width * height * 4 。Android 默认加载 Bitmap 时,也是使用这种编码格式。

ARGB_8888 很好理解,全量存储了 Alpha、Red 、Green、Blue。每一个值都取 0~255 的值。那么问题来了,在 RGB_565 中,R、G、B 三个颜色分量所占的位数都不够去存储全量的数据,所以在转换的过程中一定会存在数据丢失。在实际的操作中,通常使用的办法就是将低位数据直接进行丢弃,这样 R/B 两通道分别能表示为 0 ~ 248 , 中间值间隔为 8 。Green 能够显示更多信息。RGB_888 与 RGB_565 映射示例如下, 其中 RGB_888 的数据就被丢弃掉了:

703348c64e10b8aa1323c8e4fc6140c7.png
RGB_565 与 RGB_888 映射关系

RGB 与 YUV 转换

在前面,介绍了 RGB 与 YUV 之间的存储区别,将 RGB 转成 YUV 格式的公式也已经存在很久了,只需要照抄公式就行了。

  • RGB 转 YUV

Y = 0.299 * R + 0.587 * G + 0.114 * B
U = -0.169 * R - 0.331 * G + 0.5 * B + 128
V = 0.5 * R - 0.419 * G - 0.081 * B + 128
  • YUV 转 RGB

R = Y + 1.13983 * (V - 128)
G = Y - 0.39465 * (U - 128) - 0.58060 * (V - 128)
B = Y + 2.03211 * (U - 128)

PS, 以上公式摘抄于维基百科。

YUV420SP  旋转

众所周知,Android 从相机中输出的图像是横向的。为了能够正常播放视频,需要将 NV21 格式的图像旋转 270 度。由于 Y 与像素点的对应关系为 1:1,因此旋转后的图像格式如下所示:

51508c220834c6fd03f9e89b2d61568a.png
YUV420SP 旋转 270 度

如上图,所以旋转的代码如下:

public byte[] rotate270(byte[] original, int width, int height) {

  byte[] result = new byte[original.length];
  int resultPosition = 0;
  for (int i = 0; i < width; i++) {
    int originalPosition = width - i;
    for (int j = 0; j < height; j++) {
      result[resultPosition++] = original[originalPosition - 1];
      originalPosition += width;
    }
  }
  int uvHeight = height >> 1;
  int startPosition = width * height;

  for (int i = 0; i < width; i += 2) {
    int originalPosition = startPosition + width - i;
    for (int j = 0; j < uvHeight; j++) {
      result[resultPosition++] = original[originalPosition - 2];
      result[resultPosition++] = original[originalPosition - 1];
      originalPosition += width;
    }
  }
  return result;
}

缩小图片分辨率

在使用 Bitmap 时,我们可以使用 Matrix 进行缩放。那么,现在只有一个 NV21 的图片数据,要如何进行缩放呢?根据前面的内容,我们可以很容易地想到,直接对 NV21 的数据进行固定间隔取样就可以实现图像的缩放。根据缩放的比例,取对应点的 YUV 值。如下图所示,将 8 x 4 的图转换成 4 x 2 的大小:

23794c893dfa546f405a44820c7f021f.png
YUV 缩放

当想明白这个图后,代码就很简单了,示例代码如下:

public byte[] scaleYUV(byte[] yuv, int width, int height, int newWidth, int newHeight) {
    byte[] result = new byte[newWidth * newHeight * 3 / 2];
    float xStep =1f * width / newWidth;
    float yStep =1f * height / newHeight;
    int resultIndex = 0;
    for (int y = 0; y < newHeight; y ++) {
        for (int x = 0; x < newWidth; x ++) {
            int yuvIndex = (int)(yStep * y) * width + (int)(x * xStep);
            result[resultIndex] = yuv[yuvIndex];
            resultIndex++;
        }
    }

    // scale UV
    int uvIndex = 0;
    for (int y = 0; y < newHeight / 2; y ++) {
        for (int x = 0; x <  newWidth; x += 2) {
            int yuvIndex = width * height + (int)(yStep * y) * width + (int)(x * xStep);
            result[resultIndex + uvIndex] = yuv[yuvIndex];
            result[resultIndex + uvIndex + 1] = yuv[yuvIndex + 1];
            uvIndex += 2;
        }
    }

    return result;
}

写在最后

到目前为止,我们已经学会了在 Android 上使用图片编码并对其进行操作和处理的必要技能。希望这篇文章有助于您更好地理解 Android 中的图片编码,让您在开发时能够更加得心应手。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/23429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何对项目进度进行跟踪?逐步完善项目计划

我接手了一个小项目&#xff0c;但是无论是我还是领导&#xff0c;都认为这是个简单的项目&#xff0c;最多一月时间就能搞定。但是&#xff0c;随着时间推移&#xff0c;三个月也没有将内容完善。于是我进行了反思总结&#xff0c;我认为存在如下问题&#xff1a; 1、资源协…

spring源码篇(八)事务的原理

文章目录 前言基本操作验证 Spring事务的传播机制特殊的机制说明NOT_SUPPORTEDNESTEDSUPPORTS 源码加载事务自动配置类要不要加注解&#xff1a;EnableTransactionManagement配置类说明 EnableTransactionManagement 做了什么AutoProxyRegistrar做了什么创建的代理类是jdk动态代…

【Nodejs】使用Nodejs搭建HTTP服务,并实现公网远程访问

文章目录 前言1.安装Node.js环境2.创建node.js服务3. 访问node.js 服务4.内网穿透4.1 安装配置cpolar内网穿透4.2 创建隧道映射本地端口 5.固定公网地址 转载自内网穿透工具的文章&#xff1a;使用Nodejs搭建HTTP服务&#xff0c;并实现公网远程访问「内网穿透」 前言 Node.js…

数据结构与算法·第2章【线性表】

线性结构具有以下基本特征&#xff1a; 有唯一的一个被称为首元素&#xff08;或头元素&#xff09;的元素&#xff0c;没有直接前驱&#xff1b;有唯一的一个被称为尾元素&#xff08;或尾节点&#xff09;的元素&#xff0c;没有直接后继。 数据元素之间存在一对一的线性关…

磐维数据库panweidb单节点服务器在centos7.9安装(研发环境)

一、系统环境优化 1.1 关闭SELINUX # 修改配置文件 cat /etc/selinux/config | grep -i SELINUX SELINUXdisabled# 关闭SELINUX setenforce 0 1.2 内核参数优化 vi /etc/sysctl.conf 添加# panweidb net.ipv4.tcp_max_tw_buckets 10000 net.ipv4.tcp_tw_reuse 1 net.ipv4.t…

ssm+springboot+java高校图书馆图书借阅座位预约管理系统系统

陕理工图书馆管理系统包括多个功能模块&#xff1a;图书类别管理模块、图书管理模块、读者管理模块、借阅管理模块、预约管理、推荐管理。管理员登入后&#xff0c;维护图书借阅的信息。本文介绍了使用Java技术开发陕理工图书馆管理系统的设计与实现过程&#xff0c;首先对实现…

【源码分析】【netty】FastThreadLocal 为什么快?

写在前面 接下来几篇文章&#xff0c;我们来聊一聊 netty 相关的。这里作者想先从 FastThreadLocal 开始说&#xff0c;而不是可能大家更熟悉的 reactor 啊&#xff0c;责任链设计啊&#xff0c;ByteBuf 啊&#xff0c;池化啊等等。不过虽然说 FastThreadLocal 熟知程度不如其…

2023年湖北建筑架子工报名流程?报名需要什么资料?考试一次过?

2023年湖北建筑架子工报名流程&#xff1f;报名需要什么资料&#xff1f;考试一次过&#xff1f; 建筑架子工证是建筑行业必备的证书之一&#xff0c;它是证明持有人可以在建筑工地上从事搭建脚手架、模板等施工工作的重要证明。启程别告诉你架子工的报名流程和资料。 百度搜一…

示范性微电子院校“抢人”,芯片赛道黄不了!

经常看到有同学问&#xff0c;“国内高校微电子专业最好的是哪所高校?”“想搞数字ic设计去哪所大学好呢&#xff1f;” 其实国内28所示范性微电子学院都是非常不错的选择。 2015年&#xff0c;九所示范性微电子院校名单公布&#xff0c;包括了清华大学、北京大学、复旦大学…

【7 Vue3 – Composition API】

1 认识Composition API Options API的弊端 setup函数 2 setup函数的参数 3 setup简单使用 1 注意不再有响应式数据 要做到响应式数据需要在数据定义时使用ref包装数据,并且在使用时,使用value解包 2 注意template要使用的数据或者函数,必须要return 返回才能被使用 <templa…

软考A计划-软件设计师笔记

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分享&am…

MT4期货软件怎么使用?有哪些MT4期货软件使用知识?

现在MT4软件在投资市场上应用广泛&#xff0c;当然也包括期货交易市场&#xff0c;但有不少投资者不知道为什么一定要选择MT4期货软件&#xff0c;其实选择MT4期货软件的理由有很多&#xff0c;MT4作为一款交易软件&#xff0c;不仅能够为投资者提供准确的市场信息&#xff0c;…

02SpringCloud Nacos注册中心和配置中心与Sentinel服务熔断和流控

Nacos注册中心和配置中心 Nacos 是 Alibaba 开发的用于微服务管理的平台&#xff0c;核心功能&#xff1a;服务注册与发现和集中配置管理。 Nacos 作为服务注册发现组件&#xff0c;可以替换Spring Cloud 应用中传统的服务注册于发现组件&#xff0c;如&#xff1a;Eureka、C…

Ai作图可控性演进——从SD到MJ

背景 Ai作图从Diffusion模型开始&#xff0c;作图进入稳步发展快车道。然后用过diffusion系列作图的同学对产图稳定性&#xff0c;以及可控性都会颇有微词。diffusion系列作图方法在宏观层面上确实能够比较好的做出看上去还不错的图。然后当你细抠细节时候&#xff0c;发现这东…

如何在Windows 11更新后解决C盘已满的问题?

Windows 11比Windows 10需要占用C盘更多的空间&#xff0c;在升级到Windows 11后&#xff0c;如果升级后出现问题&#xff0c;安装程序可以帮你退回到Windows 10。无论怎样&#xff0c;在升级到Windows 11后&#xff0c;系统会自动制作以前的数据的副本&#xff0c;这会占用大量…

win7下java环境搭建以及jdk环境变量配置

很多人在搭建页游、手游时候经常遇到JAVA闪退&#xff0c;基本都是环境变量或者路径错误导致的。本章节主要讲解在win7系统环境下&#xff0c;java环境变量配置方法&#xff0c;java环境配置正确&#xff0c;才可以对apk程序进行反编译运行页游手游。其他操作系统环境变量大同小…

Mesh形变算法

前言&#xff1a; 作者正好因为动画、模拟仿真等等的重大需求需要预先研发离散形的模型Mesh的形变算法&#xff0c;并且要验证、研究适用的范围、特别是性能等等&#xff0c;摸着石头过河别喷&#xff0c;毕竟我主要是渲染、动画、引擎的对于计算几何、三维重建不是很熟悉&…

一体化医学影像平台PACS源码,影像存档与传输系统源码

PACS影像存档与传输系统源码 PACS即影像存档与传输系统&#xff0c;是医学影像、数字化图像技术、计算机技术和网络通讯技术相结合的产物&#xff0c;是处理各种医学影像信息的采集、存储、报告、输出、管理、查询的计算机应用程序。 是基于DICOM标准的医学影像管理系统&…

大龄、零基础,想转行做网络安全。怎样比较可行?这届粉丝可真难带

昨晚上真的给我气孕了。 对于一直以来对网络安全兴趣很大&#xff0c;想以此作为以后的职业方向的人群。 不用担心&#xff0c;你可以选择兼顾工作和学习&#xff0c;以步步为营的方式尝试转行到网络安全领域。 那么&#xff0c;网络安全到底要学些什么呢&#xff1f; &…

Kyligence 客户案例招商银行批发业务分析平台获评金融数字化最佳实践案例

近日&#xff0c;“2023 爱分析金融数字化最佳实践案例”评选结果正式揭晓。Kyligence 携手招商银行申报的“招商银行‘火眼’批发业务分析平台”项目经过领先性、案例创新性、应用成熟度、价值创造等维度综合评选&#xff0c;最终获评“金融数字化最佳实践案例”。 招商银行“…