源: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值对应图像亮度的变化

二、为什么进行Gamma校正?

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

 

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

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

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

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

 

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

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

3.gamma叠加的影响

 

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

三、Gamma矫正的原理

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

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

2.预补偿:根据公式 ,求出像素归一化后的 数据以 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;
}

实现结果

试验结果

原图

fGamma=2.2

fGamma=2.2

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

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

    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语言实现》————快速-查找算法(quick-find algorithm)

    算法基础是一个整型数组,当且仅当第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 / RGB 格式及快速转换算法

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

随机推荐

  1. git clean -fdx

    http://stackoverflow.com/questions/5807137/git-how-to-revert-uncommitted-changes-including-files-and ...

  2. 5.1 timestamp数据类型默认值

    5.1 不支持同一张表中有多个tmiestamp类型字段的默认值为current_time,  5.6版本无此问题

  3. asp.net导出excel科学计数问题

    方法一: 在asp.net 中 我一般都是将要导出的数据放到gridview网格里,首先对网格邦定数据时 字符串形式处理,然后再用普通的形式导出excel就把问题解决了. 我的代码非常简单:在邦定gr ...

  4. md5 加密模板

    public class MD5Util { public static String getDigestedPassword(String password) throws NoSuchAlgori ...

  5. Sea Battle

    Sea Battle time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  6. \t 的理解

    在同一个缓冲区内横向跳8个空格. 如果在 \t 前面有字符串,则包括 \t之前出现的字符串之内一共是8个空格.

  7. sql日期

    当我们处理日期时,最难的任务恐怕是确保所插入的日期的格式,与数据库中日期列的格式相匹配. 只要您的数据包含的只是日期部分,运行查询就不会出问题.但是,如果涉及时间部分,情况就有点复杂了. 在讨论日期查 ...

  8. windows程序设计(二)

    MFC架构组成 1.CWinApp的派生类 2.必须在全局区定义一个派生类的对象 3.在CWinApp派生类内必须要有InitInstance虚函数的重写函数 在MFC软件工程以App类中的InitI ...

  9. java.lang.ClassNotFoundException: org.apache.lucene.store.Directory

    看下你的lucene-core.jar有没有在WEB-INF\lib下.

  10. Python基础学习2---模块

    模块 你已经学习了如何在你的程序中定义一次函数而重用代码.如果你想要在其他程序中重用很多函数,那么你该如何编写程序呢?你可能已经猜到了,答案是使用模块.模块基本上就是一个包含了所有你定义的函数和变量的 ...