Frage

In meinem C # (3.5) Anwendung Ich brauche die durchschnittliche Farbwerte für die roten, grünen und blauen Kanäle einer Bitmap zu erhalten. Vorzugsweise ohne eine externe Bibliothek. Kann dies geschehen? Wenn das so ist, wie? Vielen Dank im Voraus.

Der Versuch, die Dinge ein wenig genauer zu machen: Jedes Pixel in der Bitmap hat einen bestimmten RGB-Farbwert. Ich mag die durchschnittlichen RGB-Werte für alle Pixel im Bild erhalten.

War es hilfreich?

Lösung

Der schnellste Weg ist durch unsicheren Code verwendet:

BitmapData srcData = bm.LockBits(
            new Rectangle(0, 0, bm.Width, bm.Height), 
            ImageLockMode.ReadOnly, 
            PixelFormat.Format32bppArgb);

int stride = srcData.Stride;

IntPtr Scan0 = srcData.Scan0;

long[] totals = new long[] {0,0,0};

int width = bm.Width;
int height = bm.Height;

unsafe
{
  byte* p = (byte*) (void*) Scan0;

  for (int y = 0; y < height; y++)
  {
    for (int x = 0; x < width; x++)
    {
      for (int color = 0; color < 3; color++)
      {
        int idx = (y*stride) + x*4 + color;

        totals[color] += p[idx];
      }
    }
  }
}

int avgB = totals[0] / (width*height);
int avgG = totals[1] / (width*height);
int avgR = totals[2] / (width*height);

Hüten Sie sich vor: Ich habe diesen Code nicht testen ... (ich einige Ecken schneiden haben)

Dieser Code auch asssumes ein 32-Bit-Bild. Für 24-Bit-Bilder. Ändern Sie die x * 4 x * 3

Andere Tipps

Hier ist eine viel einfachere Art und Weise:

Bitmap bmp = new Bitmap(1, 1);
Bitmap orig = (Bitmap)Bitmap.FromFile("path");
using (Graphics g = Graphics.FromImage(bmp))
{
    // updated: the Interpolation mode needs to be set to 
    // HighQualityBilinear or HighQualityBicubic or this method
    // doesn't work at all.  With either setting, the results are
    // slightly different from the averaging method.
    g.InterpolationMode = InterpolationMode.HighQualityBicubic;
    g.DrawImage(orig, new Rectangle(0, 0, 1, 1));
}
Color pixel = bmp.GetPixel(0, 0);
// pixel will contain average values for entire orig Bitmap
byte avgR = pixel.R; // etc.

Grundsätzlich Sie verwenden DrawImage die ursprüngliche Bitmap in ein 1-Pixel-Bitmap zu kopieren. Der RGB-Wert des Pixels 1 wird dann repräsentiert die Mittelwert für das gesamte Original. GetPixel ist relativ langsam, aber nur wenn Sie es auf einem großen Bitmap, Pixel-für-Pixel. Nenne es einmal hier ist kein großes Problem.

LockBits Verwendung ist in der Tat schnell, aber einige Windows-Benutzer haben Sicherheitsrichtlinien, die die Ausführung von „unsicheren“ Code verhindern. Ich erwähne das, weil diese Tatsache hat mich gebissen nur auf dem Hintern vor kurzem.

Aktualisieren : mit InterpolationMode auf HighQualityBicubic gesetzt, nimmt diese Methode etwa doppelt so lang wie bei LockBits im Durchschnitt; mit HighQualityBilinear, es dauert nur etwas länger als LockBits. Also, wenn die Benutzer eine Sicherheitsrichtlinie, die unsafe Code verbietet, auf jeden Fall nicht die Methode verwenden.

Update 2: im Laufe der Zeit habe ich jetzt erkennen, warum dieser Ansatz überhaupt nicht funktionieren. Selbst die hochwertigsten Interpolation Algorithmen integrieren nur wenige benachbarte Pixel, also gibt es ein Limit, wie viel kann ein Bild ohne Verlust Informationen zerquetscht gelegt. Und ein Bild Quetschen auf ein Pixel nach unten ist auch über diese Grenze hinaus, egal welche Algorithmus Sie verwenden.

Der einzige Weg, dies zu tun wäre, um das Bild in Schritten zu schrumpfen (vielleicht ist es um die Hälfte jedes Mal schrumpft), bis es auf die Größe eines Pixels zu bekommen. Ich kann nicht ausdrücken in bloßen Worten, was eine völlige Zeitverschwendung wäre so etwas wie dieses zu schreiben, also bin ich froh, dass ich mich angehalten, wenn ich daran dachte. :)

Bitte, niemand Stimme für diese Antwort mehr -. Es könnte meine dümmste Idee jemals sein

Diese Art der Sache funktioniert, aber es kann nicht schnell genug zu sein, um so nützlich.

public static Color getDominantColor(Bitmap bmp)
{

       //Used for tally
       int r = 0;
       int g = 0;
       int b = 0;

     int total = 0;

     for (int x = 0; x < bmp.Width; x++)
     {
          for (int y = 0; y < bmp.Height; y++)
          {
               Color clr = bmp.GetPixel(x, y);

               r += clr.R;
               g += clr.G;
               b += clr.B;

               total++;
          }
     }

     //Calculate average
     r /= total;
     g /= total;
     b /= total;

     return Color.FromArgb(r, g, b);
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top