【问题标题】:How to Change Pixel Color of an Image in C#.NET如何在 C#.NET 中更改图像的像素颜色
【发布时间】:2013-06-20 07:58:44
【问题描述】:

我正在使用 Java 中的图像,我设计了超过 100 多个图像(.png)格式,它们都是透明和黑色绘图。

问题是,现在我被要求更改绘图的颜色(Black -to )。

我已经搜索了许多在谷歌上截取的代码,这些代码改变了图像的位图(像素),但我没有猜到我必须做什么来匹配确切的像素并在图像处于透明模式时特别替换。 以下是 .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;

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

有人可以帮忙吗?

【问题讨论】:

    标签: c# .net drawing pixels bitmapimage


    【解决方案1】:

    这是我使用 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;
           }
       }
    }
    

    //下面是示例图像和应用不同颜色的不同结果

    我们将非常感谢您修改代码。

    【讨论】:

    • 这是最好的回复,我确信我的要求已经得到满足,感谢 DareDevil
    • 好吧,这会将每种颜色替换为新颜色(不仅仅是选定的颜色),如果存在渐变但如果满足 OP,则检查 alpha 将产生次优结果... :)
    • @DareDevil 谢谢。您编写代码以更改图像中仅颜色的对象。但我只想改变背景图像的颜色,而不是改变对象的颜色。我的原图:imgur.com/LphfKdV你改了:imgur.com/DJc0N0U我想点赞:imgur.com/4pvWtp8怎么办?谢谢。
    【解决方案2】:

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

    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;
    }
    

    当然这可以是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 位图),这样您将调用@ 987654337@ 仅当有替换时。 IMO 此处的任何优化都毫无用处:如果您需要性能,请使用第一个解决方案...

    【讨论】:

    • 匆忙,我做了所有,它被删除了==
    • @BibiTahira 删除了什么?
    • 当我将我的像素颜色与系统颜色进行比较时
    • @BibiTahira 查看代码示例,您不得比较 Color 对象,而是比较单个组件(因为原始图像中的 alpha)。
    • @AdrianoRepetti :我想使用此代码,但我需要处理多种图像类型。我可以从图像类型中获取像素格式,但是如何计算“像素大小”
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

      • 如何为特定颜色创建颜色矩阵?比如绿色、蓝色等?
      猜你喜欢
      • 2021-09-12
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      • 2019-08-26
      • 2014-11-07
      • 1970-01-01
      • 1970-01-01
      • 2017-03-10
      相关资源
      最近更新 更多