Android 图片编码之必备技能

news2024/11/24 10:31:55

在进行 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 中的图片编码,让您在开发时能够更加得心应手。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

淘宝用户体验分析方法论

本专题共10篇内容&#xff0c;包含淘宝APP基础链路过去一年在用户体验数据科学领域&#xff08;包括商详、物流、性能、消息、客服、旅程等&#xff09;一些探索和实践经验&#xff0c;本文为该专题第一篇。 在商详页基于用户动线和VOC挖掘用户决策因子带来浏览体验提升&#x…

chatgpt赋能python:Python扫描IP段的简介

Python 扫描 IP 段的简介 Python 是一种广泛应用于数据科学、机器学习、Web 开发等领域的高级编程语言。作为一种通用编程语言&#xff0c;Python 也可以应用于网络安全领域。其中&#xff0c;Python 可以用于扫描 IP 段的网络安全工具开发。 Python 扫描 IP 段 Python 扫描…

5.27下周黄金行情走势预测及开盘操作策略

近期有哪些消息面影响黄金走势&#xff1f;下周黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;周五(5月26日)黄金大幅下跌&#xff0c;主要受到美国数据影响&#xff0c;美国公布的4月PCE和耐用品订单数据向好&#xff0c;再次强化市场对美联储的鹰派押注。现货…

软件测试之自动化测试【webdriver API】

目录 一、webdriver API 1.元素的定位 2.操作测试对象 3.添加等待 3.1 sleep 强制等待 3.2 隐式等待 3.3 显式等待 4.打印信息 5.浏览器的操作 5.1 浏览器的前进和后退 5.2 浏览器滚动条操作 5.3 浏览器最大化及设置浏览器宽、高 6.键盘按键 7. 鼠标事件 8.定位…

chatgpt赋能python:Python找零-让你的生活更轻松

Python 找零 - 让你的生活更轻松 在我们日常生活中&#xff0c;找零是一个很常见的问题。无论是在超市买东西、给朋友拿钱、或者是做商业交易&#xff0c;都需要进行找零操作。而使用 Python 编程语言&#xff0c;可以让这个问题更加简单易懂&#xff0c;让我们来一起学习 Pyt…

Python中的布尔类型以及布尔值介绍

什么是布尔类型&#xff1f; 布尔类型是一种逻辑类型&#xff0c;它只有两个取值&#xff1a;True&#xff08;真&#xff09;和False&#xff08;假&#xff09;。在Python中&#xff0c;True和False是内置的布尔类型常量&#xff0c;用于表示真和假的状态。 布尔运算符 在P…

一场九年前的“出发”:奠基多模态,逐鹿大模型

原创&#xff1a;谭婧 全球AI大模型的技术路线&#xff0c;没有多少秘密&#xff0c;就那几条路线&#xff0c;一只手都数得过来。 而举世闻名的GPT-4浑身上下都是秘密。 这两件事并不矛盾。为什么呢&#xff1f; 这就好比&#xff0c;回答“如何制造一台光刻机&#xff1f;”。…

Yolov5/Yolov7涨点技巧:MobileViT移动端轻量通用视觉transformer,MobileViTAttention助力小目标检测,涨点显著

1. MobileViT介绍 论文:https://arxiv.org/abs/2110.02178 现有博客都是将MobileViT作为backbone引入Yolov5,因此存在的问题点是训练显存要求巨大,本文引入自注意力的Vision Transformer(ViTs):MobileViTAttention MobileViT是一种基于Transformers的轻量级模型,它可以用于…

chatgpt赋能python:Python操作手机:SEO指南

Python 操作手机&#xff1a;SEO 指南 在移动设备占据互联网用户市场大头的今天&#xff0c;应用程序的互动变得越来越受欢迎。这就需要我们在开发和优化网站时将手机端无缝集成到我们的计划中。使用 Python 语言可以有效地实现此目标&#xff0c;本文将探讨如何使用 Python 操…

【一篇文章带你掌握HTML中ul、ol和dl列表的使用 - 超详细】

【一篇文章带你掌握HTML中ul、ol和dl列表的使用 - 超详细】_dl标签_China_YF的博客-CSDN博客 前提 在项目开发过程中&#xff0c;列表是非常常见的&#xff0c;因此列表标签也是我们使用相对频繁的标签&#xff0c;但是当我们遇到列表的时候有没有停顿思考一下&#xff0c;我在…

