2

Si vous avez une instance System.Drawing.Bitmap qui contient une image en niveaux de gris, existe-t-il un moyen de la "coloriser" avec l'influence d'une autre couleur? Par exemple, si vous aviez une image en noir et blanc (échelle de gris) d'une tasse de café et que vous vouliez créer des images séparées de versions rouge, verte et violette par programmation."Coloriser" un bitmap dans .NET

Répondre

5

Je n'ai pas d'exemple de code à donner mais voici un moyen de le faire. Convertissez chaque pixel de RVB en HSV et changez le composant Teinte et Saturation sur chaque pixel. La teinte contrôle la couleur. La valeur devrait rester la même. Le résultat sera un bitmap avec la même légèreté et l'obscurité, mais avec une couleur différente.

Editer: voici un exemple. Notez la mise à jour de la teinte et de la saturation.

 public static Color ColorFromAhsb(int a, float h, float s, float b) 
    { 

     if (0 > a || 255 < a) 
     { 
      throw new Exception("a"); 
     } 
     if (0f > h || 360f < h) 
     { 
      throw new Exception("h"); 
     } 
     if (0f > s || 1f < s) 
     { 
      throw new Exception("s"); 
     } 
     if (0f > b || 1f < b) 
     { 
      throw new Exception("b"); 
     } 

     if (0 == s) 
     { 
      return Color.FromArgb(a, Convert.ToInt32(b * 255), 
       Convert.ToInt32(b * 255), Convert.ToInt32(b * 255)); 
     } 

     float fMax, fMid, fMin; 
     int iSextant, iMax, iMid, iMin; 

     if (0.5 < b) 
     { 
      fMax = b - (b * s) + s; 
      fMin = b + (b * s) - s; 
     } 
     else 
     { 
      fMax = b + (b * s); 
      fMin = b - (b * s); 
     } 

     iSextant = (int)Math.Floor(h/60f); 
     if (300f <= h) 
     { 
      h -= 360f; 
     } 
     h /= 60f; 
     h -= 2f * (float)Math.Floor(((iSextant + 1f) % 6f)/2f); 
     if (0 == iSextant % 2) 
     { 
      fMid = h * (fMax - fMin) + fMin; 
     } 
     else 
     { 
      fMid = fMin - h * (fMax - fMin); 
     } 

     iMax = Convert.ToInt32(fMax * 255); 
     iMid = Convert.ToInt32(fMid * 255); 
     iMin = Convert.ToInt32(fMin * 255); 

     switch (iSextant) 
     { 
      case 1: 
       return Color.FromArgb(a, iMid, iMax, iMin); 
      case 2: 
       return Color.FromArgb(a, iMin, iMax, iMid); 
      case 3: 
       return Color.FromArgb(a, iMin, iMid, iMax); 
      case 4: 
       return Color.FromArgb(a, iMid, iMin, iMax); 
      case 5: 
       return Color.FromArgb(a, iMax, iMin, iMid); 
      default: 
       return Color.FromArgb(a, iMax, iMid, iMin); 
     } 

    } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     var bmp = new Bitmap("c:\\bw.bmp"); 

     foreach (int y in Enumerable.Range(0, bmp.Height)) 
     { 
      foreach (int x in Enumerable.Range(0,bmp.Width)) 
      { 
       var p = bmp.GetPixel(x, y); 
       var h = p.GetHue(); 

       var c = ColorFromAhsb(p.A, p.GetHue() + 200, p.GetSaturation() + 0.5f, p.GetBrightness()); 
       bmp.SetPixel(x, y, c);      
      } 
     } 
     pictureBox1.Image = bmp; 
     //bmp.Dispose(); 

    } 
+0

Merci. Cela fonctionne très bien modifié légèrement. Quelle est la signification de "p.GetSaturation() + 0.5f"? Le 0.5 semble gâcher les choses si la couleur "colorante" est elle-même une nuance de gris (la sortie est rougeâtre), mais être requise autrement. – xyz

+0

@frou - Dans le bitmap que j'utilisais, la saturation était de 0. Si la saturation est nulle, la modification de la teinte ne change pas la couleur. Je viens d'ajouter un 0.5 arbitraire à la valeur zéro. La saturation devrait être n'importe quelle valeur supérieure à zéro et inférieure ou égale à 1. – Steve

1

Je créerais une copie de l'image originale et les mettrait une image semi-transparente séparée de la couleur désirée du dessus.

Mise à jour: voir exemple à http://www.codeproject.com/KB/cs/Merge_Images_in_C_.aspx

+0

Comment faites-vous cela? Vous auriez à spécifier un "moduler" plutôt qu'un type additif de fusion de calques, non? – xyz

1

See here

Je l'ai utilisé dans le passé. Vous voulez regarder spécifiquement ToSepia. Vous devrez peut-être déconstruire un peu, mais cela a fonctionné pour moi.

1

Je ne suis pas sûr d'un construit en chemin, mais, si vous représentez chaque couleur comme un flotteur plutôt que d'un octet (255 devient 1 - pleine intensité), en multipliant le chaque canal avec la couleur désirée devrait donner l'effet Tu es en train de parler de.

(1,1,1) "white" * (1,0,0) "red" = (1,0,0) "red" 

(0.5,0.5, 0.5) "grey" * (0,1,0) "green" = (0,0.5,0) "dark green" 

Vous devez cependant appliquer cette valeur par pixel.

+0

Merci. L'approche "HSV" donne des résultats plus beaux pour moi - je ne comprends pas parfaitement pourquoi :) – xyz

2

S'il s'agit d'une image 8 bits, vous pouvez simplement utiliser une palette différente (Image.Palette). C'est essentiellement une table de recherche qui attribue une valeur de couleur à chaque valeur d'octet de pixel possible. Beaucoup plus rapide que de changer tous les pixels d'une boucle.

Questions connexes