本文是isp算法学习的第七篇章,主要是讲述GAMMA CORRECTION原理和算法。

gamma调节,可以调节对比度,提高动态范围。

这张图能很好的看出不同gamma曲线带给人的直观感受的变化。从上往下看左侧黑色块黑得越来越严重,对比度也在逐渐加深。但是需要注意的时这幅图时一个反伽马曲线的特性,和ISP中的gamma表现时反的,这个具体后面回介绍。这个给这张图主要是对gamma有一个直观的理解。

补充关于gamma基础

1:人眼对暗部细节比较敏感。

**2:图片文件的色阶很有限。**图像的来龙去脉:自然界捕获的图像->图像存储和处理->显示器输出,两头的颜色数量都是非常丰富的,但是中间的存储和处理出于存储容量和渲染时带宽的限制,4位色图片每个通道只有2^8个色阶,总共只能显示2^24种颜色。

**基于以上两点,我们需要在整个图像来龙去脉中尽可能保留暗部细节,亮部细节丢掉一些也无所谓。**因此有了pow(color, 1/2.2)这个gamma encoding操作,使暗部细节也分到更多色阶。得到一张比较“亮”的图片存储起来。这张图片虽然暗部细节都保留下来了,但是不能直接看这张“亮”的图片,那只是一个中间产物而已。我们需要显示器做一个pow(color, 2.2)的gamma decoding操作把它压暗,因为显示器(特别是高端显示器)的颜色数是远大于224的,这个操作并不会在压暗的过程中丢失暗部细节。

总结一下,**gamma校正存在的本质原因是:是受限于有限存储空间及渲染带宽,需要在整个图像的流转各级转换中尽可能保留暗部细节,以满足人眼对暗部敏感的需求。**人最终看到显示器显示图像和最初从自然界捕获的图像大体是无差别的,只是暗部细节损失少,亮部细节损失多罢了

1产生原因

这个是32位图中的数值,反应的就是自然界的物理量(按照反射率分布),所以这个色带对应的其实是现实中的反射率。左边五分之一20%处是中灰色,中间的像素表现的是反射率为白色50%的物体看起来的灰度,这个灰度是0.5^0.454=73%灰。也就是8位下的186灰。具象的说,如果我有一支蜡笔反射率是50%,看起来就是中间这个灰度。

这个是人眼感觉均匀的灰的渐变。其中左端的色彩值是0,中间的色彩值是128(0.5),右边是1.0的纯白。屏幕要以什么样的亮度显示这些像素呢?最左边像素关灯不显示,是黑色,中间以白色21.8%的亮度(反射率)显示,右边像素全开,显示100%白色。

假设光照适宜的场景中有一个中灰色的物体,反射率是白纸的0.2,我们采样到它的时候,应当把0.2的物理能量用0.454的Gamma放大到0.5的灰阶地位记录下来,这样一来,暗部区域就分配到128个灰阶了。我们充分地利用了存储空间。

如果在拍照的时候不进行Gamma校正,那么中灰物体会被映射为0.2记录下来,那么此时,暗部仅分配到50个灰阶,暗部采样严重不足,高光采样冗余。

