简单的图像处理可以设置图片的每一个像素的RGB值,c#中的代码如下(下面的代码效率不高,只是为了叙述方便,比较高效的代码在最后):
public delegate Color ChangeColor(Color color); public void ChangeBitmap(ref Bitmap bmp, ChangeColor changeColor) { for (int y = 0; y < bmp.Height; y++) { for (int x = 0; x < bmp.Width; x++) { Color color = bmp.GetPixel(x, y);// 得到(x,y)像素点的颜色 Color newColor = changeColor(color);// 改变这个颜色的rgb bmp.SetPixel(x, y, newColor); // 将(x,y)像素的设置成新的颜色 } } }
色彩通道
屏蔽R、G、B中的某个通道就是将图片中的每个像素的该通道值设为0。比如屏蔽红色和蓝色通道,提取绿色通道,只需要把每个像素的R和B的值设为0,G的值不变:
ChangeBitmap(ref bmp, (color) => { return Color.FromArgb(0, color.G, 0); });
色彩平衡调节
增减某些通道的值,比如要减少蓝色通道的数值,增加红色通道的数值:
ChangeBitmap(ref bmp, (color) => { int r = color.R + 30; if (r > 255) r = 255; int b = color.G - 30; if (b < 0) b = 0; return Color.FromArgb(r,color.G,b); } );
亮度调节
亮度调节是色彩调节的一个特例,RGB同时增减相同的值
ChangeBitmap(ref bmp, (color) => { int r = color.R - 50; if (r < 0) r = 0; int g = color.G - 50; if (g < 0) g = 0; int b = color.B - 50; if (b < 0) b = 0; return Color.FromArgb(r, g, b); } );
对比度调节
提高对比度是让亮(数值大于128)的更亮,暗(数值小于128)的更暗;减少对比度则是增加暗的,减小亮的,让它们都趋于128。一般的算法是按比例调节数值与128相差的那一部分
int degree = 30;//对比度调设为30,0表示没有变化 double contrast = (100.0 + degree) / 100.0; contrast *= contrast; ChangeBitmap(ref bmp, (color) => { double r = ((color.R / 255.0 - .5) * contrast + .5) * 255; if (r > 255) r = 255; if (r < 0) r = 0; //同样方法计算G和B的值 double g = ... double b = ... return Color.FromArgb((byte)r, (byte)g, (byte)b); } );
灰度
当RGB三个数值相同时,颜色是灰色的。比如R=G=B=255是白色;R=G=B=0是黑色;在R=G=B=x,x在0~255之间就是灰色的。将彩色图片变成灰白图片就是让R=G=B=x,x的值有多种算法。
ChangeBitmap(ref bmp, (color) => { //平均值算法: //int x = (color.R + color.G + color.B) / 3; //最大值算法: //int x = Math.Max(Math.Max(color.R, color.G), color.B); //加权平均值算法,人眼对颜色的敏感度:绿色>红色>蓝色,这种算法比较合理: double x = 0.3 * color.R + 0.59 * color.G + 0.11 * color.B; return Color.FromArgb((byte)x, (byte)x, (byte)x); } );
双色阈值处理
将图片灰度化之后,灰度为大于x的设为前景色,灰度小于x的设为背景色。一般前景色和背景色是白和黑。
这与灰度化处理是有区别的。阈值处理后只有两种颜色,而灰度化处理后有0~255共256种灰度颜色
Color foreground = Color.Yellow; Color background = Color.Black; int threshold = 128;//阈值 ChangeBitmap(ref bmp, (color) => { int gray = (color.R + color.G + color.B) / 3;//先灰度化 if (gray > threshold) return foreground; else return background; } );
底片
将RGB的值分别用255去减,就的到底片效果的图片
ChangeBitmap(ref bmp, (color) => { return Color.FromArgb(255 - color.R, 255 - color.G, 255 - color.B); } );
伪色彩
灰白的图像理论上是不能还原为原始的色彩图像的。伪色彩是将不同灰度的颜色映射成其他色彩,映射的算法可以自己定。
由于人眼对色彩的分辨率远高于对灰度差的分辨率,所以进行这种转换能使图像中的信息更容易辨认。比如灰度相差很小的两种灰色不好分辨,如果把这两种颜色分别变成红色和蓝色就很好分辨了。
以下是其中的一种映射算法:
ChangeBitmap(ref bmp, (color) => { int x = color.R;//对于灰白图像,RGB的值一样 int r=0, g=0, b=0; switch (x >> 6) { case 0: r = 0; g = 4 * x; b = 255; break; case 1: r = 0; g = 255; b = 511 - 4 * x; break; case 2: r = 4 * x - 511; g = 255; b = 0; break; case 3: r = 255; g = 1023 - 4 * x; b = 0; break; } return Color.FromArgb(r, g, b); } );
Gamma矫正
由于显卡或显示去的原因实际输出的图像在亮度上可以会有偏差,像素的亮度值可能与实际显示的亮度有差别。Gamma矫正是用来矫正这种偏差,应该算是一种特殊的亮度映射吧。一般用来平滑的拓展暗调的细节。但矫正值大于1时,图像高亮部分被压缩而暗调部分被拓展,造成输出亮化;矫正值小于1时则相反,造成输出暗化。
double degree = 2;// 矫正量 0.1~5.0 // 建立Gamma矫正映射表 double g = 1 / degree; byte[] gamma = new byte[256]; for (int i = 0; i < 256; i++) { int pixel = (int)((255.0 * Math.Pow(i / 255.0, g)) + 0.5); gamma[i] = (byte)(pixel > 255 ? 255 : pixel); } ChangeBitmap(ref bmp, (color) => { return Color.FromArgb(gamma[color.R], gamma[color.G], gamma[color.B]); } );
public void ChangeBitmap(ref Bitmap bmp) { int width = bmp.Width; int height = bmp.Height; BitmapData data = bmp.LockBits(new Rectangle(new Point (0,0),bmp.Size),ImageLockMode.ReadWrite,bmp.PixelFormat); int bpp = 3; int offset = data.Stride - bpp * width; unsafe { byte* p = (byte*)data.Scan0; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // 设置每个像素的rgb值 // p[2] 红色 // p[1] 绿色 // p[0] 蓝色 p += bpp; } p += offset; } } bmp.UnlockBits(data); }