iOS图像处理----探索图片解压缩到渲染的全过程以及屏幕卡顿

一:图像成像过程

①、将需要显示的图像,由CPU和GPU通过总线连接起来,在CPU中输出的位图经总线在合适的时机上传给GPU ,GPU拿到位图做相应位图的图层渲染、纹理合成。
②、将渲染后的结果,存储到帧缓存区,帧缓存区中存储的格式是位图。
③、由视屏控制器根据Vsync(垂直同步信号)在指定时间之前去提取对应帧缓冲区当中的屏幕内容,交由显示器,从左上角逐行扫描进行显示。
如图所示:

二:图片纹理映射 

我们在获取到图片的纹理数据后,要将纹理显示到屏幕上,先要做两件事:

①、将图片的纹理坐标通过 attribute方式,经顶点着色器桥接给片元着色器

②、将图片纹理数据通过Uniform传递给片元着色器,由片元着色器进行图片颜色的填充

在图片进行纹理颜色填充时,需要按照坐标进行一一对应,纹理坐标默认左下角为(0,0),右上角为(0,1)。

纹理的坐标与图形的坐标一一对应,最终会将图片正确的显示出来。如果纹理坐标映射的不正确则可能出现图片翻转、倒置等情况,甚至图片信息错乱。

 三:图片解压

在解释图片解压之前我们先了解几个概念:

①、位图:

又叫像素图或栅格图,它记录了图片每一个像素的颜色、深度、透明度等信息。这一系列像素按照一定的规则排列起来,就形成了我们看到的图片。位图的优点是能够完整记录图片信息,无论图片怎样拉伸都不会失真,缺点是图片文件太大,因此一般将位图压缩为jpg、png等格式。

②、有损压缩:

不会完全真实的记录图片信息,会根据人眼观察世界的特性,忽略掉部分会被人眼忽略的颜色信息,代之以邻近的颜色。因此图片虽然大部分可以还原,但某些情况下还是会失真,常见的有损压缩格式有JPG等。

③、无损压缩:

无损压缩会完整记录图片颜色信息,但是相同颜色的区域,会被压缩记录,因此无损压缩也可以比较完整的还原图片。不过由于能够保存的颜色值有限,所以依然有可能会出现失真,常见的格式有PNG等。

④、解压流程 

在我们的开发过程中,我们使用比较多的都是 JPG 或者 PNG 等格式图片,但是在图片真正显示之前,都会被先解压成位图,再重新渲染到屏幕上。所以图片解压的流程是:

1、解压JPG/PNG图片,获取图片信息
2、根据获取到的图片信息重新绘制位图,即纹理数据
3、将纹理数据载入,传入到片元着色器,经过渲染后显示

⑤、解压方法(Core Graphic) 

UImage *image = [UImage imageNamed:@"fly"];
CGImageRef cgImageRef = [image CGImage]; // 将UImage转换为CGImageRef// 获取图片宽高
GLuint width = (GLuint)CGImageGetWidth(cgImageRef);
GLuint height = (GLuint)CGImageGetHeight(cgImageRef);//获取图片的rect
CGRect rect = CGRectMake(0, 0, width, height);//获取图片的颜色空间
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();// 为图片开辟一片内存区域
// 一个像素点的颜色值包含 RGBA 各8位,共4个字节
void *imageData = malloc(width * height * 4);// 创建上下文
/**
CGBitmapContextCreate(void * __nullable data,size_t width, size_t height, size_t bitsPerComponent, size_t bytesPerRow,CGColorSpaceRef cg_nullable space, uint32_t bitmapInfo)data:如果不为 NULL ,那么它应该指向一块大小至少为 bytesPerRow * height 字节的内存;如果 为 NULL ,那么系统就会为我们自动分配和释放所需的内存,所以一般指定 NULL 即可;
width:  图片宽度
height:图片高度
bitsPerComponent:每个颜色分量所占bit数,此处传8位
bytesPerRow:位图的每一行使用的字节数,大小至少为 width * bytes per pixel 字节。当我们指定 0/NULL 时,系统不仅会为我们自动计算,而且还会进行cache line alignment 的优化
space:颜色空间
bitmapInfo:位图的信息,此处采用RGBA,即kCGImageAlphaPremultipliedLast
*/
CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);// 将图片翻转过来(图片默认是倒置的)
// 图片的坐标系左上角为(0,0),纹理坐标左下角为(0,0),因此需要翻转
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0f, -1.0f);// 绘制前先清除颜色空间和绘图区域,防止残留数据
CGColorSpaceRelease(colorSpace);
CGContextClearRect(context, rect);// 对图片进行重新绘制,得到一张新的解压缩后的位图
CGContextDrawImage(context, rect, cgImageRef);// 设置图片纹理属性
// 获取纹理ID
GLuint textureID;
glGenTextures(1, &textureID); // 获取一个纹理句柄
glBindTexture(GL_TEXTURE_2D, textureID); // 将句柄绑定到纹理目标上,GL_TEXTURE_2D等// 设置纹理属性
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);// 结束后是否数据
glBindTexture(GL_TEXTURE_2D, 0); // 将纹理目标重新绑定为0CGContextRelease(context); // 释放context
free(imageData); // 释放图片数据区域

