Wie funktioniert der Algorithmus zum Färben der Songliste in iTunes 11? [geschlossen]

297

Das neue iTunes 11 bietet eine sehr schöne Ansicht für die Songliste eines Albums und wählt die Farben für die Schriftarten und den Hintergrund in Abhängigkeit vom Albumcover aus. Hat jemand herausgefunden, wie der Algorithmus funktioniert?

Drittes Beispiel

LuisEspinoza
quelle
9
Die w3c-Farbkontrastformel könnte Teil der Antwort sein. Meine eigenen Empircal-Tests zeigen, dass diese Formel von MS Word verwendet wird, um zu entscheiden, ob es sich um eine automatische Farbschrift handelt. Suche nach "Die Farbhelligkeit wird durch die folgende Formel bestimmt" [w3c Farbkontrastformel] [1] [1]: w3.org/TR/AERT#color-contrast
bluedog
@bluedog, ich denke du hast recht. Ich habe viele meiner Albumcover ausprobiert und die Schrift hat immer genug Kontrast zum Hintergrund, um sie klar zu sehen.
LuisEspinoza
1
Noch etwas zu beachten ist, dass es zwischen Mac OS und Windows zu unterscheiden scheint: twitter.com/grimfrog/status/275187988374380546
Tom Irving
2
Ich könnte mir vorstellen, dass vielleicht nicht nur die Menge der Farben, sondern auch deren Sättigungswerte Teil der Berechnung sind: Meine Experimente führten mich zu dem Schluss, dass Hervorhebungsfarben häufig als Hintergrundfarbe ausgewählt werden, obwohl sie in wenigen Bereichen der Farbe auftreten Bild. Aus diesem Grund glaube ich, dass es nützlich sein könnte, das Histogramm des Titelbilds und seine Spitzen zu betrachten, und basierend auf einigen fein abgestimmten Parametern wird die Farbe ausgewählt.
Raffael
2
Eine weitere Antwort finden Sie unter Panic.com/blog/2012/12/itunes-11-and-colors
Mark Ransom

Antworten:

423

Beispiel 1

Ich habe den iTunes 11-Farbalgorithmus in Mathematica anhand des Albumcovers als Eingabe angenähert:

Ausgabe 1

Wie ich es gemacht habe

Durch Versuch und Irrtum habe ich einen Algorithmus gefunden, der auf ~ 80% der Alben funktioniert, mit denen ich ihn getestet habe.

Farbunterschiede

Der Großteil des Algorithmus befasst sich mit dem Finden der dominanten Farbe eines Bildes. Voraussetzung für das Auffinden dominanter Farben ist jedoch die Berechnung eines quantifizierbaren Unterschieds zwischen zwei Farben. Eine Möglichkeit, die Differenz zwischen zwei Farben zu berechnen, besteht darin, ihren euklidischen Abstand im RGB-Farbraum zu berechnen. Die menschliche Farbwahrnehmung passt jedoch nicht sehr gut zur Entfernung im RGB-Farbraum.

Daher habe ich eine Funktion zum Konvertieren von RGB-Farben (in der Form {1,1,1}) in YUV geschrieben , einen Farbraum, der die Farbwahrnehmung viel besser approximieren kann:

(EDIT: @cormullion und @Drake wiesen darauf hin, dass die eingebauten CIELAB- und CIELUV-Farbräume von Mathematica genauso geeignet wären ... es sieht so aus, als hätte ich das Rad hier etwas neu erfunden)

convertToYUV[rawRGB_] :=
    Module[{yuv},
        yuv = {{0.299, 0.587, 0.114}, {-0.14713, -0.28886, 0.436},
            {0.615, -0.51499, -0.10001}};
        yuv . rawRGB
    ]

Als nächstes schrieb ich eine Funktion zur Berechnung des Farbabstands mit der obigen Konvertierung:

ColorDistance[rawRGB1_, rawRGB2_] := 
    EuclideanDistance[convertToYUV @ rawRGB1, convertToYUV @ rawRGB2]

Dominante Farben

Ich stellte schnell fest, dass die integrierte Mathematica-Funktion DominantColorsnicht genügend fein abgestimmte Steuerelemente zulässt, um den von iTunes verwendeten Algorithmus zu approximieren. Ich habe stattdessen meine eigene Funktion geschrieben ...

Eine einfache Methode zur Berechnung der dominanten Farbe in einer Gruppe von Pixeln besteht darin, alle Pixel in Eimern ähnlicher Farben zu sammeln und dann den größten Eimer zu finden.

