一、介绍
伽马变换,又名指数变换、幂次变换或幂律变换,主要用于图像的校正,将灰度过高或者灰度过低的图片进行修正,增强对比度。在图像处理领域,其公式表示为:
P(out) = C * P(in)^γ
- P(out) ,输出像素值*
- C,系数(在我的代码里直接等于1,可以不用写)
- P(in)^γ,输入像素P(in) 的 γ次幂
再补充个知识,
var a = Math.Pow(2, 3);
var b = Math.Pow(10000, 0.25);
结果是a = 8, b = 10。也就是 2 的 3 次幂是8,10000的0.25次幂是10。
在实际编程过程中,C我一般都取为1,P(in)就是原始图像像素值,只有γ的值是需要用户自己设定的 。也就是用户需要定义原始图像的像素值需要执行 多少次幂 用于生成新图像。Emgu CV也是没有专门的伽马增强的函数,自己写代码实现非常简单,其中一种思路如下:
- 加载原始图像srcMat;
- srcMat转成64位双精度类型(要进行幂计算,数值会很大);
- 幂计算,生成新图像dstMat;
- dstMat转成8 位无符号类型,显示图像,结束计算。
二、代码
C#代码如下:
Mat tempMat = srcMat.Clone();
Mat gammaImage64F = new Mat(tempMat.Rows, tempMat.Cols, DepthType.Cv64F, 1); // 对比度增强后的伽马图像,是灰度图
Mat dstMat = new Mat(); // 最终的结果,由gammaImage64F转换而来
Mat gray = new Mat(); // 原图的灰度图
double gamma = 0.5; // 伽马变化中,幂的值
int height = tempMat.Rows;
int width = tempMat.Cols;
CvInvoke.CvtColor(tempMat, gray, ColorConversion.Bgr2Gray); // 原图转灰度图
// 伽马变换
gray.ConvertTo(gray, DepthType.Cv64F, 1.0 / 255, 0);
double[,] dataArray = (double[,])gray.GetData();
Image<Gray, double> imgTemp = gammaImage64F.ToImage<Gray, double>();
for (int i = 0; i < height; i++)
{
for (int j = 0; j < width; j++)
{
imgTemp.Data[i, j, 0] = Math.Pow(dataArray[i, j], gamma);
}
}
gammaImage64F = imgTemp.Mat;
gammaImage64F.ConvertTo(dstMat, DepthType.Cv8U, 255, 0);
CvInvoke.Imshow("Gamma sharping image, " + dstMat.Size.ToString(), dstMat);
三、效果举例
原始素材定义为srcMat,如下:
还是这张夜晚天桥的照片,执行上述代码,伽马增强后的图像如下:
左上角原本比较黑暗的树叶,伽马增强后是不是清晰明亮多了,而原本明亮的路灯还是基本没变。刚才是幂的值为0.5,如果等于2.5呢,结果就是下面这样了:
还是原本亮的没变,昏暗的变更昏暗了。其实很好理解,假设两个像素点,P1 = 200,P2 = 10。
- 如果执行0.5次幂,那么P1 = 14.1 ,P2 = 3.1。两个点的值接近了,如果图像再归一化到0 -255,必然是P2点的值要远大于10,也就是暗的部分变亮了。
- 如果执行2.5次幂,那么P1 = 56565.4 ,P2 = 316.2。两个点的值相差更大了,如果图像再归一化到0 -255,必然是P2点的值要远小于10,也就是暗的部分变暗了。
- 如果执行1次幂,结果等于原图。
原创不易,请勿抄袭。共同进步,相互学习。