OpenCV Gamma 校正原理和功能实现

1.什么是Gamma校正

Gamma校正是对输入图像灰度值进行的非线性操作,使输出图像灰度值与输入图像灰度值呈指数关系:

OpenCV Gamma 校正原理和功能实现

这个指数即为Gamma.

经过Gamma校正后的输入和输出图像灰度值关系如图1所示,

OpenCV Gamma 校正原理和功能实现

Gamma 校正提供了一种输出非线性的映射机制。Gamma 值在 0.5 ~ 1 之间,图像暗处亮度提升,同时低灰度处的对比度得到增加,更利于分辨低灰度值时的图像细节;Gamma 值在 1 ~ 4 之间时,图像暗处亮度下降。

///////////////////////////////////

OpenCV Gamma 校正原理和功能实现

2.为什么进行Gamma校正

2.1 为方便人眼辨识图像

人眼对外界光源的感光值与输入光强不是呈线性关系的,而是呈指数型关系的。在低照度下,人眼更容易分辨出亮度的变化,随着照度的增加,人眼不易分辨出亮度的变化。而摄像机感光与输入光强呈线性关系。如图2所示:

OpenCV Gamma 校正原理和功能实现

人眼和摄像机的感光与实际输入光强的关系

为方便人眼辨识图像,需要将摄像机采集的图像进行gamma校正。

2.2 为能更有效地保存图像亮度信息

未经Gamma校正和经过Gamma校正保存图像信息如下图所示:

OpenCV Gamma 校正原理和功能实现

未经Gamma校正和经过Gamma校正保存图像信息

可以观察到,未经Gamma校正的情况下,低灰度时,有较大范围的灰度值被保存成同一个值,造成信息丢失;同时高灰度值时,许多比较接近的灰度值却被保存成不同的值,造成空间浪费。经过Gamma校正后,改善了存储的有效性和效率。

3.OpenCV 实现Gamma 校正

前面对Gamma变换的介绍,我们知道了 通过Gamma变换,可以调整图像的亮度,设置Gamma值,可以使图像变亮/暗。下面我们通过代码实现来演示一下效果。

OpenCV 的Gamma 变换的实现与LUT查找表的关联性很大,需要借助数学公式转换,这个可以了解一下。

unsigned char LUT[256];
for (int i = 0; i < 256; i++)
{
float f = (i + 0.5f) / 255;
f = (float)(pow(f, kFactor));
LUT[i] = saturate_cast<uchar>(f*255.0f - 0.5f);
}

LUT
就是指显示查找表(Look-Up-Table),LUT(Look-Up Table)实际上就是一张像素灰度值的映射表,它将实际采样到的像素灰度值经过必定的变换,如阈值、反转、二值化、对比度调整、线性变换等,变成了另外一个与之对应的灰度值,这样可以起到突出图像的有用信息,增强图像的光对比度的作用。
LUT(src, lut, dst);

OpenCV 实现Gamma 校正参考如下实现代码,

///////////////////Gamma 变换
#include <opencv2corecore.hpp>
#include <opencv2highguihighgui.hpp>
#include <opencv2imgprocimgproc.hpp>
#include<cmath>
/*
参数1 Mat srcImage,输入图像
参数2 Gamma系数的倒数
返回值:通过Gamma 变换返回的图像
*/
Mat gammaTransform(Mat &srcImage, float kFactor)
{
unsigned char LUT[256];
for (int i = 0; i < 256; i++)
{
float f = (i + 0.5f) / 255;
f = (float)(pow(f, kFactor));
LUT[i] = saturate_cast<uchar>(f*255.0f - 0.5f);
}
Mat resultImage = srcImage.clone();
if (srcImage.channels() == 1)
{
/////////灰度图
MatIterator_<uchar> iterator = resultImage.begin<uchar>();
MatIterator_<uchar> iteratorEnd = resultImage.end<uchar>();
for (; iterator != iteratorEnd; iterator++)
{
*iterator = LUT[(*iterator)];
}
}
else
{
//////////彩色图
MatIterator_<Vec3b> iterator = resultImage.begin<Vec3b>();
MatIterator_<Vec3b> iteratorEnd = resultImage.end<Vec3b>();
for (; iterator != iteratorEnd; iterator++)
{
(*iterator)[0] = LUT[((*iterator)[0])];//b
(*iterator)[1] = LUT[((*iterator)[1])];//g
(*iterator)[2] = LUT[((*iterator)[2])];//r
}
}
return resultImage;
}
int main()
{
Mat srcImage = imread("corridor.jpg");
if (!srcImage.data)
{
printf("could not load image...
");
return -1;
}
//取两种不同的gamma值
float gamma1 = 3.33f;
float gamma2 = 0.33f;
float kFactor1 = 1 / gamma1;
float kFactor2 = 1 / gamma2;
Mat result1 = gammaTransform(srcImage, kFactor1);
Mat result2 = gammaTransform(srcImage, kFactor2);
imshow("srcImage", srcImage);
imshow("result1", result1);
imshow("result2", result2);
waitKey(0);
return 1;
}

效果图:

OpenCV Gamma 校正原理和功能实现

原图

Gamma=4.0 的效果图,

OpenCV Gamma 校正原理和功能实现

Gamma=0.25的效果图,

OpenCV Gamma 校正原理和功能实现

从效果图可以看出经过Gamma变换的图像可以明显的改变图像的亮度并增强对比度。这种处理方法在处理比较暗的图像时效果更明显。

End

© 版权声明

相关文章

暂无评论

none
暂无评论...