伽马校正(Gamma correction) 又叫伽马非线性化(gamma nonlinearity)、伽马编码(gamma encoding) 或是就只单纯叫伽马(gamma)。是用来针对影片或是影像系统里对于光线的辉度(luminance)或是三色刺激值(tristimulus values)所进行非线性的运算或反运算。
*
1、公式
其中A是一个常量,输入和输出的值都为非负实数值。一般地来说在A=1的通常情况下,输入输出的值的范围都是在0到1之间。伽马值γ < 1的情况有时被称作编码伽马值(encoding gamma),而执行这个编码运算所使用上述幂定律的过程也叫做伽马压缩(gamma compression);相对地,伽马值γ > 1的情况有时也被称作解码伽马值(decoding gamma),而执行这个解码运算所使用上述幂定律的过程也叫做“伽马展开(gamma expansion)”。
2、解释
为图像进行伽马编码的目的是用来对人类视觉的特性进行补偿,从而根据人类对光线或者黑白的感知,最大化地利用表示黑白的数据位或带宽。在通常的照明(既不是漆黑一片,也不是令人目眩的明亮)的情况下,人类的视觉大体有伽马或者是幂函数的性质。如果不将图像进行伽马编码,那么数据位或者带宽的利用就会分布不均匀——会有过多的数据位或者带宽用来表示人类根本无法察觉到的差异,而用于表示人类非常敏感的视觉感知范围的数据位或者带宽又会不足。图像的伽马编码并不是必须的(甚至有的时候会适得其反),浮点数格式的颜色值已经提供了一部分对数曲线的线性估计。γ校正(Gamma Correction,伽玛校正):所 谓伽玛校正就是对图像的伽玛曲线进行编辑,以对图像进行非线性色调编辑的方法,检出图像信号中的深色部分和浅色部分,并使两者比例增大,从而提高图像对比 度效果。
3、详解
1、什么是Gamma曲线矫正?
Gamma曲线矫正是什么意思?Gamma曲线是一种特殊的色调曲线,当Gamma值等于1的时候,曲线为与坐标轴成45°的直线,这个时候表示输入和输出密度相同。高于1的Gamma值将会造成输出亮化,低于1的Gamma值将会造成输出暗化。总之,我们的要求是输入和输出比率尽可能地接近于1。在显示器、扫描仪、打印机等输入、输出设备中这是一个相当常见并且比较重要的概念。在计算机系统中,由于显卡或者显示器的原因会出现实际输出的图像在亮度上有偏差,而Gamma曲线矫正就是通过一定的方法来矫正图像的这种偏差的方法。一般情况下,当用于Gamma矫正的值大于1时,图像的高光部分被压缩而暗调部分被扩展,当Gamma矫正的值小于1时,图像的高光部分被扩展而暗调部分被压缩,Gamma矫正一般用于平滑的扩展暗调的细节。
2、Gamma 矫正代码
1 #include <opencv2/core/core.hpp> 2 #include <opencv2/imgproc/imgproc.hpp> 3 #include <opencv2/imgproc/types_c.h> 4 #include <opencv2/highgui/highgui.hpp> 5 #include <opencv2/highgui/highgui_c.h> 6 #include <opencv2/highgui.hpp> 7 #include <opencv2/calib3d.hpp> 8 #include <iostream> 9 10 using namespace cv; 11 using namespace std; 12 13 void GammaCorrection(Mat& src, Mat& dst, float fGamma) 14 { 15 unsigned char lut[256]; 16 for (int i = 0; i < 256; i++) 17 { 18 lut[i] = saturate_cast<uchar>(pow((float)(i / 255.0), fGamma) * 255.0f); 19 } 20 21 dst = src.clone(); 22 const int channels = dst.channels(); 23 switch (channels) 24 { 25 case 1: 26 { 27 28 MatIterator_<uchar> it, end; 29 for (it = dst.begin<uchar>(), end = dst.end<uchar>(); it != end; it++) 30 * it = lut[(*it)]; 31 32 break; 33 } 34 case 3: 35 { 36 37 MatIterator_<Vec3b> it, end; 38 for (it = dst.begin<Vec3b>(), end = dst.end<Vec3b>(); it != end; it++) 39 { 40 (*it)[0] = lut[((*it)[0])]; 41 (*it)[1] = lut[((*it)[1])]; 42 (*it)[2] = lut[((*it)[2])]; 43 } 44 45 break; 46 47 } 48 default: 49 break; 50 } 51 } 52 53 int main() 54 { 55 Mat image = imread("D://Images/wrong/2.jpg"); 56 if (image.empty()) 57 { 58 cout << "Error: Could not load image" << endl; 59 return 0; 60 } 61 Mat dst; 62 float fGamma = 1 / 1.8; 63 GammaCorrection(image, dst, fGamma); 64 imwrite("D://Images/wrong/24.jpg", dst); 65 waitKey(); 66 67 return 0; 68 }
1 package org.jaiken.tools; 2 3 import org.opencv.core.Core; 4 import org.opencv.core.CvType; 5 import org.opencv.core.Mat; 6 import org.opencv.imgcodecs.Imgcodecs; 7 8 public class GammaCorrection { 9 // 伽马校正 10 public Mat gamma(Mat src) { 11 Mat x = new Mat(); 12 src.convertTo(x, CvType.CV_32FC3); 13 Mat i = new Mat(); 14 15 Core.pow(x, 1/1.8, i); 16 Mat dst = new Mat(); 17 // 归一化 18 Core.normalize(i, dst, 0, 255, Core.NORM_MINMAX, 0); 19 Imgcodecs.imwrite("D://Images/wrong/22.jpg", dst); 20 return dst; 21 } 22 23 public static void main(String[] args) { 24 System.load("D://Export/opencv_java320.dll"); 25 Mat src = Imgcodecs.imread("D://Images/wrong/2.jpg",0); 26 if (src.empty()) { 27 System.err.println("The picture doesn't exist"); 28 return; 29 } 30 GammaCorrection gammaCorrection = new GammaCorrection(); 31 gammaCorrection.gamma(src); 32 } 33 34 }
效果图
这样还仅能看出图像亮度上的变化,体会不到细节上的变化,这样用阈值化和Blob 分析的方法检测下两张图像,结果图如下。
结果很明显的第四列,第五行的图像细节上更加清楚,处理结果更加的的好,而没有了图像上"线"的干扰。