【转】C#图像对比度处理
看了一篇关于图象对比度处理的文章,并通过实践测试整理出这段代码,仅供参考:
public static Bitmap Contrast(Bitmap b,float A)
{
//调整对比度
//A的范围:0 到 2
if (A < 0 || A > 2)
return null;
int B = Convert.ToInt32(-127 * A + 127);
BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width,
b.Height), ImageLockMode.ReadWrite,PixelFormat.Format24bppRgb);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte * p = (byte *)(void *)Scan0;
int nOffset = stride - b.Width*3;
int nWidth = b.Width * 3;
for(int y = 0;y < b.Height;++y)
{
for(int x = 0; x < nWidth;++x )
{
int k = (int)(p[0] * A + B);
if(k > 255)k = 255;
if(k < 0)k = 0;
p[0] = (byte)k;
++p;
}
p += nOffset;
}
}
b.UnlockBits(bmData);
return b;
}
附:
======================================================
在图像处理中,恐怕大家最熟悉的就是对于图像的亮度和对比度调整了。
前面一定也有很多人写过这样的文章了,但是想把我的这个系列作一个完整的小结,我就再罗嗦一番了。
还是以24位色图像为例子,每种色彩都可以用0-255,一共256种深度来表示。
如果我们把它画在一个二维坐标上,正好是一条直线。
比如我们将像素的色深作为横坐标,输出色深作为纵坐标的画,正好是一条经过原点(0,0)的45度斜线。
如图中直线A所表示的,角T为45度,表示它的对比度正好为1。
那么很容易就可以写出它的直线方程:Out = In * 1 ,系数1就是对比度的概念
如果把条直线加上一个偏移量变成B,那么它的直线方程就成为:Out = In * 1 + (ab)
偏移量(ab)就是亮度的增量。
只要有初中的代数知识就很容易看出它满足一条直线方程:Y= A * X + B
但是,我们这里要处理的情况稍微有些不同,在图像处理中,对比度和亮度要分别对待。
不能因为改变而改变亮度,因为我们习惯上把灰色(127,127)这一点作为中心点。
比如,我们加大了对比度,原来的直线A就变成如直线D所表示的,在改变了对比度的同时,也增加了亮度(ab),而我们心目中的变化应该是入直线C那样。也就是说,我们把(127,127)这一点映射成了坐标系的原点。
那么我们就要把原来的直线公式修改成:Y=( X - 127 ) * A + B。A表示对比度,B表示亮度增量。
我们验证一下:只要亮度增量 B=0,无论怎么改变对比度 A,该直线始终通过中心点(127,127),也就是说改变对比度的同时,亮度没有改变。
由此,我们就可以推导出颜色的对比度亮度计算公式了:
NewRed = (OldRed -127 ) * A + 127+ B
NewGreen = (OldGreen -127 ) * A + 127+B
NewBlue = (OldBlue -127 ) * A + 127+B
现在你是否已经准备着手用这个公式来写出你自己的亮度对比度子程序了呢?
慢着,再多做一步吧。我们是在遍程序,不是在做初中代数考试。这多出来的一步将使你的程序的执行效率更高一些。
我们把上面的公式再推导一下:
Y=( X - 127 ) * A + B => Y = X * A - 127 * A + 127+B (1)
令:B = B -127 * A +127 (2)
由上面(1),(2)两步,得到一个新的公式:Y = X * A + B
咦?怎么又变回来了??
是的公式的形式确实是变回来了,不过B所代表的东西已经不同了。
或许你又会说我这是多此一举,请聪明的读者想像一下:在一个普通的图片做亮度对比度运算的时候,我们上面这些小小的变化将带来什么样的效率提升。假设一张图片大小是1027*768
一共有786432个像素,而每个像素又要分别计算红绿蓝三种颜色。
那么,上述这个公式就需要计算786432 * 3 = 2359296 次,经过这么多次运算的放大,哪怕是小小的一个重复计算都将浪费很长的时间。
因为在调用子程序的时候亮度和对比度都已经确定,那么B = B -127 * A +127这一步就可以放在循环的外面先作好。从而减少了程序的运算时间。