图形 2.6 伽马校正

news2024/12/28 21:50:04

伽马校正

B站视频:图形 2.6 伽马校正

文章目录

  • 伽马校正
  • 颜色空间
    • 传递函数
  • Gamma校正
    • 校正过程
    • 为什么需要校正?
      • CRT与转换函数
    • 为什么sRGB在Gamma 0.45空间?
  • 人对亮度的敏感
  • 韦伯定律
    • 中灰值
  • 线性工作流
    • 不在线性空间下进行渲染的问题
    • 统一到线性空间
  • Unity中颜色空间
    • 硬件支持
    • 硬件特性支持
  • 资源导出问题
    • Substance Painter
    • PhotoShop
      • Document Color Profile
      • 半透明UI
  • 其余参考资料
  • 作业
    • 自己动手尝试进行gamma校正

颜色空间

2.6_1

通用:sRGB

电影:DCI-P3

电视:Rec-709、PAL等

印刷:CMYK、Adobe RGB

其他

传递函数

在已经知道了颜色空间下的三原色的值,但是要将其显示到电子设备上,就需要将其转换为视频信号,这就需要用到传递函数

传递函数包含两部分:

  • 光信号转为电信号(OETF。例如拍视频时,需要把场景中的线性的光转换到非线性的视频信号)

  • 电信号转换成光信号(EOTF。例如在电脑上播放视频时,需要把非线性的视频信号转换成显示在设备上的光信号)

2.6_2

Gamma校正

Gamma可以简单定义为:
V o u t = V i n g a m m a V_{out} = V_{in^{gamma}} Vout=Vingamma
Gamma是指对线性三色值非线性视频信号之间进行编码解码的操作。

2.6_3

校正过程

2.6_4

  • 图像经过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与转换函数

2.6_7

左图为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格式相当于对物理空间的颜色做了一次伽马校正

还有另外一种解释,和人眼对暗的感知更加敏感的事实有关。

2.6_5

如图,在真实世界中(第二行),如果光的强度从0.0逐步增加到1.0,那么亮度应该是线性增加的。但是对于人眼来说(上方),感知到的亮度变化却不是线性的,而是在暗的地方有更多的细节。换句话说,我们应该用更大的数据范围来存暗色,用较小的数据范围来存亮色。这就是sRGB格式做的,定义在Gamma 0.45空间。而且还有一个好处就是,由于显示器自带Gamma 2.2,所以我们不需要额外操作显示器就能显示回正确的颜色。

人对亮度的敏感

2.6_6

自然界线性增长的亮度的一个灰阶变化和人心理上感受到的均匀灰阶做一个映射,就能得到上图的曲线。

其中自然界线性增长的亮度0.2位置对应的就是人心理上感受到的一个中灰值。如果把人心理上感受到的中灰值以下称为暗部部分,把中灰值以上称为亮部部分,可以明显看到,暗部曲线会比亮部曲线更陡峭,这也就对应了上文说道的人眼在感受亮度变化时,对于暗部的变化明显比亮部的变化要更敏感

换句话说,人眼在应对外界的亮度刺激均匀增长的过程中,会从刚开始的比较敏感,然后逐渐到越来越不敏感,这种现象也符合一个定律,韦伯定律

韦伯定律

即感觉的差别阈限随原来的刺激量的变化而变化,而且表现为一定的规律性。公式如下:
C = Δ ϕ ϕ 其中 ϕ 为原刺激量, Δ ϕ 为此时的差别阈限, C 为常数,又称为韦伯率 C = \frac {\Delta \phi} \phi \\ 其中\phi为原刺激量,\Delta \phi为此时的差别阈限,C为常数,又称为韦伯率 C=ϕΔϕ其中ϕ为原刺激量,Δϕ为此时的差别阈限,C为常数,又称为韦伯率
简单来说就是,当所受刺激越大时,需要增加的刺激也要足够大才会让人感受到明显变化,但是只适用于中等强度的刺激。

中灰值

现在有一张黑白渐变图和一条纯灰图,如下所示:

2.6_8

将纯灰图移至渐变图中间,原本纯灰的表现在感受上就会出现些许渐变的效果。

又比如下图:

2.6_9

A区域的颜色和B区域的颜色在感受上明显不一致(左图),但如果在A和B之间用一个纯灰条进行连接(右图),就可以看见实际上这两个区域的颜色是一致的。

从以上表现可得出,中灰值并非是一个具体的数值,而是取决于人的视觉感受

线性工作流

2.6_10

线性工作流,就是在生产的各个环节,正确使用Gamma编码以及Gamma解码,使得最终得到的颜色数据与最初输入的物理数据一致。

