公式:

python opencv做伽马矫正 opencv gamma_反射率


A是常数,

指数为Gamma。

Gamma校正:

出现Gamma矫正根本原因是gamma校正存在的本质原因是:是受限于有限存储空间及渲染带宽,需要在整个图像的流转各级转换中尽可能保留暗部细节,以满足人眼对暗部敏感的需求。人最终看到显示器显示图像和最初从自然界捕获的图像大体是无差别的,只是暗部细节损失少,亮部细节损失多罢了。
Gamma矫正的目的是为了让显示屏显示的数据和自然界中一样。同时尽可能的保存暗部细节。
Gamma校正是一种重要的非线性变换,其是对输入图像灰度值进行指数变换,
一般情况下,当用于Gamma矫正的值大于1时,图像的高光部分被压缩而暗调部分被扩展,当Gamma矫正的值小于1时,图像的高光部分被扩展而暗调部分被压缩,Gamma矫正一般用于平滑的扩展暗调的细节。

python opencv做伽马矫正 opencv gamma_python opencv做伽马矫正_02


中间的虚线代表,

程序

import cv2
import numpy as np
def Gamma_adjust(img,Gamma):
    table = np.zeros(256, dtype=np.float32)
    for i in range(256):
        table[i] = (i/255.0)**(Gamma)*255
    table = np.array(table.astype("uint8"))
    new_img = cv2.LUT(img, table)
    new_img = np.uint8(new_img)
    return new_img


img = cv2.imread("back.jpg",0)
cv2.imshow("initial",img)
img_ga = Gamma_adjust(img,2)
cv2.imshow("Gamma",img_ga)
Key = cv2.waitKey()
if Key == 27:
    cv2.destroyAllWindows()

对Gamma矫正进行本质的认识。

Gamma矫正出现的原因有两个:

  • 韦伯定律
  • 中灰C

韦伯定律

韦伯定律,即感觉的差别阈跟随原来刺激量的变化而变化,而且表现为一定的规律性,用公式表示出来,就是python opencv做伽马矫正 opencv gamma_灰度_03,其中python opencv做伽马矫正 opencv gamma_位图_04是原刺激量,python opencv做伽马矫正 opencv gamma_位图_05是此时的差别阈限,C为常数,又称韦伯率。
简单的理解就是,人对自然界的感知,是非线性的,外界以一定比例的加强刺激,对于人来说,这个刺激是均匀增长。
比如,声音的强度是按照“分贝”来描述,倍数增加的音量听起来是均匀增加的。

物理反射率检测

人眼中的中度灰色的色块,其物理亮度值大于在白色块的20%左右。

python opencv做伽马矫正 opencv gamma_python opencv做伽马矫正_06


此图的原点是黑色,(1,1)是白色,你可以这么理解此图:当整体环境较暗,微小的亮度增长也会在人的心目中是显著的明度提升,当物理亮度达到白色的20%左右的时候,人心目中已经感受到了中灰色的概念。而剩下的一半高光区的灰阶,需要用白色80%的物理能量才能照亮成白色。

数字摄影和屏幕

为了把事儿说明白,我们先把8位每通道图像的数值,换算到0-1区间。8位图上0是黑,255是白,中灰色是128。换算以后,黑是0,白是1,中灰是0.5。
要注意,8位每通道图像,灰阶预算极其有限,仅有256个,如同一盒256色的灰阶蜡笔。
当我们在用数字相机拍照的时候,相当于对自然界采样,并把数据编码到图像文件中。

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

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

来到屏幕上,也就是文件解码端,此时屏幕从计算机中读到一个0-1的渐变,也就是从黑到白的均匀过渡(人眼感觉),图片如下:

python opencv做伽马矫正 opencv gamma_位图_07


其中左端的色彩值是0,中间的色彩值是128(0.5),右边是1.0的纯白。解码后,屏幕要以什么样的亮度显示这些像素呢?最左边像素关灯不显示,是黑色,中间以白色21.8%的亮度显示,右边像素全开,显示100%白色。这样的一个图片,在我们心目中看起来是均匀的灰度渐变。

此时屏幕的解码Gamma是2.2,这个Gamma,会把0.5映射成0.218。也就是说计算机中存储的图片的物理亮度的均匀递增的。
从这个角度来看。其实眼睛跟“照相机”真的挺像,我们看见自然界0.2的东西,就把它映射成0.5的地位,记到脑子里了。

