如何在C#.NET中更改图像的像素颜色

我正在使用Java中的Images,我设计了超过100种图像(.png)格式,它们都是Trasparent和Black Color Drawing。

问题是,现在我被要求改变绘图的颜色(黑色 – )。

我搜索了许多在谷歌剪断的代码,它改变了图像的位图(像素),但我不是猜测我必须做什么来匹配精确的像素,并在图像处于透明模式时特别替换。 下面是.Net(C#)中的代码

Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height); for (int i = 0; i < scrBitmap.Width; i++) { for (int j = 0; j < scrBitmap.Height; j++) { originalColor = scrBitmap.GetPixel(i, j); if(originalColor = Color.Black) newBitmap.SetPixel(i, j, Color.Red); } } return newBitmap; 

但它根本没有匹配,我调试了它,在整个文件中,没有Color(originalColor)变量的Red,Green,Blue参数的值。

有人可以帮忙吗?

这是我用Pixels做的解决方案。

附加源代码,以便可以尝试精确并获得结果。

我有128×128(宽x高)的样本图像。

 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Drawing; using System.IO; //using System.Globalization; namespace colorchange { class Program { static void Main(string[] args) { try { Bitmap bmp = null; //The Source Directory in debug\bin\Big\ string[] files = Directory.GetFiles("Big\\"); foreach (string filename in files) { bmp = (Bitmap)Image.FromFile(filename); bmp = ChangeColor(bmp); string[] spliter = filename.Split('\\'); //Destination Directory debug\bin\BigGreen\ bmp.Save("BigGreen\\" + spliter[1]); } } catch (System.Exception ex) { Console.WriteLine(ex.ToString()); } } public static Bitmap ChangeColor(Bitmap scrBitmap) { //You can change your new color here. Red,Green,LawnGreen any.. Color newColor = Color.Red; Color actualColor; //make an empty bitmap the same size as scrBitmap Bitmap newBitmap = new Bitmap(scrBitmap.Width, scrBitmap.Height); for (int i = 0; i < scrBitmap.Width; i++) { for (int j = 0; j < scrBitmap.Height; j++) { //get the pixel from the scrBitmap image actualColor = scrBitmap.GetPixel(i, j); // > 150 because.. Images edges can be of low pixel colr. if we set all pixel color to new then there will be no smoothness left. if (actualColor.A > 150) newBitmap.SetPixel(i, j, newColor); else newBitmap.SetPixel(i, j, actualColor); } } return newBitmap; } } } 

//下面是示例图像,并通过应用不同的颜色得到不同的结果 在此处输入图像描述

代码修改将受到高度赞赏。

在我们谈论性能之前,让我们检查你的代码:

 var originalColor = scrBitmap.GetPixel(i, j); if (originalColor = Color.Black) newBitmap.SetPixel(i, j, Color.Red); 

这里有两个错误:

  1. 您不能与Color.Black进行比较,但 Color.Black 指定originalColor
  2. 你不处理透明度。

要检查透明度,您应该比较Color对象而不是R,G,B值,让我们改为:

 var originalColor = scrBitmap.GetPixel(i, j); if (originalColor.R == 0 && originalColor.G == 0 && originalColor.B == 0) newBitmap.SetPixel(i, j, Color.FromArgb(originalColor.A, Color.Red)); 

