2013-06-20 33 views
13

Sto lavorando con le immagini in Java, ho progettato più oltre 100 immagini (.png) in formato, erano tutte di colore trasparente e nero.Come cambiare il colore dei pixel di un'immagine in C# .NET

Il problema è che ora mi è stato chiesto di cambiare il colore del disegno (nero).

Ho cercato molti codice snippato su google, che cambia la bitmap (pixel) dell'immagine, ma non sto indovinando cosa devo fare per abbinare il pixel esatto e sostituire specialmente quando le immagini se in modalità trasparente. Di seguito è riportato il codice .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; 

ma non era che corrispondono a tutti, ho il debug di esso, tutto il file, non vi era alcun valore di rosso, verde, parametri blu di colore (originalColor) variabile.

Chiunque può aiutare?

risposta

24

Ecco la soluzione che ho fatto con Pixels.

Allegare il codice sorgente in modo da poter provare l'esatto e ottenere il risultato.

Ho immagini di esempio di 128x128 (larghezza x altezza).

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

// seguito è l'immagine campione e risultati diversi applicando colore diverso enter image description here

modifiche Codice altamente saranno apprezzati.

+1

Questa è la risposta migliore e sono sicuro che il mio requisito è soddisfatto, grazie a DareDevil –

+3

Beh, questo sostituirà ogni colore con quello nuovo (non solo quello selezionato) e il controllo su alfa produrrà risultati non ottimali se c'è un gradiente ma se soddisfa l'OP ... :) –

+1

bene questo codice va bene per immagini di singolo colore. – DareDevil

15

Prima di parlare di perfromance cerchiamo di controllare il tuo codice:

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

Qui ci sono due errori:

  1. Lei non si confronta con Color.Black ma si assegnareColor.Black-originalColor.
  2. Non si gestisce la trasparenza.

Per controllare la trasparenza si dovrebbe confrontare non l'oggetto Color ma la R, G, valori B, cambiamo per:

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

Ora vedrai che funziona, ma ci vuole molto molto tempo per elaborare ogni immagine: GetPixel e SetPixel sono piuttosto lenti (primario perché controllano e calcolano tutto per ogni chiamata). È molto meglio gestire direttamente i dati bitmap. Se si conosce il formato di immagine in anticipo (ed è fisso per ogni immagine), allora si può fare molto molto più veloce con po 'più di codice:

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

Naturalmente questo può essere further optimized e potrebbe essere necessario per gestire diversi formati (see this list of pixel formats e this article sul loro layout) ma considerano un punto di partenza per lavorare con le bitmap.

Per completezza si tratta di un colore equivalente senza accesso diretto ai dati bitmap. Si prega di notare che questo dovrebbe essere usato raramente perché è terribilmente lento.

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

Inoltre si ricorda che questa considerare canale alfa in confronto (verde così 50% trasparente, per esempio, non è stesso colore verde trasparente 30%). Per ignorare alpha si può usare qualcosa di simile:

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

Infine, se si sa che i pixel per sostituire sono poco è possibile creare una copia grezza di immagine originale (usando Graphics.FromImage per creare un contesto e di trarre in esso source bitmap), in tal modo chiamerai lo SetPixel() solo quando c'è una sostituzione. IMO qualsiasi ottimizzazione qui è abbastanza inutile: se hai bisogno di prestazioni usa la prima soluzione ...

+0

In fretta, ho fatto tutto ed è stato eliminato == –

+1

@BibiTahira cosa viene eliminato? –

+0

quando stavo copiando il mio colore di pixel con il colore del sistema –

4

Un modo per sostituire in modo efficiente un colore è utilizzare una tabella di rimappatura. Nell'esempio seguente, un'immagine viene disegnata all'interno di una finestra immagine. Nel caso in Paint, il Color.Black colore viene modificato in 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); 
     } 
    } 

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

1

io vi darò un'altra soluzione dal momento che questo non calcola per ogni pixel.

È breve e semplice. Il tempo di conversione è 62 ms:

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

Come si può creare una matrice di colori per un colore particolare? Come verde, blu ecc? –