美文网首页
图形图像处理算法(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