⑥、总结

  • 1、图片文件只有在确认要显示时,CPU才会对齐进行解压缩.因为解压是非常消耗性能的事情.解压过的图片就不会重复解压,会缓存起来.

  • 2、图片渲染到屏幕的过程: 读取文件->计算Frame->图片解码->解码后纹理图片位图数据通过数据总线交给GPU->GPU获取图片Frame->顶点变换计算->光栅化->根据纹理坐标获取每个像素点的颜色值(如果出现透明值需要将每个像素点的颜色*透明度值)->渲染到帧缓存区->渲染到屏幕

 四、图片渲染流程

1、App通过CoreGraphics、CoreAnimation、CoreImage等框架的接口调用来触发图形渲染操作
2、CoreGraphics、CoreAnimation、CoreImage等框架将渲染交由OpenGL ES,由OpenGL ES来驱动GPU做渲染,最后显示到屏幕上
3、由于OpenGL ES 是跨平台的,所以在他的实现中,没有任何窗口相关的代码,而是让各自的平台为OpenGL ES提供载体。在iOS中,如果需要使用OpenGL ES,就是通过CoreAnimation提供窗口,让App可以去调用。 

 五、屏幕卡顿

屏幕卡顿是指图形图像的在显示时出现了撕裂(即图片错位显示)、掉帧(重复显示同一帧数据)等问题,导致用户能直观的从屏幕上看到的一种异常现象。

 ①、屏幕卡顿原因

1、由图像的显示原理,我们知道一帧的显示是由CPU和GPU共同决定的。一般来说,页面滑动流畅是60fps,也就是1s有60帧更新,即每隔16.7ms就要产生一帧画面,而如果CPU和GPU加起来的处理时间超过了16.7ms,从缓存区获取位图显示时,下一帧数据还没准备好,获取的仍是上一帧的数据,产生掉帧现象,掉帧就会导致屏幕卡顿。

2、苹果官方为解决屏幕撕裂问题,目前使用的方案是垂直同步+双缓存区,可以从根本上防止和解决屏幕撕裂,但是同时也导致了新的问题掉帧。虽然我们采用了双缓存区,但是我们并不能解决CPU和GPU处理图形图像的速度问题,导致屏幕在接收到垂直信号时,数据尚未准备好,缓存区仍是上一帧的数据,因此导致掉帧,如图5-1-2所示。


3、在垂直同步+双缓存区方案的基础上,提出将双缓存区,改为三缓存区的优化,但是这样并不能从根本解决掉帧问题,只是比双缓存区掉帧的概率小很多,用户可能无感知。

                                                                                  图5-1-2 

②、垂直同步与双缓存区 

1、VSync(垂直同步信号):是指给帧缓冲加锁,当电子光束扫描的过程中,只有扫描完成了才会读取下一帧的数据,而不是只读取一部分


2、双缓存区:采用两个帧缓冲区用来存储GPU处理的结果,当屏幕显示其中一个缓存区内容时,另一个缓冲区继续等待下一个缓冲结果,两个缓冲区依次进行交替

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

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

相关文章

堆解决贪心问题

