gamma correction是什么
在看传统cv的时候遇到几个比较有意思的之前不了解的东西,比如gamma correction,gamma是几乎所有数字成像系统中都很重要但很少被人理解的概念,它定义了像素的数值与其实际亮度之间的关系。了解gamma如何工作对于任何想要从事图像相关工作的人应该都是必要的。
以下是维基百科上的解释:
伽马校正(Gamma correction) 又叫伽马非线性化(gamma nonlinearity)、伽马编码(gamma encoding) 或是就只单纯叫伽马(gamma)。是用来针对影片或是影像系统里对于光线的辉度(luminance)或是三色刺激值(tristimulus values)所进行非线性的运算或反运算。最简单的例子里伽马校正是由下列幂定律公式所定义的:
$$ V_{out}=A{{V_{in}}^{\gamma }} $$
其中A是一个常量,输入和输出的值都为非负实数值。一般地来说在A=1的通常情况下,输入输出的值的范围都是在0到1之间。伽马值γ < 1的情况有时被称作编码伽马值(encoding gamma),而执行这个编码运算所使用上述幂定律的过程也叫做伽马压缩(gamma compression);相对地,伽马值γ > 1的情况有时也被称作解码伽马值(decoding gamma),而执行这个解码运算所使用上述幂定律的过程也叫做“伽马展开(gamma expansion)”。
为图像进行伽马编码的目的是用来对人类视觉的特性进行补偿,从而根据人类对光线或者黑白的感知,最大化地利用表示黑白的数据位或带宽。在通常的照明(既不是漆黑一片,也不是令人目眩的明亮)的情况下,人类的视觉大体有伽马或者是幂函数的性质。如果不将图像进行伽马编码,那么数据位或者带宽的利用就会分布不均匀——会有过多的数据位或者带宽用来表示人类根本无法察觉到的差异,而用于表示人类非常敏感的视觉感知范围的数据位或者带宽又会不足。图像的伽马编码并不是必须的(甚至有的时候会适得其反),浮点数格式的颜色值已经提供了一部分对数曲线的线性估计。
gamma的用途
1、当使用数码相机时,假如光子数量达到传感器的两倍,它会接收两倍的信号(线性关系)但由于我们的眼睛不像摄像机那样感知光线,因此,当光的强度为两倍时,肉眼感受到的亮度并没有增加两倍那么多, 而且光照越强这种现象越越明显(呈非线性关系)。
由下图可知,与相机相比,我们对暗色调的变化更敏感,从生物学上说,它使我们的视觉能够在更广泛的亮度范围内工作,这样在大部分都是白天的情况下有更好的适应能力。这些与gamma有什么关系呢? Gamma的目的其实是实现我们的眼睛的光敏感度和相机的光敏感之间的转换。 当保存数字图像时,它被“gamma编码” ,这样使得文件中两倍的光强更接近于我们认为的两倍亮度。
输入和检测对比
2、gamma编码图像能有效地存储色彩。 由于gamma编码重新分配色彩的级别,使其更接近肉眼的感知方式,因此只需更少的比特来描述给定的色彩范围。 否则,将使用多余的比特来描述更亮的色调(相机相对更敏感),并直接导致用来描述暗色调的比特数量不足(相机相对人眼较不敏感):
原始图片
线性编码
gamma编码
注意线性编码那张图片,可以看到在暗色调部分用来描述的级别不够,这也导致了描述亮色调的级别过多。同时,gamma编码的图片在整个范围的色调大致均匀地分布,这也确保了后续的图像编辑,颜色和直方图都基于自然的,感知上均匀的色调。
gamma的工作流:encoding和correction
尽管有很多优点,但gamma编码确实使得记录和显示图像的整个过程复杂化了。 下一步是大多数人都感到困惑的,所以慢慢来说。首先gamma encoding后的图像在观看时必须应用“伽马correction”,这能有效地将其转换回原始场景的光。 换句话说,gamma encoding的目的是用于记录图像,而不是用于显示图像。不过有个好消息是,第二步(显示gamma)由显示器和视频卡自动执行。 下图展示了这些过程如何组合:
1.图像gamma。无论何时将捕获的图像转换为标准JPEG或TIFF文件,都可以通过相机或RAW开发软件应用此功能。它将相机的色调级别重新分配为更均匀的级别,从而最有效地利用给定的位深度。
2.显示gamma。这是指显卡和显示设备的影响,因此它实际上可能包含几个gamma。显示器gamma的主要目的是补偿文件的gamma值 - 从而确保在屏幕上显示时图像不会变得不切实际。较高的显示伽玛会导致图像较暗,对比度较高。
3.系统gamma。这表示已应用于图像的所有gamma值的净效应,也称为“观看gamma”。为了忠实地再现场景,理想情况下应该接近直线(伽马= 1.0)。直线确保输入(原始场景)与输出(屏幕上或打印显示的灯光)相同。但是,系统gamma有时会设置为略大于1.0,以提高对比度,这可以补偿由于显示设备的限制,或者由于观看条件和图像闪光而引起的问题。
下面推荐两篇文章:
知乎上的一篇
一篇英文的,这篇博客也是参照这个来写的
下面是自己网上找的图片实现的效果和代码
原图
gamma1/1.7
import cv2
img_dark = cv2.imread(path)
cv2.imshow('img_dark', img_dark)
key = cv2.waitKey(0)
cv2.destroyAllWindows()
def gamma_correction(image, inv_gamma=1.0):
table = []
for i in range(256):
table.append(((i / 255.0) ** inv_gamma) * 255)
table = np.array(table).astype("uint8")
return cv2.LUT(img_dark, table)
img_brighter = gamma_correction(img_dark, 1/1.7)
cv2.imshow('img_dark', img_dark)
cv2.imshow('img_brighter', img_brighter)
cv2.imwrite(path, img_brighter)
key = cv2.waitKey(0)
cv2.destroyAllWindows()