如果是使用Gamma空间的贴图,在传给着色器之前需要从Gamma空间转换到线性空间。目的是为了在着色器中进行一些渲染计算的时候,使用的是线性空间的颜色值,这样就不会出现一些错误的显示结果。

不在线性空间下进行渲染的问题

2.6_11

若不在线性空间下进行渲染计算,在进行亮度叠加时(左图)会出现过曝的效果。这是因为Gamma空间下的值在经过Gamma编码之后,此时的值是比实际的值要更大。例如原本四个亮度为0.098的值,进行叠加以后应该是0.196,结果由于在Gamma空间下,0.098的值被编码为0.35,也就是四个0.35的值进行叠加,最后得出1.4,超过了1,就会有过曝的效果。

此外,在进行颜色的混合时,如果在混合前没有对非线性的颜色进行转换,就会在纯色的边界出现一些黑边(右图)。

2.6_12

在进行光照渲染计算时,如果我们把视觉上也就是非线性空间的中灰值0.5,当成物理光强为0.5去计算,就会出现上图左边的情况。

统一到线性空间

2.6_14

我们从橙色框的左上角出发。

第一步,输入的纹理如果是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。

2.6_13

  • 如果选择了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自己会处理他们。

2.6_17

还有一些纹理不是上面的任何类型,但又已经在线性空间了(比如说Mask纹理、噪声图),那你需要取消sRGB这个选项让它跳过Remove Gamma Correction过程:

2.6_18

到底什么纹理应该是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

2.6_15

当Substance的贴图导出时,线性的颜色值经过Gamma编码,颜色被提亮了,所以需要在Unity中勾选sRGB选项,让它在采样时能还原回线性值。

PhotoShop

2.6_16

如果使用线性空间,一般来说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

2.6_19

Unity中的混合是线性混合,PhotoShop的图层和图层之间做混合的时候,每个上层图层都经过了伽马变换,然后才做了混合。在设置中更改,选择“用灰度系数混合RGB颜色“,参数设置为1,这样图层才是直接混合的结果。

其余参考资料

Gamma、Linear、sRGB 和Unity Color Space,你真懂了吗? - 知乎

作业

自己动手尝试进行gamma校正

主贴图

2.6_21

① 将主贴图是否勾选sRGB选项进行对比:

结果

2.6_20

可看出,未勾选sRGB的主贴图将Gamma空间的颜色值直接加入渲染计算,最后呈现出来的颜色比原图亮很多。

② 对未勾选sRGB的主贴图进行采样,并手动转化到Linear空间:

2.6_22

Shader

Shader "TA100/2_6_GammaToLinear"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
    }
    SubShader
    {
        Tags { "RenderType"="Opaque" }
        LOD 100

        Pass
        {
            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 API
                col.rgb = GammaToLinearSpace(col.rgb);
                return col;
            }
            ENDCG
        }
    }
}

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

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

相关文章

Android setContentView执行流程(一)-生成DecorView

Android setContentView执行流程(一)-生成DecorView Android setContentView执行流程(二)-将布局添加到mContentParent setContentView的流程主要就是讲在Activity的onCreate方法中调用setContentView方法之后,我们自定义的xml文件加载的过程,学习它可以…

【计算机网络】【网络层】【习题】

计算机网络-网络层-习题 文章目录 13. 图 4-69 给出了距离-向量协议工作过程,表(a)是路由表 R1 初始的路由表,表(b)是相邻路由器 R2 传送来的路由表。请写出 R1 更新后的路由表(c)。…

图像处理实验四(Adaptive Filter)

一、Adaptive Filter简介 自适应滤波器(Adaptive Filter)是一种能够根据输入信号的统计特性自动调整自身参数以达到最佳滤波效果的滤波器。它广泛应用于信号处理领域,如信道均衡、系统识别、声学回波抵消、生物医学、雷达、波束形成等模块。 …

typedef 与 extern 的结合:一场误解的澄清

typedef 与 extern 的结合:一场误解的澄清 一、typedef 的基本用法二、extern 的基本用法三、typedef 与 extern 的结合:一场误解的澄清示例二:使用 extern 声明外部变量示例三:错误的用法:尝试在 typedef 中使用 extern四、总结在C语言编程的世界里,typedef和extern是两…

Qt_day5_常用类

常用类 目录 1. QString 字符串类(掌握) 2. 容器类(掌握) 2.1 顺序容器QList 2.2 关联容器QMap 3. 几种Qt数据类型(熟悉) 3.1 跨平台数据类型 3.2 QVariant 统一数据类型 3.3 QStringList 字符串列表 4. QD…

HashMap的put流程知道吗

HashMap 的 put 方法算是 HashMap 中比较核心的功能了,复杂程度高但是算法巧妙,同时在上一版本的基础之上优化了存储结构,从链表逐步进化成了红黑树,以满足存取性能上的需要。本文逐行分析了 put 方法的执行流程,重点放…