知乎关于gamma的描述

  1. 2.2怎么来的

    实践中目测调整出来并最终确定的,其实说良心话,只要是0.5中灰对应白色的20%左右,画面看起来都是靠谱的,所以当年的Gamma特别多种多样,在2.2上下浮动(1.8-2.5)。

    凡是说Gamma 2.2来自于老式CRT显示器物理特性的解释,都是误解。跟显示器发展史没关系,完全是视觉效果决定的。一切都因为韦伯定律

  2. 为什么一直强调低动态图像

    在低动态范围的语境下,我可以安全的定义,中灰蜡笔的反射率是白色蜡笔的20%左右,中灰像素的亮度是白像素亮度的20%左右,而不是现实场景中最亮物体的20%。这一点是很关键的。

  3. 如果灰阶预算不紧张,会怎么样

    灰阶有限的前提下,因为人眼对自然的非线性感知特性,我们才需要Gamma校正。

    具体到生活中的现象就是:因为我们硬盘太贵,网线太细,所以地球人目前主流使用8位每通道的sRGB色彩描述体系,它灰阶有限,中灰的地位必须在所有灰阶的中间,记录值为128,而不能是其物理值0.218,把物理量0.218换算成0.5灰阶编号的过程,就是编码端的Gamma校正,Gamma值为1/2.2=0.454。屏幕读取到128显示成21.8%的亮度的过程,就是解码端的Gamma校正,Gamma值为2.2。整个系统Gamma为1。若是有朝一日,32位每通道文件成为主流格式,Gamma校正就会消失。自然数据不经校正直接记录为文件数据,再不经校正直接显示。

2校正方法

2.1LUT法(查表法)

如图的论文中提到了一种LUT法的实现方式。

理解起来很简单,就是提前把每个像素值经gamma矫正后对应的值求出来,然后把这些数据直接存储到一个数中,到矫正的时候根据输入的值就能直接通过数组下标就能找到对应的矫正后的值,这种方式最大的有点就时快,几乎不消耗硬件资源,因为几乎不用做任何计算的处理,但是这种方式的弊端在于需要大量的内存来存储这么这个表。但是现在随着技术的发展内存对于硬件也不是什么限制了,一个手机动辄就8G的内存了,可以通过加DDR来提高内存,所以现在很多方案在用这种查表得方式做gamma矫正(输入10bit,输出12bit,为了保留高亮区域的信息)。

1clc;clear; close all;
2data = csvread('data/Gamma_Data_DEC_20210804103309.csv');
3plot(data);
4xlim([0, 1024]);
5ylim([0, 4098]);
6hold on;
7plot([0, 1024], [0, 4098], 'r');

对应的图像如下图所示

海思平台也是类似

2.2线性插值

这种方式在一些廉价的方案里面会用到

线性插值法也很好理解,就是在gamma曲线上提取一些采样点

  • 把采样点的输入输出作为xy存储起来

  • 矫正的时候如果在采样点上就接直接输入矫正值

  • 如果不在,那么肯定在某两个采样点之间,那么就可以就可以通过这两个采样点的线性方程求解出该点的校正值 $$ p(x)=\frac{f(x_n)-f(x_{n-1})}{x_n-x_{n-1}}(x_n-x) $$

但是这种方式会有一定的误差,因为线性方程并布恩那个完全拟合gamma曲线。

 1clc;clear;close all;
 2data = textread('data\gamma.txt', '%s');
 3xStr = char(data(1));
 4yStr = char(data(2));
 5xC = strsplit(xStr, ',');
 6yC = strsplit(yStr, ',');
 7x = hex0x2Dec(xC);
 8y = hex0x2Dec(yC);
 9plot(x, y);
10hold on;
11plot([0 255], [0 1023], 'r')
12xlim([0, 256]);
13ylim([0, 1024]);

如下图所示

2.3模拟gamma

还有一种方式就是通过模拟的方式来做gamma矫正,但是这种方式不输入ISP PIPELINE中的算法,因为不属于ISP算法,属于Sensor端的控制,所以只是简单提一下。

这种方法的大概思路就是AD转换的时候经过一定的处理使其呈现非线性的特性。如上图定义Vramp和Vsig,当电压达到Vramp时产生一个斜坡信号,同时始终信号开始工作并计数,然后当电压到达Vsig时latch信号发生一个跳变使得始终信号停止基数,然后这个电压值就会和这种始终信号有一个非线性特性,人后根据这个特性进行gamma矫正。

3补充说明

有的ISP除了有Ygamma还有RGBgamma,其实这个RGBgamma也很好理解,RGBgamma就是针对RGB三个通道分别有一条gamma曲线进行调整,这样就可以分别控制RGB三色通道从而对颜色产生控制。