图形 2.6 伽马校正
伽马校正
B站视频:图形 2.6 伽马校正
文章目录
- 伽马校正
- 颜色空间
- 传递函数
- Gamma校正
- 校正过程
- 为什么需要校正?
- CRT与转换函数
- 为什么sRGB在Gamma 0.45空间?
- 人对亮度的敏感
- 韦伯定律
- 中灰值
- 线性工作流
- 不在线性空间下进行渲染的问题
- 统一到线性空间
- Unity中颜色空间
- 硬件支持
- 硬件特性支持
- 资源导出问题
- Substance Painter
- PhotoShop
- Document Color Profile
- 半透明UI
- 其余参考资料
- 作业
- 自己动手尝试进行gamma校正
颜色空间
通用:sRGB
电影:DCI-P3
电视:Rec-709、PAL等
印刷:CMYK、Adobe RGB
其他
传递函数
在已经知道了颜色空间下的三原色的值,但是要将其显示到电子设备上,就需要将其转换为视频信号,这就需要用到传递函数。
传递函数包含两部分:
-
光信号转为电信号(OETF。例如拍视频时,需要把场景中的线性的光转换到非线性的视频信号)
-
电信号转换成光信号(EOTF。例如在电脑上播放视频时,需要把非线性的视频信号转换成显示在设备上的光信号)
Gamma校正
Gamma可以简单定义为:
V o u t = V i n g a m m a V_{out} = V_{in^{gamma}} Vout=Vingamma
Gamma是指对线性三色值和非线性视频信号之间进行编码和解码的操作。
校正过程
-
图像经过gamma编码存储在硬盘中,将获取到的物理数据做一次gamma值约为0.45的映射,这样的过程叫做gamma编码。
由上图0.45曲线可知,曲线形状上拱,此时图像像素比实际物理像素要更亮。
-
在显示图像时,需要将对经过了0.45映射图像的每个像素做一次gamma值约为2.2的校正(一般是显示器校正),使得最终结果为正确的物理数据(相当于曲线拉直了)。
经过显示的gamma校正之后,之前偏亮的图像亮度降低。
为什么需要校正?
在物理世界中,如果光的强度增加一倍,那么亮度也会增加一倍,这是线性关系。
而历史上最早的显示器CRT(阴极射线管)显示图像的时候,电压增加一倍,亮度并不跟着增加一倍。即输出亮度和电压并不是成线性关系的,而是呈亮度增加量等于电压增加量的2.2次幂的非线性关系:
l = u 2.2 ( l ∈ [ 0 , 1 ] , u ∈ [ 0 , 1 ] ) l = u^{2.2} \space\space\space\space (l \in [0,1],u \in[0,1]) l=u2.2 (l∈[0,1],u∈[0,1])
2.2也叫做该显示器的Gamma值,现代显示器的Gamma值也都大约是2.2。如果我们在显示器输出之前,做一个操作把显示器的Gamma 2.2影响平衡掉,那就和人眼直接观察物理世界一样了。
CRT与转换函数
左图为Gamma编码的曲线,也是人眼对于一个物理光强度的一个响应曲线。
右图为早期CRT在Gamma 2.2时,电压与屏幕亮度之间对应关系的一个映射曲线。
可看出,这两个曲线是互为反函数的一个关系。
以物理光强0.218为例:
- 在经过Gamma编码曲线映射之后,就变成了0.5;
- 显示在CRT上时,会经过Gamma 2.2的映射,从0.5映射回0.218。
为什么sRGB在Gamma 0.45空间?
假设你用数码相机拍一张照片,你看了看照相机屏幕上显示的结果和物理世界是一样的。可是照相机要怎么保存这张图片,使得它在所有显示器上都一样呢? 可别忘了所有显示器都带Gamma 2.2。反推一下,那照片只能保存在Gamma 0.45空间,经过显示器的Gamma 2.2调整后,才和你现在看到的一样。换句话说,sRGB格式相当于对物理空间的颜色做了一次伽马校正。
还有另外一种解释,和人眼对暗的感知更加敏感的事实有关。
如图,在真实世界中(第二行),如果光的强度从0.0逐步增加到1.0,那么亮度应该是线性增加的。但是对于人眼来说(上方),感知到的亮度变化却不是线性的,而是在暗的地方有更多的细节。换句话说,我们应该用更大的数据范围来存暗色,用较小的数据范围来存亮色。这就是sRGB格式做的,定义在Gamma 0.45空间。而且还有一个好处就是,由于显示器自带Gamma 2.2,所以我们不需要额外操作显示器就能显示回正确的颜色。
人对亮度的敏感
将自然界线性增长的亮度的一个灰阶变化和人心理上感受到的均匀灰阶做一个映射,就能得到上图的曲线。
其中自然界线性增长的亮度0.2位置对应的就是人心理上感受到的一个中灰值。如果把人心理上感受到的中灰值以下称为暗部部分,把中灰值以上称为亮部部分,可以明显看到,暗部曲线会比亮部曲线更陡峭,这也就对应了上文说道的人眼在感受亮度变化时,对于暗部的变化明显比亮部的变化要更敏感。
换句话说,人眼在应对外界的亮度刺激均匀增长的过程中,会从刚开始的比较敏感,然后逐渐到越来越不敏感,这种现象也符合一个定律,韦伯定律。
韦伯定律
即感觉的差别阈限随原来的刺激量的变化而变化,而且表现为一定的规律性。公式如下:
C = Δ ϕ ϕ 其中 ϕ 为原刺激量, Δ ϕ 为此时的差别阈限, C 为常数,又称为韦伯率 C = \frac {\Delta \phi} \phi \\ 其中\phi为原刺激量,\Delta \phi为此时的差别阈限,C为常数,又称为韦伯率 C=ϕΔϕ其中ϕ为原刺激量,Δϕ为此时的差别阈限,C为常数,又称为韦伯率
简单来说就是,当所受刺激越大时,需要增加的刺激也要足够大才会让人感受到明显变化,但是只适用于中等强度的刺激。
中灰值
现在有一张黑白渐变图和一条纯灰图,如下所示:
将纯灰图移至渐变图中间,原本纯灰的表现在感受上就会出现些许渐变的效果。
又比如下图:
A区域的颜色和B区域的颜色在感受上明显不一致(左图),但如果在A和B之间用一个纯灰条进行连接(右图),就可以看见实际上这两个区域的颜色是一致的。
从以上表现可得出,中灰值并非是一个具体的数值,而是取决于人的视觉感受。
线性工作流
线性工作流,就是在生产的各个环节,正确使用Gamma编码以及Gamma解码,使得最终得到的颜色数据与最初输入的物理数据一致。
如果是使用Gamma空间的贴图,在传给着色器之前需要从Gamma空间转换到线性空间。目的是为了在着色器中进行一些渲染计算的时候,使用的是线性空间的颜色值,这样就不会出现一些错误的显示结果。
不在线性空间下进行渲染的问题
若不在线性空间下进行渲染计算,在进行亮度叠加时(左图)会出现过曝的效果。这是因为Gamma空间下的值在经过Gamma编码之后,此时的值是比实际的值要更大。例如原本四个亮度为0.098的值,进行叠加以后应该是0.196,结果由于在Gamma空间下,0.098的值被编码为0.35,也就是四个0.35的值进行叠加,最后得出1.4,超过了1,就会有过曝的效果。
此外,在进行颜色的混合时,如果在混合前没有对非线性的颜色进行转换,就会在纯色的边界出现一些黑边(右图)。
在进行光照渲染计算时,如果我们把视觉上也就是非线性空间的中灰值0.5,当成物理光强为0.5去计算,就会出现上图左边的情况。
统一到线性空间
我们从橙色框的左上角出发。
第一步,输入的纹理如果是sRGB(Gamma 0.45),那我们要进行一个操作转换到线性空间。这个操作叫做Remove Gamma Correction,在数学上是一个2.2的幂运算。如果输入不是sRGB,而是已经在线性空间的纹理了呢?那就可以跳过Remove Gamma Correction了。
注:美术输出资源时都是在sRGB空间的,但Normal Map等其他电脑计算出来的纹理则一般在线性空间,即Linear Texture。
第二步,现在输入已经在线性空间了,那么进行Shader中光照、插值等计算后就是比较真实的结果了,如果不对sRGB进行Remove Gamma Correction直接就进入Shader计算,那算出来的就会不自然,就像前面那两张球的光照结果一样。
第三步,Shader计算完成后,需要进行Gamma Correction,从线性空间变换到Gamma 0.45空间,在数学上是一个约为0.45的幂运算 。如果不进行Gamma Correction输出会怎么样?那显示器就会将颜色从线性空间转换到Gamma 2.2空间,接着再被你看到,结果会更暗。
第四步,经过了前面的Gamma Correction,显示器输出在了线性空间,这就和人眼看物理世界的过程是一样的了。
Unity中颜色空间
通过点击菜单Edit -> Project Settings -> Player页签 -> Other Settings下的Rendering部分进行修改,参数Color Space可以选择Gamma或Linear。
- 如果选择了Gamma,那Unity不会对输入和输出做任何处理,换句话说,Remove Gamma Correction 、Gamma Correction都不会发生,除非你自己手动实现;
- 如果选了Linear,那么就是上文提到的统一线性空间的流程了。对于sRGB纹理,Unity在进行纹理采样之前会自动进行Remove Gamma Correction,对于Linear纹理则没有这一步。而在输出前,Unity会自动进行Gamma Correction再让显示器输出。
怎么告诉Unity纹理是sRGB还是Linear呢?对于特定用途的纹理,可以直接设置他们所属的类型:如Normal Map、Light Map等都是Linear,设置好类型Unity自己会处理他们。
还有一些纹理不是上面的任何类型,但又已经在线性空间了(比如说Mask纹理、噪声图),那你需要取消sRGB这个选项让它跳过Remove Gamma Correction过程:
到底什么纹理应该是sRGB,什么是Linear?
所有需要人眼参与被创作出来的纹理,都应是sRGB(如美术画出来的图)。所有通过计算机计算出来的纹理(如噪声,Mask,Light Map)都应是Linear。
硬件支持
线性空间需要图形API的硬件支持,目前支持的平台
-
Windows、Mac OS x、Linux(Standalone)
-
Xbox one
-
PS 4
-
Android(OpenGL ES 3.0)
-
IOS(Metal)
-
WebGL
硬件特性支持
主要由两个硬件特性来支持:
-
sRGB Frame Buffer
- 将Shader的计算结果输出到显示器前做Gamma校正;
- 作为纹理被读取时会自动把存储的颜色从sRGB空间转换到线性空间;
- 调用ReadPixels()、ReadBacklmage()时,会直接返回sRGB空间下的颜色;
- sRGB Frame Buffer只支持每通道为8 bit的格式,不支持浮点格式;
- HDR开启后会先把渲染结果绘制到浮点格式的Frame Buffer中,最后绘制到sRGB Frame Buffer上输出。
-
sRGB Sampler
将sRGB的贴图进行线性采样的转换。
使用硬件特性完成sRGB贴图的线性采样和shader计算结果的Gamma校正,比起在shader里对贴图采样和计算结果的校正要快。
资源导出问题
Substance Painter
当Substance的贴图导出时,线性的颜色值经过Gamma编码,颜色被提亮了,所以需要在Unity中勾选sRGB选项,让它在采样时能还原回线性值。
PhotoShop
如果使用线性空间,一般来说PhotoShop可以什么都不改,导出的贴图只要勾上sRGB就可以了。如果调整PhotoShop的伽玛值为1,导出的贴图在Unity中也不需要勾选sRGB了。
Document Color Profile
- PhotoShop对颜色管理特别精确,Unity里看到的颜色要经过显示器的Gamma变换,而PhotoShop不会,PhotoShop会读取显示器的Color Profile,反向补偿回去;
- PhotoShop有第二个Color Profile,叫做Document Color Profile。通常它的默认值就是sRGB Color Profile,和显示器的Color Profile一致,颜色是被这个Color Profile压暗了,所以PhotoShop中看到的结果才和Unity中一样。
半透明UI
Unity中的混合是线性混合,PhotoShop的图层和图层之间做混合的时候,每个上层图层都经过了伽马变换,然后才做了混合。在设置中更改,选择“用灰度系数混合RGB颜色“,参数设置为1,这样图层才是直接混合的结果。
其余参考资料
Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗? - 知乎
作业
自己动手尝试进行gamma校正
主贴图
① 将主贴图是否勾选sRGB选项进行对比:
结果
可看出,未勾选sRGB的主贴图将Gamma空间的颜色值直接加入渲染计算,最后呈现出来的颜色比原图亮很多。
② 对未勾选sRGB的主贴图进行采样,并手动转化到Linear空间:
Shader
Shader "TA100/2_6_GammaToLinear"
{Properties{_MainTex ("Texture", 2D) = "white" {}}SubShader{Tags { "RenderType"="Opaque" }LOD 100Pass{CGPROGRAM#pragma vertex vert#pragma fragment frag#include "UnityCG.cginc"struct appdata{float4 vertex : POSITION;float2 uv : TEXCOORD0;};struct v2f{float2 uv : TEXCOORD0;float4 vertex : SV_POSITION;};sampler2D _MainTex;float4 _MainTex_ST;v2f vert (appdata v){v2f o;o.vertex = UnityObjectToClipPos(v.vertex);o.uv = TRANSFORM_TEX(v.uv, _MainTex);return o;}fixed4 frag (v2f i) : SV_Target{fixed4 col = tex2D(_MainTex, i.uv);//Gamma to Linear//col.rgb = pow(col.rgb, 2.2);//UnityCG APIcol.rgb = GammaToLinearSpace(col.rgb);return col;}ENDCG}}
}
相关文章:

图形 2.6 伽马校正
伽马校正 B站视频:图形 2.6 伽马校正 文章目录 伽马校正颜色空间传递函数 Gamma校正校正过程为什么需要校正?CRT与转换函数 为什么sRGB在Gamma 0.45空间? 人对亮度的敏感韦伯定律中灰值 线性工作流不在线性空间下进行渲染的问题统一到线性空…...

LLM - 计算 多模态大语言模型 的参数量(Qwen2-VL、Llama-3.1) 教程
欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/143749468 免责声明:本文来源于个人知识与公开资料,仅用于学术交流,欢迎讨论,不支持转载。 影响 (…...

数据可视化这样做,汇报轻松拿捏(附免费好用可视化工具推荐)
一、数据可视化的定义 数据可视化是数据分析中重要的工作之一。在完成数据采集之后,通过可视化方式,将数据转化为美观且浅显易懂的统计图/表/视频,从而进一步解读数据背后隐藏的价值,这种方数据处理方式就叫做数据可视化。近些年…...

杂七杂八之基于JSON Web Token (JWT) 进行API认证和鉴权(Java版)
杂七杂八之基于JSON Web Token (JWT) 进行API认证和鉴权(Java版) 在现代Web应用和API开发中,JSON Web Token (JWT) 是一种广泛使用的认证和鉴权机制。JWT不仅简化了认证流程,还提供了安全的令牌传递方式,使得跨域认证…...

建设展示型网站企业渠道用户递达
展示型网站的主要作用便是作为企业线上门户平台、信息承载形式、拓客咨询窗口、服务/产品宣传订购、其它内容/个人形式呈现等,网站发展多年,现在依然是企业线上发展的主要工具之一且有建设的必要性。 谈及整体价格,自制、定制开发、SAAS系统…...

如何通过AB测试找到最适合的Yandex广告内容
想要在Yandex上找到最能吸引目标受众的广告内容,A/B测试是一个不可或缺的步骤。通过对比不同版本的广告,我们可以发现哪些元素最能引起用户的共鸣。首先,设计两个或多个广告版本,确保每个版本在标题、文案、图片等关键元素上有所不…...

AI写作(四)预训练语言模型:开启 AI 写作新时代(4/10)
一、预训练语言模型概述 预训练语言模型在自然语言处理领域占据着至关重要的地位。它以其卓越的语言理解和生成能力,成为众多自然语言处理任务的关键工具。 预训练语言模型的发展历程丰富而曲折。从早期的神经网络语言模型开始,逐渐发展到如今的大规…...

解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url
解决Anaconda出现CondaHTTPError: HTTP 000 CONNECTION FAILED for url 第一类情况 在anaconda创建新环境时,使用如下代码 conda create -n charts python3.7 错误原因: 默认镜像源访问速度过慢,会导致超时从而导致更新和下载失败。 解决方…...

员工绩效统计出现很多小数点,处理方法大全
1.直接通过数据库修改数据类型 譬如采用DECIMAL类型 2.float 降低小数点位数 3.php 采用round函数...

【启明智显分享】5G CPE为什么适合应用在连锁店中?
连锁门店需要5G CPE来满足其日益增长的网络需求,提升整体运营效率和竞争力。那么为什么5G CPE适合连锁店应用呢,小编为此做了整理,主要是基于以下几个方面的原因: 一、高效稳定的网络连接 1、高速数据传输: 5G CPE能…...

十大经典排序算法-希尔排序与归并排序
1、希尔排序 希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。但希尔排序是非稳定排序算法。 希尔排序是基于插入排序的以下两点性质而提出改进方法的: 插入排序在对几乎已经排好序的数据操作时,效率高&…...

gitlab和jenkins连接
一:jenkins 配置 安装gitlab插件 生成密钥 id_rsa 要上传到jenkins,id_rsa.pub要上传到gitlab cat /root/.ssh/id_rsa 复制查看的内容 可以看到已经成功创建出来了对于gitlab的认证凭据 二:配置gitlab cat /root/.ssh/id_rsa.pub 复制查…...

Qt Event事件系统小探2
目录 事件过滤器 来看一个例子 拖放事件和拖放操作 Qt官方文档给出的说明 拖放 拖放类 配置 拖动 放置 覆盖建议的操作 子类化复杂窗口小部件 拖放操作 添加新的拖放类型 放置操作 放置矩形 剪贴板 其他函数的介绍 事件过滤器 我们知道,有的时候想…...

[2024最新] java八股文实用版(附带原理)---java集合篇
介绍一下常见的list实现类? ArrayList 线程不安全,内部是通过数组实现的,继承了AbstractList,实现了List,适合随机查找和遍历,不适合插入和删除。排列有序,可重复,当容量不够的时候…...

pytorch tensor在CPU和GPU之间转换,numpy之间的转换
# input input.cpu().numpy() input input.cpu().detach().numpy() # 有gradCPU tensor转GPU tensor: cpu_imgs.cuda()GPU tensor 转CPU tensor: gpu_imgs.cpu()numpy转为CPU tensor: torch.from_numpy( imgs )4.CPU tensor转为numpy数…...

【电压分层控制】光储三相并网下垂控制,直流微电网协调母线电压分层控制
摘要 本文研究了一种基于电压分层控制的光伏与储能系统并网控制策略。通过下垂控制和分层控制方法实现直流微电网的协调运行,提高系统动态响应和稳态性能。仿真结果表明,该控制策略能够在不同工况下有效稳定母线电压,并实现负载功率合理分配…...

【CSS】absolute定位的默认位置
position: absolute; 属性会使元素脱离正常的文档流,并相对于最近的非 static 定位祖先元素进行定位。如果没有这样的祖先元素,则相对于初始包含块(通常是视口)进行定位。 但是当top和left没有指定具体值时,元素的在上…...

遗传算法与深度学习实战——利用进化计算优化深度学习模型
遗传算法与深度学习实战——利用进化计算优化深度学习模型 0. 前言1. 利用进化计算优化深度学习模型2. 利用进化策略优化深度学习模型3. 利用差分计算优化深度学习模型相关链接 0. 前言 我们已经学习了使用进化策略 (Evolutionary Strategies, ES) 和差分进化 (Differential E…...

计算机视觉 ---图像读取与显示(OpenCV与Matplotlib)
前言 本文分别介绍了使用 OpenCV 和 Matplotlib 进行图像读取与显示的方法,如 cv2.imread ()、cv2.imshow ()、plt.imread ()、plt.imshow () 等,并提及了使用 OpenCV 时的注意事项。 OpenCV与Matplotlib图像读取与显示的差异 图像读取: Op…...

XML Schema 字符串数据类型
XML Schema 字符串数据类型 1. 概述 XML Schema 是一种用于定义 XML 文档结构和内容的语言。它提供了一种强大的机制来描述 XML 数据的类型、结构和约束。在 XML Schema 中,字符串数据类型是一种基本数据类型,用于表示文本数据。 2. 字符串数据类型 …...

Spring Boot 读取 yml 并映射至实体
application-base.yml app:# 附件存储路径upload-attachments: /data/attachments/# 报告导出详情 url - 前端score-detail-url: ${app.host.web}/#/process/start?processNo{}# api 文件下载 urlfile-download-url: ${app.host.web}/prod-api/sys_file_info/download/{}?fu…...

/// ts中的三斜线指令 | 前端
第一次看到注意到这行代码,不知道的还以为是注释呢,查了资料才知道这是typescript中的三斜线指令,那有什么作用呢? 1. 这行代码是TypeScript中的一个三斜线指令(Triple-Slash Directive),用于…...

什么岗位需要学习 OpenGL ES ?说说 3.X 的新特性
什么是 OpenGL ES OpenGL ES 是一种为嵌入式系统和移动设备设计的3D图形API(应用程序编程接口)。它是标准 OpenGL 3D 图形库的一个子集,专门为资源受限的环境(如手机、平板电脑、游戏机和其他便携式设备)进行了优化。 由于其在移动设备上的广泛适用性,OpenGL ES是学习移…...

【插件】多断言 插件pytest-assume
背景 assert 断言一旦失败,后续的断言不能被执行 有个插件,pytest-assume的插件,可以提供多断言的方式 安装 pip3 install pytest-assume用法 pytest.assume(表达式,f’提示message’) pytest.assume(表达式,f‘提示message’) pytest.ass…...

ctfshow DSBCTF web部分wp
ctfshow 单身杯 web部分wp web 签到好玩的PHP 源码: <?php error_reporting(0); highlight_file(__FILE__);class ctfshow {private $d ;private $s ;private $b ;private $ctf ;public function __destruct() {$this->d (string)$this->d;$this…...

三维点云 和模型转换的问题
随着科技的发展,三维激光扫描采集的点云数据作为一种新型的数据形式,在多个领域中都展现出了其强大的应用价值。那么,什么是点云数据?它是如何生成的?又能为我们的生活和工作带来哪些便利呢? 1.…...

黑马智数Day7
获取行车管理计费规则列表 封装接口 export function getRuleListAPI(params) {return request({url: parking/rule/list,params}) } 获取并渲染数据 import { getRuleListAPI } from /apis/carmounted() {this.getRuleList() }methods: {// 获取规则列表async getRuleList(…...

虚拟机安装Ubuntu 24.04服务器版(命令行版)
这个是专门用于服务器使用的,没有GUI,常用软件安装,见 虚拟机安装Ubuntu 24.04及其常用软件(2024.7)_ubuntu24.04-CSDN博客https://blog.csdn.net/weixin_42173947/article/details/140335522这里只记录独特的安装步骤 1 下载Ubuntu 24.04安…...

.net core开发windows程序在国产麒麟操作系统中运行
.net core自从3.1版本号后,完全是一个独立的开源的多平台开发组件,目前国产化是趋势,不少项目需要开发国产如Kylin操作系统中运行的程序,无论是Web程序还是桌面程序,都有这样的需求。 首先,可明确的的.net…...

【LinuxC编程】06 - 守护进程,线程
进程组和会话 概念和特性 进程组,也称之为作业。BSD于1980年前后向Unix中增加的一个新特性。代表一个或多个进程的集合。每个进程都属于一个进程组。在waitpid函数和kill函数的参数中都曾使用到。操作系统设计的进程组的概念,是为了简化对多个进程的管…...