美文网首页
图形图像处理算法(2)---- Gamma 校正及算法实现

图形图像处理算法(2)---- Gamma 校正及算法实现

作者: 特立独行的佩奇 | 来源:发表于2021-11-06 10:43 被阅读0次

    什么是Gamma 校正

    Gamma 是指灰度系数,是显示设备都有的一种指标,每种显示设备都不一样,会影响输出设备的亮度:
    显示设备输出亮度 = 电压的Gamma次幂

    使用 gamma 校正有下面两个原因:

    • 显示设备的亮度的非线性特性
      输出的亮度和输入的电压并非线性关系,而是近似 2.2 次幂的关系,导致进入人眼的亮度要比计算机上存储的亮度要低
      例如:计算机上存储的亮度为 0.5,经过显示器调整后变为 0.5 的 2.2 次幂,即 0.218。为了让进入人眼的亮度与计算机中存储的值相同,需要在显示器调整前将亮度变为自身的 1/2.2 次幂,即 0.73,这样在经过显示器的调整,进入人眼就是 0.5 了,2.2 这个值是一个近似值,或者可以说是一个标准,实际上不同的显示器可能会有不同

    • 人眼对不同亮度的敏感性不同
      人眼对暗部的敏感要高于亮部, 也就是非线性的,但是我们存储计算机颜色的空间是有限的,比如常见的有ARGB8888 格式,如果直接到显示设备上显示,会损失较多的暗部细节,所以需要我们对输入的内容做gamma 变换,可以展示更多的暗部细节,有更好的显示效果。

    Gamma 校正算法

    Gamma 校正公式:

    f(I) = I^gamma

    自变量 #I 是颜色像素值归一化后的值,区间分为是从0 到 1, 归一化通过下面的公式就可以实现:
    归一化后的像素值 = 当前像素值 / 像素的最大值

    不同gamma 值的函数曲线如下:


    gamma_fx.png
    • 当 gamma = 1 的时候,输出值等于输入值,只会有原图的显示效果
    • 当 gamma 大于1 的时候,如图中的黄色线所示,低灰度区域的动态值变小,高灰度区域的动态值变大,降低了低灰度区域图像的对比度,提高了高灰度值区域图像的对比度, 图像整体变暗。
    • 当 gamma 小于1 的时候,低灰度区域的动态值变大,进而图像对比度增强,高灰度值区域,动态值变小,图像整体变亮。

    显示效果如下:


    gamma_lessthan1.png gamma_greatherthan1.png

    Gamma 校正的LUT实现

    gamma 校正的公式涉及到指数运算,在实际应用中效率太低,需要优化;
    可以使用查找表(LUT)法,输入的像素值的范围是有限的 一般为[0,255], 在 gamma 值 已知的情况下 ,0 ~ 255 之间的任一整数 , 经过归一 化、预补偿、反归一化操作后 , 所对应的结果是唯一的 , 并且也落在 0 ~ 255 这个范围内;
    如果可以预先建立一张表,使得每个输入的像素值都有唯一的gamma 校正后输出像素值对应,就可以大大降低运算量;

    1DLUT.png

    使用LUT实现Gamma 校正的C++ 代码

    #include <iostream>
    #include <opencv2/opencv.hpp>
    
    using namespace std;
    using namespace cv;
    
    // 存储 gamma LUT 的数组
    uint8_t gammaLUT[256] = { 0 };
    
    void _gammaCorrection(Mat& src, Mat& dst, float K)
    {
        src.copyTo(dst);
        for (int i = 0; i < 256; i++) {
            float f = i / 255.0f; // 注意不可以写成 i / 255
            f = pow(f, K);
            gammaLUT[i] = static_cast<uint8_t>(f*255.0);
        }
    
        if (dst.channels() == 1) {
            MatIterator_<uint8_t> it = dst.begin<uint8_t>();
            MatIterator_<uint8_t> it_end = dst.end<uint8_t>();
            for (; it != it_end; it++)
            {
                *it = gammaLUT[*it];
            }
    
        } else {
            cout << "dst image channel" << dst.channels() << endl;
            MatIterator_<Vec3b> it = dst.begin<Vec3b>();
            MatIterator_<Vec3b> it_end = dst.end<Vec3b>();
    
            for (; it != it_end; it++)
            {
                (*it)[0] = gammaLUT[(*it)[0]];
                (*it)[1] = gammaLUT[(*it)[1]];
                (*it)[2] = gammaLUT[(*it)[2]];
            }
    
        }
    }
    
    bool testGammaCorrection()
    {
        cout << "gamma correection demo" << endl;
        const char *ImageName = "C:/Users/86185/Documents/Visual Studio 2015/Projects/opencvdemo/x64/Debug/demoImage.png";
        Mat img = imread(ImageName, 1);
        if (img.empty()) {
            cout << "read image empty" << endl;
            return false;
        }
    
        Mat dstimg;
        _gammaCorrection(img, dstimg, 1/2.2);
    
    
        imshow("src_image", img);
        imshow("dst_image", dstimg);
    
        return true;
    }
    
    Review History
    日期 说明
    2022/10/1 修正部分格式
    NA NA

    相关文章

      网友评论

          本文标题:图形图像处理算法(2)---- Gamma 校正及算法实现

          本文链接:https://www.haomeiwen.com/subject/vqxjzltx.html