现在您将看到它可以工作,但处理每个图像需要很长时间: GetPixelSetPixel非常慢(主要因为它们检查并计算每个调用的所有内容)。 直接处理位图数据要好得多。 如果您事先知道图像格式(并且每个图像都是固定的),那么您可以使用更多的代码更快地完成它:

 static unsafe Bitmap ReplaceColor(Bitmap source, Color toReplace, Color replacement) { const int pixelSize = 4; // 32 bits per pixel Bitmap target = new Bitmap( source.Width, source.Height, PixelFormat.Format32bppArgb); BitmapData sourceData = null, targetData = null; try { sourceData = source.LockBits( new Rectangle(0, 0, source.Width, source.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); targetData = target.LockBits( new Rectangle(0, 0, target.Width, target.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); for (int y = 0; y < source.Height; ++y) { byte* sourceRow = (byte*)sourceData.Scan0 + (y * sourceData.Stride); byte* targetRow = (byte*)targetData.Scan0 + (y * targetData.Stride); for (int x = 0; x < source.Width; ++x) { byte b = sourceRow[x * pixelSize + 0]; byte g = sourceRow[x * pixelSize + 1]; byte r = sourceRow[x * pixelSize + 2]; byte a = sourceRow[x * pixelSize + 3]; if (toReplace.R == r && toReplace.G == g && toReplace.B == b) { r = replacement.R; g = replacement.G; b = replacement.B; } targetRow[x * pixelSize + 0] = b; targetRow[x * pixelSize + 1] = g; targetRow[x * pixelSize + 2] = r; targetRow[x * pixelSize + 3] = a; } } } finally { if (sourceData != null) source.UnlockBits(sourceData); if (targetData != null) target.UnlockBits(targetData); } return target; } 

当然,这可以进一步优化 ,您可能需要处理不同的格式( 请参阅此像素格式列表和本文关于其布局的文章 ),但将其视为使用位图的起点。

为了完整性,这是等效的颜色,不能直接访问位图数据。 请注意,这应该很少使用,因为它非常慢。

 static Bitmap ReplaceColor(Bitmap source, Color toReplace, Color replacement) { var target = new Bitmap(source.Width, source.Height); for (int x = 0; x < source.Width; ++x) { for (int y = 0; y < source.Height; ++y) { var color = source.GetPixel(x, y); target.SetPixel(x, y, color == toReplace ? replacement : color); } } return target; } 

另请注意,这比较考虑alpha通道(例如,50%透明绿色,与30%透明绿色不同)。 要忽略alpha,您可以使用以下内容:

 if (color.R == toReplace.R && color.G == toReplace.G && color.B == toReplace.B) 

最后,如果您知道要替换的像素很少,您可以创建原始图像的原始副本(使用Graphics.FromImage创建上下文并绘制到source位图),这样您只能在那里调用SetPixel()是一个替代品。 IMO在这里的任何优化都是无用的:如果你需要性能使用第一个解决方案......

有效替换颜色的一种方法是使用重映射表。 在以下示例中,将在图片框内绘制图像。 在Paint事件中,Color.Black的颜色更改为Color.Blue:

  private void pictureBox_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; using (Bitmap bmp = new Bitmap("myImage.png")) { // Set the image attribute's color mappings ColorMap[] colorMap = new ColorMap[1]; colorMap[0] = new ColorMap(); colorMap[0].OldColor = Color.Black; colorMap[0].NewColor = Color.Blue; ImageAttributes attr = new ImageAttributes(); attr.SetRemapTable(colorMap); // Draw using the color map Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); g.DrawImage(bmp, rect, 0, 0, rect.Width, rect.Height, GraphicsUnit.Pixel, attr); } } 

更多信息: http : //msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx

我会给你另一个解决方案,因为这不计算每个像素。

它简短而简单。 转换时间为62毫秒:

 public Bitmap Color(Bitmap original) { //create a blank bitmap the same size as original Bitmap newBitmap = new Bitmap(original.Width, original.Height); //get a graphics object from the new Image Graphics g = Graphics.FromImage(newBitmap); //create the color you want ColorMatrix //now is set to red, but with different values //you can get anything you want. ColorMatrix colorMatrix = new ColorMatrix( new float[][] { new float[] {1f, .0f, .0f, 0, 0}, new float[] {1f, .0f, .0f, 0, 0}, new float[] {1f, .0f, .0f, 0, 0}, new float[] {0, 0, 0, 1, 0}, new float[] {0, 0, 0, 0, 1} }); //create some image attributes ImageAttributes attributes = new ImageAttributes(); //set the color matrix attribute attributes.SetColorMatrix(colorMatrix); //draw original image on the new image using the color matrix g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, attributes); //release sources used g.Dispose(); return newBitmap; }