Gamma原理及快速实现算法(C/C++)(转)

时间:2021-11-08 23:31:35

源:Gamma原理及快速实现算法(C/C++)

原文:http://blog.csdn.net/lxy201700/article/details/24929013

参考

http://www.cambridgeincolour.com/tutorials/gamma-correction.htm

http://en.wikipedia.org/wiki/Gamma_correction

论文Gamma矫正的快速算法以及其C语言实现

一、什么是Gamma校正

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

[2]   A是一个常数,通常取1,这个指数即为Gamma

经过Gamma校正后的输入和输出图像灰度值关系如图1所示:横坐标是输入灰度值,纵坐标是输出灰度值,蓝色曲线是gamma值小于1时的输入输出关系,红色曲线是gamma值大于1时的输入输出关系。可以观察到,当gamma值小于1时(蓝色曲线),图像的整体亮度值得到提升,同时低灰度处的对比度得到增加,更利于分辩低灰度值时的图像细节。

图一Gamma校正后的输入和输出图像灰度值关系图

Gamma原理及快速实现算法(C/C++)(转)

 

Gamma原理及快速实现算法(C/C++)(转)

上图是不同gamma值对应图像亮度的变化

二、为什么进行Gamma校正?

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

Gamma原理及快速实现算法(C/C++)(转)

 

图2 人眼和摄像机的感光与实际输入光强的关系[1]。

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

2. 为能更有效的保存图像亮度信息,需进行Gamma校正。

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

Gamma原理及快速实现算法(C/C++)(转)

 

图3 未经gamma校正和经过gamma校正保存图像信息.

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

3.gamma叠加的影响

Gamma原理及快速实现算法(C/C++)(转)

 

如图所示对于一个标准的伽玛编码的图像文件(一),改变显示的γ(— )将因此具有以下的总体影响(— )的图像上。

三、Gamma矫正的原理

假设图像中有一个像素,值是200,那么对这个像素进行校正必须执行如下步骤。

1.归一化:将像素值转换为 0~1 之间的实数。 算法如下: ( i + 0. 5)/256 这里包含1个除法和1个加法操作。对于像素 A 而言 ,其对应的归一化值为 0. 783203。

2.预补偿:根据公式Gamma原理及快速实现算法(C/C++)(转) ,求出像素归一化后的 数据以 1/gamma 为指数的对应值。这一步包含一个 求指数运算。若 gamma 值为 2. 2 , 则 1/gamma 为 0. 454545 ,对归一化后的 A 值进行预补偿的结果就 是 0. 783203^0. 454545 = 0. 894872。

3.反归一化:将经过预补偿的实数值反变换为 0 ~ 255 之间的整数值。具体算法为: f*256 - 0. 5 此步骤包含一个乘法和一个减法运算。续前 例 ,将 A 的预补偿结果 0. 894872 代入上式 ,得到 A 预补偿后对应的像素值为 228 ,这个 228 就是最后送 入显示器的数据。

如上所述如果直接按公式编程的话,假设图像的分辨率为800*600,对它进行gamma校正,需要执行48万个浮点数乘法、除法和指数运算。效率太低,根本达不到实时的效果。

针对上述情况,提出了一种快速算法,如果能够确知图像的像素取值范围 ,例如 , 0~255之间的整数 ,则图像中任何一个像素值只能 是 0 到 255 这 256 个整数中的某一个;在 gamma值 已知的情况下 ,0~255 之间的任一整数 ,经过“归一 化、预补偿、反归一化”操作后,所对应的结果是唯一的 ,并且也落在 0~255 这个范围内。如前例 ,已知 gamma 值为 2. 2 ,像素 A 的原始值是 200 ,就可求得 经 gamma 校正后 A 对应的预补偿值为 228。基于上述原理 ,我们只需为 0~255 之间的每个整数执行一次预补偿操作 ,将其对应的预补偿值存入一个预先建立的 gamma 校正查找表(LUT:Look Up Table) ,就可以使用该表对任何像素值在 0~255 之 间的图像进行 gamma 校正。

C语言程序:

#include <math.h>