鸿蒙UI开发——实现环形文字

1、背 景 有朋友提问:您好关于鸿蒙UI想咨询一个问题 如果我想实现展示环形文字是需要通过在Text组件中设置transition来实现么,还是需要通过其他方式来实现。 针对这位粉丝朋友的提问,我们做一下解答。 2、实现环形文字效果 ❓ 什么是环形…

保存pytest的执行日志;在日志中显示当前是第几次执行

1、在本地保存执行日志: 在终端中执行时因为指定了-s参数,所以会打印相关信息,可以帮助我们后续定位问题: 但是显示在终端时后面无法查看,所以需要把执行日志保存在本地,使用tee 或 重定向符号>&#x…

2024年8个最佳在线websocket调试工具选择

精选了 8 款功能强大且易于使用的 WebSocket 测试工具: 工具名称支持的系统是否免费ApifoxWindows, Mac, Linux是WebSocket KingWindows, Mac, Linux是PostmanWindows, Mac, Linux是Socket.IO Test ClientWindows, Mac, Linux是InsomniaWindows, Mac, Linux是Wires…

H5流媒体播放器EasyPlayer.js播放器wasm编译打包之后报uncaught referenceErro的原因排查

EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、Mp3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方…

初识算法 · 位运算(2)

目录 前言: 判定字符是否唯一 丢失的数字 比特位计数 只出现一次的数字III 前言: ​本文的主题是位运算,通过四道题目讲解,一道是判断字符是否唯一,一道是只出现一次的数字III,一道是比特位计数&…

丹摩征文活动 | 丹摩智算平台:服务器虚拟化的璀璨明珠与实战秘籍

丹摩DAMODEL|让AI开发更简单!算力租赁上丹摩! 目录 一、引言 二、丹摩智算平台概述 (一)平台架构 (二)平台特点 三、服务器虚拟化基础 (一)虚拟化的概念 &#xf…

[Docker#6] 镜像 | 常用命令 | 迁移镜像 | 压缩与共享

目录 Docker 镜像是什么 生活案例 为什么需要镜像 镜像命令详解 实验 1.一些操作 1. 遍历查看镜像 2. 查看镜像仓库在本地的存储信息 进入镜像存储目录 查看 repositories.json 文件 3. 镜像过滤 4. 下载镜像时的分层 实战一:离线迁移镜像 实战二&…

信用租赁系统的灵活配置与智能化管理助力租赁市场发展

内容概要 在现代租赁市场中,信用租赁系统就像一把金钥匙,打开了灵活配置与智能化管理的大门。首先,让我们看看它是如何运作的。这个系统允许用户根据自身需求自定义设备类型和信用分比例,不同租赁形式的选择使得整个过程更加个性…

Java基于SpringBoot+Vue框架的宠物寄养系统(V2.0),附源码,文档

博主介绍:✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ 🍅文末获取源码联系🍅 👇🏻 精彩专栏推荐订阅👇…

游戏引擎学习第四天

视频参考:https://www.bilibili.com/video/BV1aDmqYnEnc/ BitBlt 是 Windows GDI(图形设备接口)中的一个函数,用于在设备上下文(device context, DC)之间复制位图数据。BitBlt 的主要用途是将一个图像区域从一个地方复…

OpenGL ES 文字渲染进阶--渲染中文字体

旧文 OpenGL ES 文字渲染方式有几种? 一文中分别介绍了 OpenGL 利用 Canvas 和 FreeType 绘制文字的方法。 无论采用哪种方式进行渲染,本质上原理都是纹理贴图:将带有文字的图像上传到纹理,然后进行贴图。 渲染中文字体 利用 Canvas 绘制中文字体和绘制其他字体在操作方式上…

T265相机双目鱼眼+imu联合标定(全记录)

最近工作用到t265,记录一遍标定过程 1.安装驱动 首先安装realsense驱动,因为笔者之前使用过d435i,装的librealsense版本为2.55.1,直接使用t265会出现找不到设备的问题,经查阅发现是因为realsense在2.53.1后就不再支持…

python数据分析|二 IPython和JupyterNotebooks

一 python 解释器 Python解释器同一时间只能运行一个程序的一条语句。 如何适用: win r cmd 要退出Python解释器返回终端,可以输入 exit() 或 Ctrl-D。 假设创建了一个 hello_world.py 文件,它的内容是: 可以用下面的命令运…

集群聊天服务器(2)Json介绍

目录 Json序列化Json反序列化 大家之间交流用json,想要发送数据,就把数据序列化成json,想要接收数据,就反序列化成自己程序的语言。 Json序列化 可以直接赋值一个容器对象 js[‘xx’]vec; #include "json.hpp" using jsonnlohman…