目录(?)[-]
图2中左图为原图,中图为gamma = 1/2.2在校正结果,原图中左半侧的灰度值较高,右半侧的灰度值较低,经过gamma = 1/2.2校正后(中图),左侧的对比度降低(见胡须),右侧在对比度提高(明显可以看清面容),同时图像在的整体灰度值提高。
右图为gamma = 2.2在校正结果,校正后,左侧的对比度提高(见胡须),右侧在对比度降低(面容更不清楚了),同时图像在的整体灰度值降低。
值得一提的是,人眼是按照gamma < 1的曲线对输入图像进行处理的。
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
using namespace cv;
using namespace std;
// Normalizes a given image into a value range between 0 and 255.
Mat norm_0_255(const Mat& src) {
// Create and return normalized image:
Mat dst;
switch(src.channels()) {
case 1:
cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC1);
break;
case 3:
cv::normalize(src, dst, 0, 255, NORM_MINMAX, CV_8UC3);
break;
default:
src.copyTo(dst);
break;
}
return dst;
}
int main(int argc, const char *argv[]) {
// Get filename to the source image:
if (argc != 2) {
cout << "usage: " << argv[0] << " <image.ext>" << endl;
exit(1);
}
// Load image & get skin proportions:
//Mat image = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE);
Mat image = imread(argv[1], CV_LOAD_IMAGE_COLOR);
// Convert to floating point:
Mat X;
image.convertTo(X, CV_32FC1);
//image.convertTo(X, CV_32F);
// Start preprocessing:
Mat I;
float gamma = 1/2.2;
pow(X, gamma, I);
// Draw it on screen:
imshow("Original Image", image);
imshow("Gamma correction image", norm_0_255(I));
//imwrite("origin.jpg", image);
imwrite("gamma_inv2.2.jpg", norm_0_255(I));
// Show the images:
waitKey(0);
// Success!
return 0;
}
Gamma 校正
问题:什么是Gamma曲线矫正?Gamma曲线矫正是什么意思?
Gamma曲线是一种特殊的色调曲线,当Gamma值等于1的时候,曲线为与坐标轴成45°的直线,这个时候表示输入和输出密度相同。高于1的Gamma值将会造成输出亮化,低于1的Gamma值将会造成输出暗化。总之,我们的要求是输入和输出比率尽可能地接近于1。在显示器、扫描仪、打印机等输入、输出设备中这是一个相当常见并且比较重要的概念。在计算机系统中,由于显卡或者显示器的原因会出现实际输出的图像在亮度上有偏差,而Gamma曲线矫正就是通过一定的方法来矫正图像的这种偏差的方法。一般情况下,当用于Gamma矫正的值大于1时,图像的高光部分被压缩而暗调部分被扩展,当Gamma矫正的值小于1时,图像的高光部分被扩展而暗调部分被压缩,Gamma矫正一般用于平滑的扩展暗调的细节。
图1显示的是一般CRT显示器的亮度响应曲线,可以看到其输入电压提高一倍,亮度输出并不是提高一倍,而是接近于两倍,显然这样输出的图像同原来的图像相比就发生了输出亮化的现象,也就是说未经过Gamma矫正的CRT显示器其Gamma值是小于1的。
没有经过Gamma矫正的设备会影响最终输出图像的颜色亮度,比如一种颜色由红色和绿色组成,红色的亮度为50%,绿色的亮度为25%,如果一个未经过Gamma矫正的CRT显示器的Gamma值是2.5,那么输出结果的亮度将分别为18%和3%,其亮度大大的降低了。
图2 按图进行曲线补偿
为了补偿这方面的不足,我们需要使用反效果补偿曲线来让显示器尽可能地输出同输入图像相同的图像,所以这个时候显示器的输入信号应该按照图2所示的曲线进行补偿,这样才能在显示器上得到比较理想的输出结果。
一般的反效果可以直接被赋予存储在帧缓存中的图像,使之Gamma曲线呈非线性,也可以通过RAMDAC进行这种反效果补偿(或者说是Gamma曲线矫正)。这样我们就可以在显示器上看到同我们输入的图像接近的图像了(如图3)。当然图3所示的曲线只是理想状态下的情况,在实际应用中我们并不可能得到如此完美的曲线,所以不同的厂商之间所竞争的就是谁能做到最接近于这个效果。
显示器的gamma值是用于定义一个显示器的显示特性的数学方法,是决定显示器从黑色到白色的值。简单的说,当显示一个颜色从黑到白时(也就是0到1),显示器的电压也要随之变化,但这个变化不是线性的。因为显示器的物理特性决定了如果电压的变化是线性的,显示出来的亮度就不是线性的,这时,显示的亮度就会很暗。所以,为了保整显示出来的亮度是正常(线性)的,就需要对显示器的电压变化加以校正,这个值就是我们通常所说的gamma值。通常情况只有在调整HDRI图片时和在做动画渲染时会用到。
γ校正(Gamma Correction,伽玛校正):所 谓伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比 度效果。计算机绘图领域惯以此屏幕输出电压与对应亮度的转换关系曲线,称为伽玛曲线(Gamma Curve)。以传统CRT(Cathode Ray Tube)屏幕的特性而言,该曲线通常是一个乘幂函数,Y=(X+e)γ,其中,Y为亮度、X为输出电压、e为补偿系数、乘幂值(γ)为伽玛值,改变乘幂 值(γ)的大小,就能改变CRT的伽玛曲线。典型的Gamma值是0.45,它会使CRT的影像亮度呈现线性。使用CRT的电视机等显示器屏幕,由于对于 输入信号的发光灰度,不是线性函数,而是指数函数,因此必需校正。
在电视和图形监视器中,显像管发生的电子束及其生成的图像亮度并不是随显像管的输入电压线性变化,电子流与输入电压相比是按照指数曲线变化的,输入 电压的指数要大于电子束的指数。这说明暗区的信号要比实际情况更暗,而亮区要比实际情况更高。所以,要重现摄像机拍摄的画面,电视和监视器必须进行伽玛补 偿。这种伽玛校正也可以由摄像机完成。我们对整个电视系统进行伽玛补偿的目的,是使摄像机根据入射光亮度与显像管的亮度对称而产生的输出信号,所以应对图 像信号引入一个相反的非线性失真,即与电视系统的伽玛曲线对应的摄像机伽玛曲线,它的值应为1/γ,我们称为摄像机的伽玛值。电视系统的伽玛值约为 2.2,所以电视系统的摄像机非线性补偿伽玛值为0.45。彩色显像管的伽玛值为2.8,它的图像信号校正指数应为1/2.8=0.35,但由于显像管内 外杂散光的影响,重现图像的对比度和饱和度均有所降低,所以现在的彩色摄像机的伽玛值仍多采用0.45。在实际应用中,我们可以根据实际情况在一定范围内 调整伽玛值,以获得最佳效果。
今天有个朋友问γ校正的用处,这里简单说一下:
伽马校正最初是由于显示器的阴极现象管(也就是物理上所说的示波管的阴极射线版)的成像扭曲引起的,为了不使画面失真所以就用先特殊算法进行校正,此之谓γ校正。
γ校正的原理是修改显示系统的配色方案,本来显示系统输出的r g b电子枪线性的根据显存中的各个颜色值输出对应的控制电压,但是通过伽码校正可以把某个颜色值对应的输出电压调整高或调整低。达到校正显示系统色泽的目的。同时可以用软件的方法校正,就是对一副图片设定某个颜色的颜色值变换成新的颜色值的对照表,然后用新的颜色值取代原来图片中对应的颜色就行了呀。比如你先编写一个控制rgb各个分量对应关系的曲线调节器,在曲线调节器里面调整控制曲线设置原来颜色多少对应目标颜色多少,然后根据设定的关系,修改要调整色泽的图片每一个像素的颜色就可以了。
数学公式可以深刻和精确的把握一个概念,却不能表达概念的物理意义和本质含义,本贴试图摆脱数学公式的陈述和推导,用言语来解释gamma的本质含义。