typedef unsigned char UNIT8; //用 8 位无符号数表示 0~255 之间的整数
UNIT8 g_GammaLUT[];//全局数组:包含256个元素的gamma校正查找表
//Buildtable()函数对0-255执行如下操作:
//①归一化、预补偿、反归一化;
//②将结果存入 gamma 查找表。
//从公式得fPrecompensation=1/gamma
void BuildTable(float fPrecompensation )
{
int i;
float f;
for( i=;i<;i++)
{
f=(i+0.5F)/;//归一化
f=(float)pow(f,fPrecompensation);
g_GammaLUT[i]=(UNIT8)(f*-0.5F);//反归一化
}
} void GammaCorrectiom(UNIT8 src[],int iWidth,int iHeight,float fGamma,UNIT8 Dst[])
{
int iCols,iRows;
BuildTable(/fGamma);//gamma校正查找表初始化
//对图像的每个像素进行查找表矫正
for(iRows=;iRows<iHeight;iRows++)
{
for(iCols=;iCols<iWidth;iCols++)
{
Dst[iRows*iWidth+iCols]=g_GammaLUT[src[iRows*iWidth+iCols]];
}
}
}

四、利用OpenCV实现的Gamma校正

#include <opencv\cv.h>
#include <opencv\highgui.h>
#include <iostream> using namespace cv; //下面的所有cv相关类型不用加上前缀了 int main(int argc, char* argv[])
{
Mat img = imread(argv[]);
Mat& src=img;
Mat& MyGammaCorrection(Mat& src, float fGamma);
if(!img.data)
return -;
float fGamma=/2.2;
MyGammaCorrection(img, fGamma);
namedWindow("dst", CV_WINDOW_AUTOSIZE);
imshow("dst",src);
waitKey();
return ;
} Mat& MyGammaCorrection(Mat& src, float fGamma)
{
CV_Assert(src.data); //若括号中的表达式为false,则返回一个错误的信息。 // accept only char type matrices
CV_Assert(src.depth() != sizeof(uchar));
// build look up table
unsigned char lut[];
for( int i = ; i < ; i++ )
{
lut[i] = pow((float)(i/255.0), fGamma) * 255.0;
}
//先归一化,i/255,然后进行预补偿(i/255)^fGamma,最后进行反归一化(i/255)^fGamma*255 const int channels = src.channels();
switch(channels)
{
case :
{
//运用迭代器访问矩阵元素
MatIterator_<uchar> it, end;
for( it = src.begin<uchar>(), end = src.end<uchar>(); it != end; it++ )
//*it = pow((float)(((*it))/255.0), fGamma) * 255.0;
*it = lut[(*it)]; break;
}
case :
{ MatIterator_<Vec3b> it, end;
for( it = src.begin<Vec3b>(), end = src.end<Vec3b>(); it != end; it++ )
{
//(*it)[0] = pow((float)(((*it)[0])/255.0), fGamma) * 255.0;
//(*it)[1] = pow((float)(((*it)[1])/255.0), fGamma) * 255.0;
//(*it)[2] = pow((float)(((*it)[2])/255.0), fGamma) * 255.0;
(*it)[] = lut[((*it)[])];
(*it)[] = lut[((*it)[])];
(*it)[] = lut[((*it)[])];
} break; }
} return src;
}

实现结果

试验结果

Gamma原理及快速实现算法(C/C++)(转)

原图

Gamma原理及快速实现算法(C/C++)(转)

fGamma=2.2

Gamma原理及快速实现算法(C/C++)(转)

fGamma=2.2

