伽马(Gamma)校正原理及Matlab/C++代码实现

在图像处理中,gamma校正是重要的环节,它会对每个像素的亮度做非线性调整,从而让大家主观上得到一张令人满意、更加舒服的照片。

什么是gamma矫正

gamma校正是一种图像亮度非线性变化的调整过程,而最终图像的原始亮度与输出亮度为指数关系,即

其中: Vin为输入亮度值,Vout为输出亮度值,γ为gamma大小

一般我们常说的1/2.2或2.2为上述公式中γ的大小。

如下图:横坐标为输入灰度值,纵坐标为输出的灰度值,三条曲线分别代表了gamma为1,1/2.2,2.2的输入输出关系

  1. gamma  =  1:图像整体亮度经过gamma后不做调整
  2. gamma  >  1:图像整体亮度经过gamma后降低
  3. 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

谢谢观看

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值