DominantColorSimple[pixelArray_] :=
    Module[{buckets},
        buckets = Gather[pixelArray, ColorDistance[#1,#2] < .1 &];
        buckets = Sort[buckets, Length[#1] > Length[#2] &];
        RGBColor @@ Mean @ First @ buckets
    ]

Beachten Sie, dass dies .1die Toleranz dafür ist, wie unterschiedliche Farben als getrennt betrachtet werden müssen. Beachten Sie auch, dass die Eingabe zwar ein Array von Pixeln in roher Triplettform ( {{1,1,1},{0,0,0}}) ist, ich jedoch ein Mathematica- RGBColorElement zurückgebe, um die integrierte DominantColorsFunktion besser zu approximieren .

Meine eigentliche Funktion DominantColorsNewfügt die Option hinzu, nnach dem Herausfiltern einer bestimmten anderen Farbe zu dominanten Farben zurückzukehren. Außerdem werden Toleranzen für jeden Farbvergleich angezeigt:

DominantColorsNew[pixelArray_, threshold_: .1, n_: 1, 
    numThreshold_: .2, filterColor_: 0, filterThreshold_: .5] :=
    Module[
        {buckets, color, previous, output},
        buckets = Gather[pixelArray, ColorDistance[#1, #2] < threshold &];
        If[filterColor =!= 0, 
        buckets = 
            Select[buckets, 
                ColorDistance[ Mean[#1], filterColor] > filterThreshold &]];
        buckets = Sort[buckets, Length[#1] > Length[#2] &];
        If[Length @ buckets == 0, Return[{}]];
        color = Mean @ First @ buckets;
        buckets = Drop[buckets, 1];
        output = List[RGBColor @@ color];
        previous = color;
        Do[
            If[Length @ buckets == 0, Return[output]];
            While[
                ColorDistance[(color = Mean @ First @ buckets), previous] < 
                    numThreshold, 
                If[Length @ buckets != 0, buckets = Drop[buckets, 1], 
                    Return[output]]
            ];
            output = Append[output, RGBColor @@ color];
            previous = color,
            {i, n - 1}
        ];
        output
    ]

Der Rest des Algorithmus

Zuerst habe ich die Größe des Albumcovers ( 36px, 36px) geändert und die Details mit einem bilateralen Filter reduziert

image = Import["http://i.imgur.com/z2t8y.jpg"]
thumb = ImageResize[ image, 36, Resampling -> "Nearest"];
thumb = BilateralFilter[thumb, 1, .2, MaxIterations -> 2];

iTunes wählt die Hintergrundfarbe aus, indem es die dominierende Farbe an den Rändern des Albums findet. Durch Beschneiden des Bildes werden jedoch schmale Albumcover-Ränder ignoriert.

thumb = ImageCrop[thumb, 34];

Als nächstes fand ich die dominante Farbe (mit der neuen Funktion oben) am äußersten Rand des Bildes mit einer Standardtoleranz von .1.

border = Flatten[
    Join[ImageData[thumb][[1 ;; 34 ;; 33]] , 
        Transpose @ ImageData[thumb][[All, 1 ;; 34 ;; 33]]], 1];
background = DominantColorsNew[border][[1]];

Zuletzt habe ich 2 dominante Farben im gesamten Bild zurückgegeben und die Funktion angewiesen, auch die Hintergrundfarbe herauszufiltern.

highlights = DominantColorsNew[Flatten[ImageData[thumb], 1], .1, 2, .2, 
    List @@ background, .5];
title = highlights[[1]];
songs = highlights[[2]];

Die obigen Toleranzwerte sind wie folgt: .1ist die minimale Differenz zwischen "getrennten" Farben; .2ist der minimale Unterschied zwischen zahlreichen dominanten Farben (ein niedrigerer Wert kann Schwarz und Dunkelgrau zurückgeben, während ein höherer Wert eine größere Vielfalt der dominanten Farben gewährleistet); .5ist der minimale Unterschied zwischen dominanten Farben und dem Hintergrund (Ein höherer Wert ergibt kontrastreichere Farbkombinationen)

Voila!

Graphics[{background, Disk[]}]
Graphics[{title, Disk[]}]
Graphics[{songs, Disk[]}]

Endgültige Ausgabe

Anmerkungen

Der Algorithmus kann sehr allgemein angewendet werden. Ich habe die obigen Einstellungen und Toleranzwerte so weit angepasst, dass sie für ~ 80% der von mir getesteten Albumcover allgemein korrekte Farben erzeugen. Einige Randfälle treten auf, wenn DominantColorsNewkeine zwei Farben für die Highlights gefunden werden (dh wenn das Albumcover monochrom ist). Mein Algorithmus behandelt diese Fälle nicht, aber es wäre trivial, die Funktionalität von iTunes zu duplizieren: Wenn das Album weniger als zwei Glanzlichter liefert, wird der Titel je nach bestem Kontrast zum Hintergrund weiß oder schwarz. Dann werden die Songs zu der einen Hervorhebungsfarbe, wenn es eine gibt, oder die Titelfarbe tritt etwas in den Hintergrund.

Mehr Beispiele

Mehr Beispiele

Seth Thompson
quelle
3
OK @ Seth Thompson, es scheint sehr vielversprechend. Ich werde es selbst versuchen, es wird ein paar Tage dauern, bitte haben Sie etwas Geduld.
LuisEspinoza
6
Ziemlich tolle Lösung. Jetzt brauche ich einen Port von Mathematica nach Objective-C, das ist ein harter Kampf.
Loretoparisi
1
+1 für diese sehr detaillierte Antwort!
Marius Schulz
1
@cormullion LUV (und LAB) streben beide eine einheitliche Wahrnehmung an. Ich fand jedoch keine expliziten Hinweise auf die Verwendung euklidischer Abstände in beiden Farbräumen. Ich vermute, wenn nicht anders, wären beide besser als RGB.
Seth Thompson
6
Dies ist, was ich gerne eine "Chuck Norris Antwort"
nenne
44

Mit der Antwort von @ Seth-thompson und dem Kommentar von @bluedog baue ich ein kleines Objective-C-Projekt (Cocoa-Touch), um Farbschemata in Abhängigkeit von einem Bild zu generieren.

Sie können das Projekt überprüfen unter:

https://github.com/luisespinoza/LEColorPicker

Im Moment macht LEColorPicker:

  1. Das Bild wird auf 36 x 36 Pixel skaliert (dies reduziert die Rechenzeit).
  2. Es erzeugt ein Pixelarray aus dem Bild.
  3. Konvertiert das Pixelarray in YUV-Raum.
  4. Sammeln Sie Farben wie es Seth Thompsons Code tut.
  5. Die Farbsätze sind nach Anzahl sortiert.
  6. Der Algorithmus wählt die drei dominantesten Farben aus.
  7. Die dominanteste wird als Hintergrund zugeordnet.
  8. Die zweit- und dritthäufigsten Dominanten werden mit der Farbkontrastformel w3c getestet, um zu überprüfen, ob die Farben genügend Kontrast zum Hintergrund haben.
  9. Wenn eine der Textfarben den Test nicht besteht, wird sie je nach Y-Komponente Weiß oder Schwarz zugewiesen.

Im Moment werde ich das ColorTunes-Projekt ( https://github.com/Dannvix/ColorTunes ) und das Wade Cosgrove-Projekt auf neue Funktionen überprüfen . Außerdem habe ich einige neue Ideen zur Verbesserung des Farbschemaergebnisses.

Screenshot_Mona

LuisEspinoza
quelle
2
+1 - Sehr cooles Zeug und ein großartiges Beispiel dafür, wie sowohl Algorithmusentwicklung als auch Anwendungsentwicklung für sich genommen sehr interessant sein können
Yuval Karmi
1
+1 zur Überprüfung des Kontrasts.
Brianmearns
Ja cool, aber wie runden Sie die Hash-Werte für jede Farbe? Ich denke, ich könnte diesen Algorithmus leicht brechen, indem ich einfach ein kleines schwarz-weißes "Explicit" -Logo unten rechts hinzufüge, fügst du wirklich einen Fokus für schwarz und weiß hinzu. Wie auch immer, dieser Algorithmus würde besser für Clip-Art-basierte Bilder funktionieren, aber wenn Sie das Bild bei 36x36 haben, werden diese Fehlerfälle durch das Anti-Aliasing seltener
Jack Franzen
Ein Wort: FANTASTISCH!
Teddy
16

Wade Cosgrove von Panic schrieb einen schönen Blog-Beitrag, in dem er seine Implementierung eines Algorithmus beschrieb, der dem in iTunes nahekommt. Es enthält eine Beispielimplementierung in Objective-C.

Mike Akers
quelle
15

Sie können auch ColorTunes auschecken , eine HTML-Implementierung der Itunes- Albumansicht, die den MMCQ-Algorithmus (Median Cut Color Quantization) verwendet.

Matthias
quelle
ja ich überprüfe es schon Scheint leider kaum dokumentiert.
LuisEspinoza
Der wichtige Kommentar in ColorTunes ist der Verweis auf den (Median Cut Quantization Algorithmus) [ leptonica.com/papers/mediancut.pdf] . Ich habe dies gerade in Python in ungefähr 2 Stunden implementiert. Bilden Sie einfach die Beschreibung im Papier und ziehen Sie es meiner Implementierung des obigen Seth-Algorithmus vor. Ich mag die Ergebnisse etwas besser, aber am wichtigsten ist, dass sie viel schneller sind (natürlich hätte ich Seths Algorithmus falsch implementieren können).
Brianmearns
@ sh1ftst0rm hast du deine Python-Implementierung auf Github oder irgendwo? prost
Anentropic
@Anentropic Sorry, ich nicht. Es war Teil eines privaten Projekts, an dem ich gearbeitet habe, und ich habe es überhaupt nicht herausgezogen. Wenn ich die Gelegenheit dazu bekomme, werde ich versuchen, es irgendwo zu posten, aber es wird wahrscheinlich nicht so bald sein.
Brianmearns
5

Ich habe gerade eine JS-Bibliothek geschrieben, die ungefähr den gleichen Algorithmus implementiert wie den von @Seth beschriebenen . Es ist frei verfügbar unter github.com/arcanis/colibrijs und auf NPM as colibrijs.

Maël Nison
quelle