Frage

Ich versuche herauszufinden, wie man alle Pixel in einem Bild probiert und eine Farbpalette daraus erzeugt, so etwas wie Dies oder Dies. Ich habe keine Ahnung, wo ich überhaupt anfangen soll. Kann mir jemand in die richtige Richtung verweisen?

__BEARBEITEN: __

Das habe ich bisher gelandet:

Ich habe das benutzt Pixel Funktion, um große Blockabschnitte zu erhalten, wie Joe_Coolish vorgeschlagen. Es funktioniert perfekt und gibt mir ein ziemlich gutes Beispiel von Farben, mit denen ich arbeiten kann (dies stammt aus dem Windows -Beispiel für Jelly Fish -Bild):

Wenn mir jemand helfen könnte, die 5 unterschiedlichsten Farben (dunkelste blau, hellste Blau, Orange, Grau und Pfirsich (?)) Zu bekommen, würde ich dich für immer lieben. Ich verstehe wirklich nicht, wie es geht Durchschnitt oder hinzufügen Farben zusammen. Ich kann auch nicht herausfinden, wie ich feststellen kann, ob eine Farbe programmatisch ähnlich ist. Es gibt viele Zahlen und Variablen in Ihren Erklärungen, die ich verirrte, um herauszufinden, was mit wem das tut.

War es hilfreich?

Lösung

Die Antworten mit dem Code zeigen Ihnen, wie Sie die vollständige Palette erhalten. Wenn Sie die durchschnittlichen Farben wie auf den von Ihnen geposteten Websites erhalten möchten, würde ich es so tun.

Quellbild:

Source

Erstens würde ich die Farben durch Durchschnitt eines Tiefpassfilters durchschnittlich (so etwas wie eine Gaußsche Unschärfe) durchschnittlich

enter image description here

Auf diese Weise begrenzen Sie die Gesamtpalette. Von dort aus würde ich den Bildschirm in N -Blöcke teilen (n ist die Gesamtzahl der Pixel, die Sie in Ihrer Palette möchten).

enter image description here

Von dort aus zielen Sie jeden Block ab und iterieren Sie sie über jedes Pixel und erhalten Sie das durchschnittliche Pixel für diesen Block und fügen Sie ihn zu Ihrem Palettenindex hinzu. Das Ergebnis ist so etwas:

enter image description here

Auf diese Weise ist Ihre Palette begrenzt und Sie erhalten die durchschnittlichen Farben aus den verschiedenen Regionen. Sie können das alles im Code machen, und wenn Sie etwas helfen möchten, lassen Sie es mich wissen und ich werde einige veröffentlichen. Dies ist nur das hohe Niveau "Was ich tun würde".

Andere Tipps

Nehmen Sie zunächst die Pixel auf dem Bild: (Angenommen using System.Drawing.Imaging; und using System.Runtime.InteropServices)

Bitmap b = new Bitmap(myImage);
BitmapData bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, ImageFormat.Format32Bpp);
int[] arr = new int[bd.Width * bd.Height - 1];
Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
b.UnlockBits(bd);

Dann können Sie Ihre Palette erstellen:

var distinctColors = arr.Distinct();

Optional: Beseitigen Sie ähnliche Farben, bis Sie Ihre bevorzugte Palettengröße haben. So können Sie das tun (obwohl dies definitiv nicht der effizienteste oder genaueste Weg ist, nur der einfachste):

var dc = distinctColors.toArray(); // int dc[] = distinctColors.toArray() is what it used to be
int cmIndex1 = -1;
int cmIndex2 = -1;
int cmDiff = -1;
for (int i = 0; i < dc.length; i++) {
    Color c1 = Color.FromArgb(dc[i]);
    for (int j = i + 1; j < dc.length; j++) {
        Color c2 = Color.FromArgb(dc[j]);
        // Note: you might want to include alpha below
        int diff = Math.Abs(c1.R - c2.R) + Math.Abs(c1.G - c2.G) + Math.Abs(c1.B - c2.B);
        if (cmDiff < 0 || diff < cmDiff) {
            cmIndex1 = i;
            cmIndex2 = j;
            cmDiff = diff;
        }
    }
}
// Remove the colors, replace with average, repeat until you have the desired number of colors

In jedem satten Bild ist es wahrscheinlich, dass die meisten Ihrer Farben in irgendeiner Weise einzigartig sind. Es würde also folgen, dass es Ihnen wahrscheinlich nicht helfen wird, Ihr Ziel zu erreichen.

Ich empfehle, die HSV -Werte für jedes Pixel in Ihrem Bild zu inspizieren. Ich werde Sie unzähligen Online -Beispielen für das Abrufen von Bildern als Arrays von HSV -Werten überlassen.

Mit Ihren HSV -Werten können Sie Cluster von herausragenden Farbtönen berechnen, indem Sie ein ganzzahliges Array von 256 Hue -Zählungen erstellen, wodurch ein Histogramm von Farbtönen in Ihren Bilddaten berechnet wird. Sie können herausragende Farbtöne bestimmen, indem Sie Cluster von 4-6 sequentiellen Farbtönen mit einer hohen Anzahl der Anzahl finden.

