2010-03-30 3 views
8

Ich möchte die Mehrheit Farbe in einem Hintergrundbild in .NET abrufen. Ist es möglich?Wie erhält man eine Mehrheitsfarbe in einem Bild?

+0

Können Sie die Bedeutung von 'Mehrheit Farbe' klären? Meinst du die Farbe, die am häufigsten in einem Bild verwendet wird? die durchschnittliche Farbe eines Bildes; der 'höchste' Farbäquivalent RGB? – Seidr

+3

Sie müssen wahrscheinlich klären, was Sie mit "Mehrheitsfarbe" meinen. Bei den meisten Bildern ist es unwahrscheinlich, dass eine Farbe eine richtige Mehrheit darstellt. Ich nehme an, Sie meinen entweder die häufigste Farbe (Pixel für Pixel) oder die dominierende Komponente (entweder R, G oder B). – MusiGenesis

+0

Benötigen Sie Geschwindigkeit oder Genauigkeit? Möchten Sie auch die am häufigsten verwendete Farbe, durchschnittliche Farbe oder Trendfarbe? Brauchen Sie RGB gemischt oder speriert? –

Antwort

6

Sie können alle Pixel im Bild durchlaufen und mithilfe der getPixel-Methode den RGB-Wert ermitteln. Sie können dann ein Wörterbuch haben, das den ARGB-Wert zusammen mit einer Zählung speichert. Sie können dann sehen, welcher ARGB-Wert am meisten im Bild vorhanden ist.

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

Wie bereits erwähnt, hat dies keine Sympathie für ähnliche Farben. Wenn Sie eine mehr generelle Farbe wünschen, können Sie einen Schwellenwert für Ähnlichkeit haben. z.B. statt:

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

könnten Sie tun:

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

Sie könnten die Schwelle von 10, was auch immer Sie benötigt werden.

+0

Wenn dies eine "echte Farbe" JPEG ist ... das könnte Tonnen von Werten im Wörterbuch mit sehr wenigen Zählimpulsen pro Schlüssel sein. –

+0

Einverstanden. Sie benötigen eine Art Binning oder Gruppierung, um anständig zu arbeiten. Mit diesem könnte man 2 perfekt rote Pixel und eine Tonne subtile Varianten von Schwarz haben und mit Rot als Hauptfarbe herauskommen. – RandomEngy

+0

Technisch gesehen wäre Rot dann die Hauptfarbe. – CeejeeB

3

Angenommen, Sie charakterisieren die Farbe jedes Pixels mit RGB (im Gegensatz zu, sagen wir CMYK), könnten Sie ein 3D-Array (jeweils eine Dimension für R, G und B) bauen. Entscheiden Sie sich dann für die Anzahl der Fächer, die Sie in jeder Dimension haben möchten - je mehr Fächer, desto größer ist die Differenzierung zwischen ähnlichen Farbtönen.

Sobald das erledigt ist, durchlaufen Sie einfach eine Bitmap-Darstellung Ihres Bildes summieren die # Pixel, die in jede der Zellen in Ihrem 3D-Array fällt. Die Zelle mit der höchsten Summe wird die vorherrschende Farbe sein.

Wahrscheinlich möchten Sie Ihren Algorithmus für die # Bins in jeder Dimension leicht konfigurierbar machen, damit Sie einstellen können, wie stark er zwischen ähnlichen Farben unterscheidet.

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

Dies wird die durchschnittliche Farbe für das Bild zurück.

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

Ich glaube nicht, dass das Ergebnis als "Mehrheitsfarbe" gilt, da es nicht einmal ein Pixel gibt, das eine durchschnittliche Farbe hat. – Kaniu

+0

Sehr wahr ... und deshalb fragte ich in meinem Kommentar unter der Frage nach mehr Details. Keine Antwort, das ist mein Eintrag. –

4

Dies wird die durchschnittliche Farbe für das Bild mit unsicheren Zeiger Zugriff zurückgeben. Hinweis: Code ist nur für 24bppRgb angepasst, könnte für andere Pixelformate angepasst werden.

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

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

+0

+1 für die Leistung. Der Aufruf von GetPixel auf jedem einzelnen Pixel ist extrem langsam. – RandomEngy

+1

Extrem langsam ist ein bisschen übertrieben. Ich konnte die GetPixel-Methode verwenden, um Videoframes mit 15fps 800x600 zu analysieren. Wenn das Poster also nur ein einzelnes Bild analysieren muss, ist GetPixel mehr als ausreichend. – CeejeeB

Verwandte Themen