总结

python opencv做伽马矫正 opencv gamma_python opencv做伽马矫正_08


总结段要说三个问题:

Gamma值2.2怎么来的

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

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

Gamma=2.2怎么来的?是实践中目测调整出来并最终确定的,其实说良心话,只要是0.5中灰对应白色的20%左右,画面看起来都是靠谱的,所以当年的Gamma特别多种多样,在2.2上下浮动(1.8-2.5),1996年微软和惠普在特定的光照条件下测试人观看显示器的感受,他们认为,把8位图像中128号灰(0.5灰)这个抽象的、代表心目中中灰色的数值,对应以白像素21.8%的亮度显示出来,由黑到白的渐变过渡看起来会比较均匀。最终对应的Gamma就是2.2。那么他们定了这个标准,后世的硬件也就都往上面靠了,包括拍照的时候,编码Gamma也就取了1/2.2=0.454。这样能保证整个编码解码系统总Gamma是1,高保真,自然界中的色值能在屏幕上相对完好的再现。

凡是说Gamma 2.2来自于老式CRT显示器物理特性的解释,都是误解。这个误解一般会这么讲解Gamma的来龙去脉:当年老式的CRT显示器内置Gamma 2.35左右,解码的时候会把输入信号压暗,所以我们呢,为了保证总Gamma接近1,就要预先在编码的时候把输入文件的信号提亮,而且这样一来呢,刚好顺应了人眼对暗部感兴趣的特点,把暗部的信息多多记录了下来,充分利用了文件的空间,真是美妙的巧合啊。但是人类就被一个老式硬件的物理特性决定了后世的工业标准?这逻辑不对。

为啥错,比如当年要是没有先发明CRT显示器呢?假设我们先发明了一个物理Gamma为1的显示器。当输入8位图像0.5的数值的时候,它还是要乖乖的把这个0.5映射成白像素的20%输出出来。否则看起来就不是中灰,8位每通道的显示器Gamma必须在2.2左右,跟显示器发展史没关系,完全是视觉效果决定的。一切都因为韦伯定律。

为什么一直强调低动态图像?这个其实涉及到“自然景象再现成画面”这样一个复杂的事情,自然界是高动态的,亮度可以非常亮,也可以有一些明亮的光源,所以我在描述中灰的物理量的时候,我不可能描述成场景中最亮的物体亮度的20%,这个最亮的概念会非常不好确定。同一个明亮的场景中,中灰纸张应该是白纸反射率的20%而不是灯泡能量的20%。我如果把高亮物体牵涉仅来,事情就乱了。但是我可以用绘画举例子,画布的动态范围是有限的,最亮不过是画布上的留白,屏幕的动态范围也是有限的,最亮不过是白像素。所以在低动态范围的语境下,我可以安全的定义,中灰蜡笔的反射率是白色蜡笔的20%左右,中灰像素的亮度是白像素亮度的20%左右,而不是现实场景中最亮物体的20%。这一点是很关键的。

另外,一切的前提必须是:灰阶预算很紧张,只有灰阶有限,我们才需要考虑中灰映射给谁的问题,如果灰阶足足的够用,硬盘不要钱了,网线足够粗,我们主流不再使用8位每通道图片记录亮度信息的话,Gamma是没必要的,我们直接把自然界的0.2记录在文件上,显示器读取到0.2,也直接显示就好了——32位每通道的hdr格式就是这样的。32位格式中,中灰就被记作0.218,所以在32位环境中拉一个0-1的渐变是这样的,很明显暗部被压缩了,高光区很多:
这张图怎么理解?它还是0-1的均匀渐变,中间那个颜色还是0.5,只不过32位图中的数值就是自然界的物理量,所以这个色带对应的其实是现实中的反射率。左边五分之一20%处是中灰色,中间的像素表现的是反射率为白色50%的物体看起来的灰度,这个灰度是0.5^0.454=73%灰。也就是8位下的186灰。具象的说,如果我有一支蜡笔反射率是50%,看起来就是中间这个灰度。

总之一句话:灰阶有限的前提下,因为人眼对自然的非线性感知特性,我们才需要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校正就会消失。自然数据不经校正直接记录为文件数据,再不经校正直接显示。