如何在c#。net中改变图像的像素颜色?

时间:2022-12-07 23:59:57

I am working with Images in Java, I have designed more over 100+ images(.png) format, They were all Trasparent and Black Color Drawing.

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

The problem is, Now I have been asked to change the color of the Drawing (Black -to ).

问题是,现在我已经被要求改变图纸的颜色(黑色到)。

I have searched many code snipped at google,that changes the Bitmap (pixels) of the Image, but i am not guessing what i have to do to match the exact pixel and replace specially when the images if in Transparent mode. Below is the code in .Net (C#)

我已经在谷歌上搜索了许多代码,这改变了图像的位图(像素),但我不是在猜测我必须做什么来匹配准确的像素,特别是在透明模式下的图像。下面是。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;

but it was not matching at all, I debugged it, throughout the file, there was no value of Red,Green,Blue parameters of Color (originalColor) variable.

但它根本不匹配,我调试它,在整个文件中,没有红色、绿色、蓝色参数(原始颜色)的值。

Anybody can help?

任何人都可以帮忙吗?

4 个解决方案

#1


25  

Here is the Solution I have done with Pixels.

这是我用像素做的解决方案。

Attaching the source code so one can try the exact and get the result.

附加源代码,以便您可以尝试准确和得到结果。

I have sample images of 128x128 (Width x Height).

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

//Below is the sample image and different results by applying different color 如何在c#。net中改变图像的像素颜色?

//下面是使用不同颜色的样本图像和不同的结果。

Code modifications will be highly appreciated.

代码修改将非常感谢。

#2


15  

Before we talk about perfromance let's check your code:

在我们讨论perfromance之前让我们检查一下代码:

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

Here there are two errors:

这里有两个错误:

  1. You do not compare to Color.Black but you assign Color.Black to originalColor.
  2. 你不与颜色相比较。黑色,但你指定颜色。黑色originalColor。
  3. You do not handle transparency.
  4. 你不处理透明度。

To check for transparency you should compare not the Color object but the R, G, B values, let's change to:

为了检查透明度,你应该对比颜色对象,但是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));

Now you'll see that it works but it takes a very long time to process each image: GetPixel and SetPixel are pretty slow (primary because they check and calculate everything for each call). It's much better to handle bitmap data directly. If you know the image format in advance (and it's fixed for each image) then you can do it much much faster with little bit more code:

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

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

Of course this can be further optimized and you may need to handle different formats ( see this list of pixel formats and this article about their layout) but consider it a starting point to work with bitmaps.

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

For completeness this is equivalent color without direct access to bitmap data. Please note that this should be rarely used because it's terribly slow.

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

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

Also please note that this consider alpha channel in comparison (so 50% transparent green, for example, is not same color as 30% transparent green). To ignore alpha you may use something like this:

也请注意,这是比较的alpha通道(例如,50%透明绿色,与30%透明绿色不一样)。忽略alpha,你可以用这样的方法:

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

Finally if you know that pixels to replace are little you may create a raw copy of original image (using Graphics.FromImage to create a context and to draw into it source bitmap), in such way you'll call SetPixel() only when there is a replacement. IMO any optimization here is pretty useless: if you need performance use first solution...

最后,如果您知道要替换的像素很小,您可以创建原始图像的原始副本(使用图形)。从图像到创建上下文,并将其绘制到它的源位图),这样您就会调用SetPixel(),只有在有替换的时候。在这里,任何优化都是无用的:如果您需要性能使用第一解决方案……

#3


4  

One way to efficiently replace a color is to use a remap table. In the following example, an image is drawn inside a picture box. In the Paint event, the color Color.Black is changed to 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);
        }
    }

More information: http://msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx

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

#4


1  

I will give you another solution since this does not calculate for every pixel.

我将给你另一个解,因为它不计算每个像素。

Its short and simple. Convert time is 62 ms:

其短期和简单。转换时间为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;
        }

#1


25  

Here is the Solution I have done with Pixels.

这是我用像素做的解决方案。

Attaching the source code so one can try the exact and get the result.

附加源代码,以便您可以尝试准确和得到结果。

I have sample images of 128x128 (Width x Height).

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

//Below is the sample image and different results by applying different color 如何在c#。net中改变图像的像素颜色?

//下面是使用不同颜色的样本图像和不同的结果。

Code modifications will be highly appreciated.

代码修改将非常感谢。

#2


15  

Before we talk about perfromance let's check your code:

在我们讨论perfromance之前让我们检查一下代码:

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

Here there are two errors:

这里有两个错误:

  1. You do not compare to Color.Black but you assign Color.Black to originalColor.
  2. 你不与颜色相比较。黑色,但你指定颜色。黑色originalColor。
  3. You do not handle transparency.
  4. 你不处理透明度。

To check for transparency you should compare not the Color object but the R, G, B values, let's change to:

为了检查透明度,你应该对比颜色对象,但是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));

Now you'll see that it works but it takes a very long time to process each image: GetPixel and SetPixel are pretty slow (primary because they check and calculate everything for each call). It's much better to handle bitmap data directly. If you know the image format in advance (and it's fixed for each image) then you can do it much much faster with little bit more code:

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

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

Of course this can be further optimized and you may need to handle different formats ( see this list of pixel formats and this article about their layout) but consider it a starting point to work with bitmaps.

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

For completeness this is equivalent color without direct access to bitmap data. Please note that this should be rarely used because it's terribly slow.

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

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

Also please note that this consider alpha channel in comparison (so 50% transparent green, for example, is not same color as 30% transparent green). To ignore alpha you may use something like this:

也请注意,这是比较的alpha通道(例如,50%透明绿色,与30%透明绿色不一样)。忽略alpha,你可以用这样的方法:

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

Finally if you know that pixels to replace are little you may create a raw copy of original image (using Graphics.FromImage to create a context and to draw into it source bitmap), in such way you'll call SetPixel() only when there is a replacement. IMO any optimization here is pretty useless: if you need performance use first solution...

最后,如果您知道要替换的像素很小,您可以创建原始图像的原始副本(使用图形)。从图像到创建上下文,并将其绘制到它的源位图),这样您就会调用SetPixel(),只有在有替换的时候。在这里,任何优化都是无用的:如果您需要性能使用第一解决方案……

#3


4  

One way to efficiently replace a color is to use a remap table. In the following example, an image is drawn inside a picture box. In the Paint event, the color Color.Black is changed to 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);
        }
    }

More information: http://msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx

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

#4


1  

I will give you another solution since this does not calculate for every pixel.

我将给你另一个解,因为它不计算每个像素。

Its short and simple. Convert time is 62 ms:

其短期和简单。转换时间为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;
        }