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

时间:2013-06-20 07:58:44

标签: c# .net drawing pixels bitmapimage

我正在使用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参数值。

有人可以帮忙吗?

4 个答案:

答案 0 :(得分:28)

以下是我对Pixels所做的解决方案。

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

我有128x128(宽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;
       }
   }
}

//下面是示例图像,通过应用不同的颜色得到不同的结果 enter image description here

我们非常感谢代码修改。

答案 1 :(得分:15)

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

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

这里有两个错误:

  1. 您不能与Color.Black进行比较,但 Color.Black分配给originalColor
  2. 你不处理透明度。
  3. 要检查透明度,您应该比较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;
    }
    

    当然这可能是further optimized,您可能需要处理不同格式(see this list of pixel formatsthis article关于其布局),但请将其视为使用位图的起点。

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

    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在这里的任何优化都是无用的:如果你需要性能,请使用第一个解决方案...

答案 2 :(得分:5)

有效替换颜色的一种方法是使用重映射表。在以下示例中,将在图片框内绘制图像。在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

答案 3 :(得分:1)

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

简短而简单。转换时间为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;
        }
相关问题