提醒!手机卡注销前,一定要做的四件事!

现在更换手机卡的情况对小伙伴们来说都是家常便饭的事情了&#xff0c;但是很多小伙伴在手机换号的时候&#xff0c;经常忘记解绑以前手机号绑定的一些业务&#xff0c;为此产生了很多不必要的麻烦&#xff0c;今天的这篇文章就是要告诫大家换号之前一定要做的几件事&#xff0…

基于yolov5的双目鱼体长度检测

前言 在水产养殖行业中&#xff0c;鱼体长度是衡量鱼类品质和成熟度的重要指标。然而&#xff0c;传统的鱼体长度测量方法需要手动测量&#xff0c;不仅耗时耗力还容易出现误差。正好最近做了一个基于双目视觉的鱼体检测项目&#xff0c;在这里和大家分享以下思路。 步骤 第一…

跨境电商环境搭建和买家账号培养的关键考虑因素

作为跨境电商环境搭建和买家账号培养的专业技术开发人员&#xff0c;我深知在亚马逊、速卖通、阿里国际、速卖通、美客多、shopee、Lazada、ebay、Temu等平台上运营的卖家面临的挑战 其中&#xff0c;补单是一项关键的工作&#xff0c;它能帮助卖家增加商品列表和评价数量&…

这个 冒泡排序详解过程 我能吹一辈子!!!

文章目录 冒泡排序概念冒泡排序算法思路冒泡排序代码实现冒泡排序优化 冒泡排序概念 冒泡排序是比较基础的排序算法之一&#xff0c;其思想是相邻的元素两两比较&#xff0c;较大的数下沉&#xff0c;较小的数冒起来&#xff0c;这样一趟比较下来&#xff0c;最大(小)值就会排列…

ES2020新语法:可选链操作符

目录 一、前言 二、案例 三、方法一&#xff1a;AND运算符 四、方法二&#xff1a;可选链操作符( ?. ) 1. 语法 2. 可选链与函数调用 3. 处理可选的回调函数或事件处理器 4.可选链和表达式 5.可选链访问数组元素 6.使用空值合并操作符 一、前言 今天看一个实习生写的…

Linux高级---configmap和secret

文章目录 一、ConfigMap1、介绍2、创建configmap3、使用configmap4、引入环境变量的另一种方式 二、Secret1、介绍2、创建secret3、使用secret4、引入环境变量的另一种方式 一、ConfigMap 1、介绍 ConfigMap 是一种 API 对象&#xff0c;用来将非机密性的数据保存到键值对中。使…

chatgpt赋能python:Python指定日期处理方法,从入门到实践

Python指定日期处理方法&#xff0c;从入门到实践 Python是一种高级编程语言&#xff0c;因其简单易学和功能强大而深受开发者喜爱。在日常工作中&#xff0c;我们经常需要对日期进行处理和计算。Python提供了丰富的日期和时间处理库&#xff0c;因此我们可以轻松地进行日期处…

el-table分页保留勾选的数据

1、目标效果 代码全部写在下方App.vue中&#xff0c;复制粘贴即可运行 目前选中了5条数据 点击下方切换分页&#xff0c;选中的数据消失了 2、原理 &#xff08;1&#xff09;el-table复选框&#xff0c;用一个变量数组selectedRow:[ ] 监听选择了哪些数据 <el-table-colu…

【Python】Requests库基本使用

知识目录 一、写在前面✨二、Requests库三、接口调用四、总结撒花&#x1f60a; 一、写在前面✨ 大家好&#xff01;我是初心&#xff0c;希望我们一路走来能坚守初心&#xff01; 今天跟大家分享的文章是 Python中Requests库在爬虫和自动化中的使用 &#xff0c;希望能帮助到…

这10种神级性能优化手段

引言&#xff1a;取与舍 软件设计开发某种意义上是“取”与“舍”的艺术。 关于性能方面&#xff0c;就像建筑设计成抗震9度需要额外的成本一样&#xff0c;高性能软件系统也意味着更高的实现成本&#xff0c;有时候与其他质量属性甚至会冲突&#xff0c;比如安全性、可扩展性…