本文转自 使用C#实现对图片内某种颜色的替换 – 知乎 (zhihu.com)
效果图:
图片处理
证件照换背景色
程序很简单,大体结构如下:
核心代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/// <summary> /// 指定颜色替换成另一种颜色 /// </summary> /// <param name="img">原图</param> /// <param name="w">图宽</param> /// <param name="h">图高</param> /// <param name="R">要被替换颜色的RGB的R</param> /// <param name="G">要被替换颜色的RGB的G</param> /// <param name="B">要被替换颜色的RGB的B</param> /// <param name="r">替换色的RGB的R</param> /// <param name="g">替换色的RGB的G</param> /// <param name="b">替换色的RGB的B</param> /// <returns>处理后的结果图像</returns> public Bitmap ReplaceColor(Bitmap img, int w, int h, int R, int G, int B, int r, int g, int b) { Bitmap bt = new Bitmap(ConvertTo32bpp(img)); Rectangle rect = new Rectangle(0, 0, w, h); BitmapData bmpdata = bt.LockBits(rect, ImageLockMode.ReadWrite, bt.PixelFormat); IntPtr ptr = bmpdata.Scan0; int bytes = Math.Abs(bmpdata.Stride) * bt.Height; byte[] rgbValues = new byte[bytes]; System.Runtime.InteropServices.Marshal.Copy(ptr, rgbValues, 0, bytes); int len = rgbValues.Length; byte a = (byte)int.Parse(tbTolerance.Text); byte R1 = (byte)R; byte G1 = (byte)G; byte B1 = (byte)B; byte r1 = (byte)r; byte g1 = (byte)g; byte b1 = (byte)b; for (int i = 0; i < len; i += 4) { //Format32bppRgb是用4个字节表示一个像素,第一个字节表示RGB的B值,第一个表示为G值,第三个表示为R值,第四个表示为Alpha值 if (Math.Abs(rgbValues[i] - B1) < a && Math.Abs(rgbValues[i + 1] - G1) < a && Math.Abs(rgbValues[i + 2] - R1) < a) { rgbValues[i] = b1; rgbValues[i + 1] = g1; rgbValues[i + 2] = r1; } } System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, ptr, bytes); bt.UnlockBits(bmpdata); return bt; } |
代码说明:
通过LockBits方法来锁定系统内存中现有的bitmap位图,使其可以用编程的方式进行更改.然后通过用bitmapdata的Scan0属性来找到位图第一个像素数据的位置,进而通过bitmapdata的Stride属性来得到位图的扫描宽度(和图片的width属性不一样,Stride是内存中实际位图每行的宽度,存在一个补齐为4的倍数).然后通过宽度和高度的乘积得到位图在内存中占有的字节(byte)数组大小,进而用Marshal.Copy方法从内存中得到这些位图的像素数据,然后采用for循环去遍历每一个像素(4字节,顺序是bgrAlpha)上的颜色数值和要替换的颜色数值的差的绝对值是否在设定的容差范围内,如果在就用替换的颜色数值去覆盖原有颜色数值.
程序地址:
https://github.com/JingChao94/ImgDemo
参考资料: