Как изменить цвет пикселя изображения в C#.NET

Я работаю с изображениями на Java, я разработал более 100 + изображений(.png) формат, все они были прозрачными и черными цветными рисунками.

проблема в том, что теперь меня попросили изменить цвет рисунка (черный-на ).

Я искал много кода, обрезанного в google, который изменяет растровое изображение (пиксели) изображения, но я не догадываюсь, что мне нужно сделать, чтобы соответствовать точному пикселю и заменить специально, когда изображения, если в прозрачном режиме. Ниже код в .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).

кто-нибудь может помочь?

4 ответов


вот решение, которое я сделал с пикселями.

прикрепление исходного кода, чтобы можно было попробовать точное и получить результат.

У меня есть примеры изображений 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

изменения кода будут высоко оценены.


прежде чем мы поговорим о perfromance давайте проверим ваш код:

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

здесь есть две ошибки:

  1. вы не сравниваете с Color.Black а вы присвоить Color.Black to 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));

теперь вы увидите, что он работает, но для этого требуется очень долгое время для обработки каждого изображения: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;
}

конечно это может быть дополнительно оптимизирован и вам может потребоваться обрабатывать различные форматы ( см. этот список пикселей форматы и в этой статье об их макете) , но считают его отправной точкой для работы с растровыми изображениями.

для полноты это эквивалент цвет без прямого доступа к растровым данным. Обратите внимание, что это должно использоваться редко, потому что это ужасно медленно.

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

Также обратите внимание, что это рассмотреть альфа-канал в сравнении (так 50% прозрачный зеленый, например, не такой же цвет, как 30% прозрачный зеленый). Игнорировать Альфа тебя может использовать что-то вроде этого:

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

наконец, если вы знаете, что пикселей для замены мало, вы можете создать сырую копию исходного изображения (используя Graphics.FromImage создать контекст и втянуть в нее source bitmap), таким образом вы вызовете SetPixel() только когда есть замена. IMO любая оптимизация здесь довольно бесполезна: если вам нужна производительность, используйте первое решение...


один из способов эффективной замены цвета-использовать таблицу переназначения. В следующем примере изображение рисуется внутри окна изображения. В событии Paint цвет.Черный цвет меняется на цвет.Синий:

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