502题,最小代价实现最大化IPO class Solution {/*本质还是贪心,只不过多了需要满足贪心的条件而已,首先由于启动资金是固定的,你得从小往大去观察哪些最小资本合适,这就需要定义一个pair,最小资本最大利润…

centos7常用命令之安装插件2

centos7安装插件1 7、kibana 【启动kibana,需要调整这个配置文件(/opt/kibana-6.3.0/config/kibana.yml)的一处ip地址,因为每次虚拟机的ip地址可能会有所不同, 同时访问页面地址的ip:5601时,ip地址也对应修改】 1.解压缩包 cd /opt/ tar -xvf kibana-6.3.0-linux-x…

【脑电信号处理与特征提取】P7-贾会宾:基于EEG/MEG信号的大尺度脑功能网络分析

基于EEG/MEG信号的大尺度脑功能网络分析 Q: 什么是基于EEG/MEG信号的大尺度脑功能网络分析? A: 基于脑电图(EEG)或脑磁图(MEG)信号的大尺度脑功能网络分析是一种研究大脑活动的方法,旨在探索脑区之间的功能…

【JavaSE篇】——继承

目录 🎓继承 ✅为什么需要继承 ✅继承概念 ✅继承的语法 ✅父类成员访问 🚩子类中访问父类的成员变量 1. 子类和父类不存在同名成员变量的情况 2. 子类和父类成员变量同名 🚩子类中访问父类的成员方法 1. 成员方法名字不同 2. 成员…

SAM:基于 prompt 的通用图像分割模型

Paper: Kirillov A, Mintun E, Ravi N, et al. Segment anything[J]. arXiv preprint arXiv:2304.02643, 2023. Introduction: https://segment-anything.com/ Code: https://github.com/facebookresearch/segment-anything SAM 是 Meta AI 开发的一款基于 prompt 的通用视觉大…

100%涨点!2024最新卷积块创新方案盘点(附模块和代码)

在写论文时,设计高效、创新的卷积块可以显著提升模型的性能,保障工作的有效性和先进性。另外,合理利用卷积块还可以帮助我们提升实验结果、拓展研究的视野和应用场景,增加论文的创新点。因此,对于论文er来说&#xff0…

2024美赛数学建模F题思路源码

比赛当天第一时间更新! 赛题目的 赛题目的: 问题描述: 解题的关键: 问题一. 问题分析 问题解答 问题二. 问题分析 问题解答 问题三. 问题分析 问题解答 问题四. 问题分析 问题解答 问题五. 问题分析 问题解答

数据库||数据库相关知识练习题目与答案

目录 1.只能读取本系学生的信息? 2.要查询选修“Computer”课的男生姓名,将涉及到关系( ) 3.实体完整性规则规定( ) 4.下列有关范式的叙述中正确的是( ) 5.从课程表course&…

BSV区块链将凭借Teranode的创新在2024年大放异彩

​​发表时间:2024年1月15日 2024年1月15日,瑞士楚格 – BSV区块链协会研发团队今日官宣了Teranode的突破性功能,这些功能将显著提升BSV区块链网络的效率和速度。在不久的将来,BSV区块链的交易处理能力将达到每秒100万笔交易。 T…

与后端配合单个/批量导出excel的方法

单个: 点击导出按钮后 直接通过后端提供的接口一行代码即可 location.href URL /api/Preparation/exportPreparationData?id${row.id}批量(这里的批量指的是一个Excel文件多个sheet页签,我们传参需要传相应的数组或其他数据结构给后端&am…

粒子群优化算法

PSO算法 粒子群算法(Particle,Swarm Optimization,PSO)由Kennedy和Eberhart于1995年提出,算法模仿鸟群觅食行为对优化问题进行求解。 粒子群算法中每个粒子包含位置和速度两个属性,其中,位置代表了待求问题的一个候选…

关于boolean类型isXxx的问题【2024-01-31】

1.0、见解文章: https://blog.csdn.net/yuechuzhixing/article/details/1247752661.1、问题来源 对于基础平台的响应体中,命名只有三个字段信息:code、msg、data,但是在响应的时候会莫名其妙出现一个ok字段。 如下是一个该问题…

安装GPU版本Pytorch(全网最详细过程)

目录 一、前言 二、安装CUDA 三、安装cuDNN 四、安装Anacanda 五、安装pytorch 六、总结 一、前言 最近因为需要安装GPU版本的Pytorch,所以自己在安装过程中也是想着写一篇博客,把整个过程记录下来,在整个过程中也遇到了不少的问题&a…

Vite 官方文档速通

前言:参考 Vite 官网 一. 指引 1. 为什么选择 Vite 1.1 现实问题 问题:当项目中 JS 代码量变多,就会导致:1. 启动开发服务慢(几分钟)。2,模块热替换(HMR)慢&#xff0…

Java List中对象根据id去重,并处理重复对象的某个字段

List中对象根据id去重 一、需求二、解决 一、需求 参考文章:https://blog.csdn.net/A_Gui_Code/article/details/106978867 对在list集合中对象根据主键id去重,同时需要对重复对象的某个字段进行单独处理。 例如,对象包含字段如下, 当某个对象重复时&a…

nignx日志定时清理、Windows 清理nignx日志、linux 清理nignx日志

因为项目日志老占磁盘空间,记录一下优化配置文件: 针对linux清理: 1.创建一个名为 cleanup_nginx_logs.sh 的脚本文件 nano cleanup_nginx_logs.sh 2.在打开的文本编辑器中,将以下内容复制并粘贴到文件中: #!/bin…

【开源】基于JAVA+Vue+SpringBoot的用户画像活动推荐系统

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块2.1 数据中心模块2.2 兴趣标签模块2.3 活动档案模块2.4 活动报名模块2.5 活动留言模块 三、系统设计3.1 用例设计3.2 业务流程设计3.3 数据流程设计3.4 E-R图设计 四、系统展示五、核心代码5.1 查询兴趣标签5.2 查询活动推荐…

状态压缩 笔记

棋盘式的f[i][j]中表示状态的j可以是状态本身也可以是在合法状态state中的下标 用状态本身比较方便,用下标比较省空间 用下标的话可以开id[M]数组记录一下 蒙德里安的梦想 求把 NM的棋盘分割成若干个 12的长方形,有多少种方案。 例如当 N2&#xff0…

【Redis】一文搞懂redis的所有知识点

目录 1. 什么是Redis?它主要用来什么的? 2.说说Redis的基本数据结构类型 2.1 Redis 的五种基本数据类型​编辑 2.2 Redis 的三种特殊数据类型 3. Redis为什么这么快?​编辑 3.1 基于内存存储实现 3.2 高效的数据结构 3.3 合理的数据编…

新火种AI|哄哄大模型的火爆,给了普通人AI创业破局的关键

作者:一号 编辑:美美 人们似乎更喜欢把AI当做玩具,而非工具。 近日,一款名为哄哄模拟器的AI原生应用火了,一天之内就吸引了60万用户。 哄哄模拟器设置了多种情侣吵架场景,无论你是男是女,都…