Comment changer la couleur des pixels d’une image en C # .NET

Je travaille avec Images en Java, j’ai conçu plus de 100 formats d’image (.png). Ils étaient tous trasparents et dessin en couleur noire.

Le problème est que maintenant, on m’a demandé de changer la couleur du dessin (noir).

J’ai recherché de nombreux codes coupés sur Google, qui modifient le bitmap (pixels) de l’image, mais je ne devine pas ce que je dois faire pour correspondre au pixel exact et le remplacer spécialement lorsque les images sont en mode transparent. Ci-dessous le code en .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; 

mais il ne correspondait pas du tout, je l’ai débogué, tout au long du fichier, il n’y avait aucune valeur pour les parameters Red, Green, Blue de la variable Color (originalColor).

Quelqu’un peut aider?

Voici la solution que j’ai faite avec Pixels.

Joindre le code source afin que l’on puisse essayer l’exact et obtenir le résultat.

J’ai des exemples d’images de 128×128 (largeur x hauteur).

 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(ssortingng[] args) { try { Bitmap bmp = null; //The Source Directory in debug\bin\Big\ ssortingng[] files = Directory.GetFiles("Big\\"); foreach (ssortingng filename in files) { bmp = (Bitmap)Image.FromFile(filename); bmp = ChangeColor(bmp); ssortingng[] spliter = filename.Split('\\'); //Destination Directory debug\bin\BigGreen\ bmp.Save("BigGreen\\" + spliter[1]); } } catch (System.Exception ex) { Console.WriteLine(ex.ToSsortingng()); } } 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; } } } 

// Ci-dessous, l’exemple d’image et les résultats différents obtenus en appliquant une couleur différente entrez la description de l'image ici

Les modifications du code seront très appréciées.

Avant de parler de performance, vérifions votre code:

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

Ici il y a deux erreurs:

  1. Vous ne comparez pas à Color.Black mais vous affectez Color.Black à originalColor .
  2. Vous ne gérez pas la transparence.

Pour vérifier la transparence, vous ne devez pas comparer l’object Color mais les valeurs R, V, 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)); 

Maintenant, vous verrez que cela fonctionne, mais le traitement de chaque image prend beaucoup de temps: GetPixel et SetPixel sont assez lents (primaires car ils vérifient et calculent tout pour chaque appel). Il est bien préférable de gérer les données bitmap directement. Si vous connaissez le format d’image à l’avance (et qu’il est fixé pour chaque image), vous pouvez le faire beaucoup plus rapidement avec un peu plus de code:

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

Bien sûr, cela peut être optimisé davantage et vous devrez peut-être gérer différents formats ( voir la liste des formats de pixels et cet article sur leur disposition), mais considérez-le comme un sharepoint départ pour utiliser des bitmaps.

Pour être complet, il s'agit d'une couleur équivalente sans access direct aux données bitmap. S'il vous plaît noter que cela devrait être rarement utilisé parce que c'est terriblement lent.

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

Veuillez également noter que cela considère le canal alpha en comparaison (ainsi, 50% de vert transparent, par exemple, n’a pas la même couleur que 30% de vert transparent). Pour ignorer l'alpha, vous pouvez utiliser quelque chose comme ceci:

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

Enfin, si vous savez que les pixels à remplacer sont peu nombreux, vous pouvez créer une copie brute de l'image d'origine (à l'aide de Graphics.FromImage pour créer un contexte et y SetPixel() bitmap source ). Ainsi, vous n'appellerez SetPixel() que est un remplacement. IMO toute optimisation ici est plutôt inutile: si vous avez besoin de performance, utilisez la première solution ...

Un moyen de remplacer efficacement une couleur consiste à utiliser un tableau de remappage. Dans l’exemple suivant, une image est dessinée dans une zone d’image. Dans l’événement Paint, la couleur Color.Black est remplacée par Color.Blue:

  private void pictureBox_Paint(object sender, PaintEventArgs e) { Graphics g = e.Graphics; using (Bitmap bmp = new Bitmap("myImage.png")) { // Set the image atsortingbute's color mappings ColorMap[] colorMap = new ColorMap[1]; colorMap[0] = new ColorMap(); colorMap[0].OldColor = Color.Black; colorMap[0].NewColor = Color.Blue; ImageAtsortingbutes attr = new ImageAtsortingbutes(); 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); } } 

Plus d’informations: http://msdn.microsoft.com/en-us/library/4b4dc1kz%28v=vs.110%29.aspx

Je vais vous donner une autre solution car cela ne calcule pas pour chaque pixel.

C’est court et simple. Le temps de conversion est de 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 ColorMasortingx //now is set to red, but with different values //you can get anything you want. ColorMasortingx colorMasortingx = new ColorMasortingx( 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 atsortingbutes ImageAtsortingbutes atsortingbutes = new ImageAtsortingbutes(); //set the color masortingx atsortingbute atsortingbutes.SetColorMasortingx(colorMasortingx); //draw original image on the new image using the color masortingx g.DrawImage(original, new Rectangle(0, 0, original.Width, original.Height), 0, 0, original.Width, original.Height, GraphicsUnit.Pixel, atsortingbutes); //release sources used g.Dispose(); return newBitmap; }