在图像处理中,gamma校正是重要的环节,它会对每个像素的亮度做非线性调整,从而让大家主观上得到一张令人满意、更加舒服的照片。
什么是gamma矫正
gamma校正是一种图像亮度非线性变化的调整过程,而最终图像的原始亮度与输出亮度为指数关系,即
其中: Vin为输入亮度值,Vout为输出亮度值,γ为gamma大小
一般我们常说的1/2.2或2.2为上述公式中γ的大小。
如下图:横坐标为输入灰度值,纵坐标为输出的灰度值,三条曲线分别代表了gamma为1,1/2.2,2.2的输入输出关系
- gamma = 1:图像整体亮度经过gamma后不做调整
- gamma > 1:图像整体亮度经过gamma后降低
- gamma < 1:图像整体亮度经过gamma后提高
相关的matlab代码实现:
y1 = 1/2.2;
Vin = (0:255);
plot(Vin,'DisplayName', 'gamma = 1');
legend
hold on
%归一化
Vin = Vin / 255;
%计算输出值
Vout = (Vin.^y1) * 255;
plot(Vout,'DisplayName', 'gamma = 1/2.2');
hold on
y2 = 2.2;
%计算输出值
Vout = (Vin.^y2) * 255;
plot(Vout,'DisplayName', 'gamma = 2.2');
xlim([0 255])
ylim([0 255])
xlabel('input')
ylabel('output')
如下图为不同gamma对应的图像亮度,中间gamma = 1的图像为原图亮度。
![]() | ![]() | ![]() |
gamma = 2.2 |
gamma = 1 |
gamma = 1/2.2 |
y1 = 1/2.2;
y2 = 2.2;
img = imread('C:\Users\Desktop\gray.jpg');
gamma_1_22 = img;
gamma_1 = img;
gamma_22 = img;
m = size(img);
height = m(1);
width = m(2);
for i = 1:height
for j = 1:width
gamma_1_22(i,j) = ((double(gamma_1_22(i,j))/255).^y1)*255;
gamma_1(i,j) = ((double(gamma_1(i,j))/255).^1)*255;
gamma_22(i,j) = ((double(gamma_22(i,j))/255).^y2)*255;
end
end
为什么要进行gamma校正
早期,CRT(阴极射线管)几乎是唯一的显示设备,CRT显示设备的工作机制基于真空电子束技术,核心原理是利用高速电子束轰击屏幕内表面的荧光粉涂层,使其发光形成图像。
输入电压的变化,会对高速电子束造成一定的影响,从而影响了图像的亮度。然而,人们发现这种显示设备的输入电压和显示亮度并非线性关系,典型的CRT显示器的伽马曲线大致是一个伽马值为2.2的幂律曲线。显示器端的伽马被叫做display gamma。由于display gamma的存在,图像的采集设备就需要做伽马校正,这类伽马被叫做encoding gamma。所以,我们从显示设备中看到的图像其实经过了两次伽马。
如下图所示:
encoding gamma:反应了在图像采集设备拿到图像后,真实场景与编码后亮度关系
display gamma:反映了编码与显示的亮度关系
而encoding gamma与display gamma的乘积为1,则显示亮度与真实场景的亮度是成比例的。
到这里,相信大家就明白了做伽马校正的原因,个人理解,其实就是为了补偿由于display gamma造成的图像亮度差异,从而使得我们看到的图像更符合真实场景的亮度关系。
现如今的OLED与液晶显示器(LCD)的伽马(Gamma)值普遍采用 2.2 作为标准目标值。这一设定源于人类视觉系统对亮度的非线性感知特性(韦伯-费希纳定律),即人眼对暗部亮度变化更敏感,而对亮部变化较迟钝。
因我们现在看到的图像大部分为彩色图像,此外还做了RGB gamma的C++代码:
以下为基于灰度图像做不同的gamma的效果图:
![]() | ![]() | ![]() |
gamma = 2.2 |
gamma = 1 |
gamma = 1/2.2 |
以下为RGB图像做RGB gamma的效果图:
| ||
gamma = 2.2 |
gamma = 1 |
gamma = 1/2.2 |
//定义枚举类型
enum gamma_type{
NONE_GAMMA = 0,
RGB_GAMMA
};
void gamma_convert(Mat& src,Mat& dst,enum gamma_type type,float gamma_value){
int channel = src.channels();
int height = src.rows;
int width = src.cols;
if(channel == 1){
for(int y = 0;y < height;y++){
for(int x = 0;x < width;x++){
dst.at<uchar>(y,x) = pow((src.at<uchar>(y,x) * 1.0 / (255.0)),gamma_value) * 255;
}
}
}else if(type == RGB_GAMMA){
for(int y = 0;y < height;y++){
for(int x = 0;x < width;x++){
dst.at<Vec3b>(y,x)[0] = pow((src.at<Vec3b>(y,x)[0] * 1.0 / (255.0)),gamma_value) * 255;
dst.at<Vec3b>(y,x)[1] = pow((src.at<Vec3b>(y,x)[1] * 1.0 / (255.0)),gamma_value) * 255;
dst.at<Vec3b>(y,x)[2] = pow((src.at<Vec3b>(y,x)[2] * 1.0 / (255.0)),gamma_value) * 255;
}
}
}
}
参考链接:https://blog.youkuaiyun.com/candycat1992/article/details/46228771
谢谢观看