首页 > 其他分享 >伽马校正

伽马校正

时间:2023-03-30 22:59:44浏览次数:42  
标签:校正 非线性 颜色 显示器 亮度 伽马 gamma

颜色空间

​ 在介绍伽马校正前,我们先了解了解必要的知识——颜色空间

​ 颜色空间有几种,分别是sRGB、CIE XYZ等,他们都有颜色匹配函数,但不同颜色空间表示的色域范围不同

CIE XYZ

​ CIE XYZ是人造的颜色空间,他并不是由实验得出的,用XYZ表示颜色,其中Y可以表示亮度
image-20230330164740308

​ CIE XYZ的颜色匹配表达式如下:
image-20230330165219391

​ 能不能将其可视化呢?也就是转化为一个2d图像。因为y表示亮度,所以把y固定为一个亮度,然后让XZ变化,结果如图所示
image-20230330165539462

​ 上图中这块带颜色的就是色域,它有一个中心,中心是白色(最不纯的),而边界时单色(最纯的)

sRGB

​ sRGB是一类应用非常广泛的标准系统,比如显示器,但sRGB的色域是有限的
image-20230330205044358

​ 由于人眼对亮度的感知是非线性的,对较暗区域的变化更加敏感,基于这一特点,sRGB要求图像将更多地空间用于存储更多较暗的区域

这里写图片描述

显示器非线性的颜色空间

​ 在早期的CRT显示器,像素点得到的电压值和该值对应的光强并不是线性的;在如今的LCD显示器,为了保证兼容,在硬件上也都选择了和当年CRT一样的非线性特性。显示器的电压和亮度的关系曲线类似一个指数函数,这个指数称为gamma。如下图所示,一个典型的gamma值2.2,它表示像素点在50%的强度下发出的亮度不到100%强度的1/4
24fig02.jpg

gamma校正

​ Gamma对于不同的显示设备,其具体的值不尽相同,通常在 [2.0,2.4]。根据这个非线性性质做校正的过程,称作gamma 校正。值得注意的是,在0和1处对应的值是不变的,我们需要校正的是(0,1)的值

​ 对于渲染而言,它所用的光照都是线性模型,因此这种情况下100%的亮度是50%的两倍,但这一切有个前提,那就是反射比与物体表面的反射特性是一个线性关系,也就是说,视点看到的光照强度,与保存在 Frame Buffer 里的值是成固定比例的

更多的,若拍摄是在Gamma颜色空间下进行,在线性空间下渲染,没有经过 Gamma 校正而直接输出,这时结果可能反而第一眼看起来像是对的,这是为什么呢?因为非线性的拍摄和非线性的显示,会在某种程度上相互抵消,但这也会存在许多瑕疵,如光照、blend、mipmaps,也就是说关乎颜色的计算都会出问题

不进行gamma校正会出现的问题

非线性输入纹理(Nonlinear Input Textures)

​ 大部分用户不会用到校准后的显示器,因此很多图片格式会自动进行一个预校正,如JPEG格式会将Gamma 值校正为 2.2 ,该值虽然并不精确匹配所有显示器,但能适配绝大部分显示器。这也说明,输入的纹理并不是线性的,因此这种进行了预校正的图片在渲染前,需要进行一下反 Gamma 校正

Mipmaps

​ 创建 Mipmap 的经典操作就是将原图缩小。假设在一张高分辨率的图上,有一条边(周围像素色值相差较大)上有 4 个相邻的像素,分别是2 个 1.0,2 个 0.0,在低分辨率的mipmap上,这四个像素会合为1个像素,按理说该像素应该为0.5,但若处在一个gamma值为2.0的非线性颜色空间中,该像素点的亮度只有最高亮度的25%,因此mipmaps的计算将会出错

光照

​ 如下图所示,假设我们使用Lambertian模型,假设光源的反射向量L和法线的夹角是60°,按理说反射光强度是原来的一半,但若处在一个gamma值为2.0的非线性颜色空间中,实际的反射光强度是原来的1/4
24fig03.jpg

也许你会想,我不可以直接将亮度拉高吗?这是不行的,因为处于不同亮度范围需要被校正的值是不同的,明暗交界处会变得更锐利——从亮到暗的过渡会变得更快

校正方法

​ Gamma 校正是指在图片显示之前,应用一个与显示器颜色变换相反的变换到图片上.也就是说,对于一个像素,先将其色值转换为原来的 1/γ

​ 对于动画来说,常见的处理方法是程序使用一份颜色校准查找表(color-correction lookup tables),校准后可以让渲染操作使用线性数学正确显示渲染图像

​ 对于游戏来说,常见的处理方法是使用一个较为通用的 Gamma 值(2.2),去匹配大多数普通的显示器

​ 现代的GPU都支持sRGB 贴图格式,这个格式的图片虽然像素经过了gamma校正,但文件里保存了校正的gamma值,作为贴图传给GPU时,GPU硬件会预先取出该gamma值,将贴图还原到线性空间后再传给shader,这被称为自动校准。而所有8-bit 格式的贴图都支持 sRGB,这些格式包括 RGB、RGBA、luminance、luminance alpha 、 DXT compressed。而手动校正会使用pow指令,该指令只能在抗锯齿后使用,这会导致抗锯齿的操作是在非线性空间下的,且自动校准不仅效率更快,而且能避免转换过程中造成的精度损失

  • 手动校正实例

     float3 diffuseCol = pow( f3tex2D( diffTex, texCoord ), 2.2 );
    // Or (cheaper, but assuming gamma of 2.0 rather than 2.2)    
    float3 diffuseCol = f3tex2D( diffTex, texCoord ); 
    diffuseCol = diffuseCol * diffuseCol; 
    
  • 将输出进行校正

    float3 finalCol = do_all_lighting_and_shading(); 
    float pixelAlpha = compute_pixel_alpha(); 
    return float4(pow(finalCol, 1.0 / 2.2), pixelAlpha); 
    // Or (cheaper, but assuming gamma of 2.0 rather than 2.2)    return float4( sqrt( finalCol ), pixelAlpha ); 
    

reference

Chapter 24. The Importance of Being Linear | NVIDIA Developer

GAMES101

标签:校正,非线性,颜色,显示器,亮度,伽马,gamma
From: https://www.cnblogs.com/chenglixue/p/17274627.html

相关文章