2010-03-30 19 views
8

Je souhaite récupérer la couleur majoritaire dans une image d'arrière-plan dans .NET. C'est possible?Comment obtenir une couleur majoritaire dans une image?

+0

Pouvez-vous préciser le sens de la 'couleur majoritaire'? Voulez-vous dire la couleur la plus souvent utilisée dans une image; la couleur moyenne d'une image; la couleur 'la plus élevée' valeur équivilant RGB? – Seidr

+3

Vous avez probablement besoin de clarifier ce que vous entendez par "couleur majoritaire". Pour la plupart des images, il est peu probable qu'une seule couleur constitue la majorité appropriée. Je suppose que vous voulez dire soit la couleur la plus fréquente (pixel par pixel), soit la composante dominante (R, G ou B). – MusiGenesis

+0

Avez-vous besoin de vitesse ou de précision? Voulez-vous également la couleur la plus utilisée, la couleur moyenne ou la couleur de tendance? Avez-vous besoin de RVB mélangé ou sperated? –

Répondre

6

Vous pouvez parcourir tous les pixels de l'image et utiliser la méthode getPixel pour déterminer la valeur RVB. Vous pouvez alors avoir un dictionnaire qui stocke la valeur ARGB avec un nombre. Vous pouvez ensuite voir quelle valeur ARGB est la plus présente dans l'image.

var list = new Dictionary<int, int>(); 
Bitmap myImage = (Bitmap)Bitmap.FromFile("C:/test.jpeg"); 
for (int x = 0; x < myImage.Width; x++) 
{ 
    for (int y = 0; y < myImage.Height; y++) 
    { 
     int rgb = myImage.GetPixel(x, y).ToArgb(); 
     if (!list.ContainsKey(rgb)) 
      list.Add(rgb, 1); 
     else 
      list[rgb]++; 
    } 
} 

Comme indiqué, ceci n'a aucune sympathie pour des couleurs similaires. Si vous vouliez une couleur majoritaire plus «générale», vous pourriez avoir un seuil de similarité. par exemple. plutôt que:

if (!list.ContainsKey(rgb)) 
     list.Add(rgb, 1); 
    else 
     list[rgb]++; 

vous pouvez faire:

var added = false; 
for (int i = 0; i < 10; i++) 
{ 
    if (list.ContainsKey(rgb+i)) 
    { 
     list[rgb+i]++; 
     added = true; 
     break; 
    } 
    if (list.ContainsKey(rgb-i)) 
    { 
     list[rgb-i]++; 
     added = true; 
     break; 
    } 
} 
if(!added) 
    list.Add(rgb, 1); 

Vous pouvez le seuil de 10 à tout ce que vous avez besoin.

+0

S'il s'agit d'un jpeg "true color" ... qui pourrait contenir des tonnes de valeurs dans le dictionnaire avec très peu de comptes par clé. –

+0

D'accord. Vous aurez besoin d'une sorte de binning ou de regroupement pour travailler décemment. Avec celui-ci vous pourriez avoir 2 pixels parfaitement rouges et une tonne de variantes subtiles de noir et sortir avec le rouge comme couleur majoritaire. – RandomEngy

+0

Eh bien techniquement, le rouge serait alors la couleur majoritaire. – CeejeeB

3

En supposant que vous caractérisez la couleur de chaque pixel en utilisant RGB (par exemple, CMYK), vous pouvez construire un tableau 3d (une dimension pour R, G et B). Décidez ensuite du nombre de bacs que vous voulez avoir dans chaque dimension - plus vous avez de bacs, plus grande est la différenciation que vous faites entre des teintes similaires. Une fois cela fait, il suffit de parcourir une représentation bitmap de votre image en additionnant les # pixels qui tombent dans chacune des cellules de votre tableau 3d. La cellule avec la somme la plus élevée sera la couleur prédominante.

Vous voudrez probablement rendre votre algorithme facilement configurable pour les # cases de chaque dimension afin que vous puissiez ajuster à quel point il distingue les couleurs similaires.

image = new Bitmap("C:\\test.bmp", true); 
int x, y; 
// Loop through the images pixels to product 3d histogram 
for(x=0; x<image.Width; x++) 
{ 
    for(y=0; y<image.Height; y++) 
    { 
     Color pixelColor = image.GetPixel(x, y); 

     // Increment color count in appropriate cell of your 3d histogram here 
     ... 
    } 
} 
5

La couleur moyenne de l'image sera renvoyée.

static Color AverageColor(string fileName) 
{ 
    using (var bmp = new Bitmap(fileName)) 
    { 
     int width = bmp.Width; 
     int height = bmp.Height; 
     int red = 0; 
     int green = 0; 
     int blue = 0; 
     int alpha = 0; 
     for (int x = 0; x < width; x++) 
      for (int y = 0; y < height; y++) 
      { 
       var pixel = bmp.GetPixel(x, y); 
       red += pixel.R; 
       green += pixel.G; 
       blue += pixel.B; 
       alpha += pixel.A; 
      } 

     Func<int, int> avg = c => c/(width * height); 

     red = avg(red); 
     green = avg(green); 
     blue = avg(blue); 
     alpha = avg(alpha); 

     var color = Color.FromArgb(alpha, red, green, blue); 

     return color; 
    } 
} 
+0

Je ne pense pas que le résultat se qualifie comme "couleur majoritaire" car il pourrait ne pas y avoir même un pixel qui est la couleur moyenne. – Kaniu

+0

Très vrai ... et c'est pourquoi j'ai demandé plus de détails dans mon commentaire sous la question. Pas de réponse donc c'est mon entrée. –

4

Ceci retournera la couleur moyenne de l'image en utilisant un accès au pointeur non sécurisé. Note: le code est seulement adapté pour 24bppRgb, pourrait être adapté pour d'autres formats de pixels.

unsafe static Color GetColor(string filename) 
    { 
     using (var image = (Bitmap)Bitmap.FromFile(filename)) 
     { 
      if (image.PixelFormat != PixelFormat.Format24bppRgb) throw new NotSupportedException(String.Format("Unsupported pixel format: {0}", image.PixelFormat)); 

      var pixelSize = 3; 
      var bounds = new Rectangle(0, 0, image.Width, image.Height); 
      var data = image.LockBits(bounds, ImageLockMode.ReadOnly, image.PixelFormat); 

      long r = 0; 
      long g = 0; 
      long b = 0; 

      for (int y = 0; y < data.Height; ++y) 
      { 
       byte* row = (byte*)data.Scan0 + (y * data.Stride); 
       for (int x = 0; x < data.Width; ++x) 
       { 
        var pos = x * pixelSize; 
        b += row[pos]; 
        g += row[pos + 1]; 
        r += row[pos + 2]; 
       } 
      } 

      r = r/(data.Width * data.Height); 
      g = g/(data.Width * data.Height); 
      b = b/(data.Width * data.Height); 
      image.UnlockBits(data); 

      return Color.FromArgb((int)r, (int)g, (int)b); 
     } 
    } 

essentiel: http://gist.github.com/349210

+0

+1 pour la performance. L'appel de GetPixel sur chaque pixel est extrêmement lent. – RandomEngy

+1

Extrêmement lent est un peu exagéré. J'ai été en mesure d'utiliser la méthode GetPixel pour analyser les images vidéo à 15fps 800x600. Donc, si l'affiche a juste besoin d'analyser une seule image GetPixel est plus que suffisant. – CeejeeB

Questions connexes