Gamma原理及快速实现算法(C/C++)(转)的更多相关文章

  1. Atitti 文本分类 &&num;160&semi;以及 垃圾邮件 判断原理 以及贝叶斯算法的应用解决方案

    Atitti 文本分类  以及 垃圾邮件 判断原理 以及贝叶斯算法的应用解决方案 1.1. 七.什么是贝叶斯过滤器?1 1.2. 八.建立历史资料库2 1.3. 十.联合概率的计算3 1.4. 十一. ...

  2. sdut 1592转置矩阵【稀疏矩阵的压缩存储】【快速转置算法】

    转置矩阵 Time Limit: 1000ms   Memory limit: 32768K  有疑问?点这里^_^ 题目链接:http://acm.sdut.edu.cn/sdutoj/proble ...

  3. 深度信任网络的快速学习算法(Hinton的论文)

    也没啥原创,就是在学习深度学习的过程中丰富一下我的博客,嘿嘿. 不喜勿喷! Hinton是深度学习方面的大牛,跟着大牛走一般不会错吧-- 来源:A fast learning algorithm fo ...

  4. Altium designer 原理图库快速创建

    Altium designer 原理图库快速创建,原来都没发现用这个功能,最近查了一下很好用,就是通过Excel编写管脚名称再直接导入就可以了,很方便的. 1.首先在Excel创建填好对应管脚名称. ...

  5. 《算法C语言实现》————快速-查找算法&lpar;quick-find algorithm&rpar;

    算法基础是一个整型数组,当且仅当第p个元素和第q个元素相等时,p和q时连通的.初始时,数组中的第i个元素的值为i,0<=i<N,为实现p与q的合并操作,我们遍历数组,把所有名为p的元素值改 ...

  6. 卷积神经网络中的Winograd快速卷积算法

    目录 写在前面 问题定义 一个例子 F(2, 3) 1D winograd 1D to 2D,F(2, 3) to F(2x2, 3x3) 卷积神经网络中的Winograd 总结 参考 博客:blog ...

  7. java 基础排序(冒泡、插入、选择、快速)算法回顾

    java 基础排序(冒泡.插入.选择.快速)算法回顾 冒泡排序 private static void bubbleSort(int[] array) { int temp; for (int i = ...

  8. SSE图像算法优化系列三十:GIMP中的Noise Reduction算法原理及快速实现。

    GIMP源代码链接:https://gitlab.gnome.org/GNOME/gimp/-/archive/master/gimp-master.zip GEGL相关代码链接:https://gi ...

  9. YUV &sol; RGB 格式及快速转换算法

    1 前言 自然界的颜色千变万化,为了给颜色一个量化的衡量标准,就需要建立色彩空间模型来描述各种各样的颜色,由于人对色彩的感知是一个复杂的生理和心理联合作用 的过程,所以在不同的应用领域中为了更好更准确 ...

随机推荐

  1. Java Se :Map 系列

    之前对Java Se中的线性表作了简单的说明.这一篇就来看看Map. Map系列的类,并不是说所有的类都继承了Map接口,而是说他们的元素都是以<Key, Value>形式设计的. Dic ...

  2. igv

    integrative genomics viewer 下载: http://www.broadinstitute.org/igv/download 下载前要注册 导入参考基因组:http://www ...

  3. bzoj1237

    假如不存在相等的两个数不能配对,那很容易贪心得到,A中rank 1匹配B中rank 1 A中rank2 匹配B中rank 2…… 有了相等不能匹配这个条件,那么A中rank i可能和rank i,i- ...

  4. &lbrack;PWA&rsqb; 5&period; Hijacking one type of request

    Previously we saw how to Hijacking all the reqest, but this is not useful. So now we want to see how ...

  5. html与css的移动端与pc端需要注意的事项

    一个移动端与pc端之间最主要的也就是尺寸问题,苹果与安卓的机型尺寸大小相差甚多,一个尺寸都会影响用户的体验.那么我们来了解一下一些常用的解决方法. 一般在网页中都会在头部有一些这样的代码 <me ...

  6. java学习之部分笔记

    1.枚举类型 2.String的方法Index的用法.StringBuffer 的用法.Math的用法.Date类 3.用abstract修饰的类就是抽象类.抽象方法不能有主体.抽象类中,可以有抽象方 ...

  7. dos下的cd指令

    进入同根目录下的目录: 1.进入同根目录的下一级目录:cd 目录名 2.返回同根目录的上一级目录:cd .. 3.返回目录的根目录:cd \ 进入不同根目录下的目录: 1.进入另外一个根目录(的默认目 ...

  8. openwrt的编译环境

    安装centos7 ,以最小的方式安装在 vmware 的虚拟机了.(yum 更新系统就不提了.下面是没有yum更新的情况下的记录和总结) 安装后,发现 ifconfig 命令不好用,得用 ip ad ...

  9. Serv-u Mysql数据库用户

    Serv-u 关联Mysql数据库用户需要用到ODBC数据源,windows不自带支持MySQL.所以要网上下载自己安装 官网下载地址:http://dev.mysql.com/downloads/c ...

  10. JNDI在server&period;xml中的配置(全局和局部的)

    总结: 全局就是在数据源server.xml中配置,然后通过和项目名相同的xml来进行映射.对所有的项目都起作用.那个项目需要就在对应的tomcat下配置一个与项目名相同的xml映射文件. 局部的就是 ...