Nach mehreren prominenten Farbtönen sammeln die Pixel dieser Farbtöne in ein anderes Histogramm, das die Sättigung misst, und sammeln prominente Cluster und so weiter.

Grobe Beispiel

In dem folgenden Code wird versucht, herausragende Farbtöne zu identifizieren. Es gibt höchstwahrscheinlich andere großartige Möglichkeiten, dies zu tun. Dies kann jedoch einige Ideen liefern.

Zuerst bekomme ich alle Bildfarben als eine Reihe von Color Objekte wie SO:

private static Color[] GetImageData(Image image)
{
    using (var b = new Bitmap(image))
    {
        var bd = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
        byte[] arr = new byte[bd.Width * bd.Height * 3];
        Color[] colors = new Color[bd.Width * bd.Height];
        Marshal.Copy(bd.Scan0, arr, 0, arr.Length);
        b.UnlockBits(bd);

        for (int i = 0; i < colors.Length; i++)
        {
            var start = i*3;
            colors[i] = Color.FromArgb(arr[start], arr[start + 1], arr[start + 2]);
        }

        return colors;
    }
}

Sie könnten in Betracht ziehen, zu validieren, dass ich die Reihenfolge von RGB in der bekommen habe Color.FromArgb Methodenaufruf in der richtigen Reihenfolge.

Als nächstes habe ich eine Versorgungsmethode zur Konvertierung in HSV beiseite. In meinem Beispiel werde ich nur mit Farbtönen arbeiten, aber hier ist ein vollständiges Beispiel für die Konvertierung:

private static void ColorToHSV(Color color, out int hue, out int saturation, out int value)
{
    int max = Math.Max(color.R, Math.Max(color.G, color.B));
    int min = Math.Min(color.R, Math.Min(color.G, color.B));

    hue = (int)(color.GetHue() * 256f / 360f);
    saturation = (max == 0) ? 0 : (int)(1d - (1d * min / max));
    value = (int)(max / 255d);
}

Schließlich baue ich das Farbton -Histogramm, definiere eine Breite von Farbtönen (z. B. 9 Farbtöne), in denen ich zusammenzählen kann, und dann melde ich die Zählungen der Konsole.

private static void ProcessImage(Color[] imagecolors)
{
    var hues = new int[256];
    var hueclusters = new int[256];
    int hue, saturation, value;

    // build hue histogram.
    foreach (var color in imagecolors) {
        ColorToHSV(color, out hue, out saturation, out value);
        hues[hue]++;
    }

    // calculate counts for clusters of colors.
    for (int i = 0; i < 256; i++) {
        int huecluster = 0;
        for (int count = 0, j = i; count < 9; count++, j++) {
            huecluster += hues[j % 256];
        }

        hueclusters[(i + 5) % 256] = huecluster;
    }

    // Print clusters on the console
    for (int i = 0; i < 256; i++) {
        Console.WriteLine("Hue {0}, Score {1}.", i, hueclusters[i]);
    }
}

Ich habe keinen Versuch unternommen, zu filtern die Farbtöne zu wählen. Möglicherweise müssen Sie einige Heuristiken in Betracht ziehen, anstatt blind die Top-So-Viele-Zählungen zu entscheiden, da Sie wahrscheinlich Farbtöne auswählen möchten, die im Farbspektrum etwas getrennt sind. Ich habe keine Zeit, dies weiter zu erkunden, aber ich hoffe, dass dies einen Einblick in eine Strategie bietet, die Sie in Betracht ziehen können.

Ich habe hier angefangen:

System.Drawing.Image img = System.Drawing.Bitmap.FromFile("file");
System.Drawing.Imaging.ColorPalette palette = img.Palette;
foreach (Color color in palette.Entries)
{
  //...
}

Ich werde den besten Ansatz auf einem sehr hohen Niveau beschreiben.

Zuerst konstruieren Sie ein Histogramm von Farben im Bild und deren Frequenz.

Am Ende haben Sie eine Liste aller Farben im Bild. Sie können Datenclustering verwenden, um Kandidatenfarben zu finden, um zusammenzuarbeiten. Farben, die basierend auf der Frequenz der ursprünglichen Farben zu einem gewichteten Durchschnitt zusammengeführt werden.

Auf diese Weise können Sie die Palette schrittweise auf eine gewünschte Treue verringern, während Sie hohe Kontrast, aber feine Details erhalten und nur die Treue verlieren, wo die Gradienten viel subtiler sind.

Sobald Sie die reduzierte Palette haben, werden Sie das Bild mit der nächsten Nachbarfarbe in der Palette erneut einverstanden.

Das K-means Der Clustering -Algorithmus funktioniert gut für dieses Problem. Es macht eine großartige Aufgabe, Zentroide von Bildfarbclustern zu extrahieren, ist sich jedoch bewusst, dass sein nicht deterministisches Verhalten die tatsächliche Bedeutung jedes Clusters schwierig macht.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top