web-dev-qa-db-fra.com

Comment fonctionne l'algorithme pour colorer la liste de chansons dans iTunes 11?

Le nouvel iTunes 11 offre une vue très agréable pour la liste des chansons d’un album, en sélectionnant les couleurs des polices et de l’arrière-plan en fonction de la couverture de l’album. Quelqu'un a compris comment fonctionne l'algorithme?

Third Example

295
LuisEspinoza

Example 1

J'ai approximé l'algorithme de couleur iTunes 11 dans Mathematica en me servant de la couverture de l'album:

Output 1

Comment je l'ai fait

Par essais et erreurs, j'ai mis au point un algorithme qui fonctionne sur environ 80% des albums avec lesquels je l'ai testé.

Différences de couleur

L’essentiel de l’algorithme consiste à trouver la couleur dominante d’une image. Une condition préalable à la recherche de couleurs dominantes consiste toutefois à calculer une différence quantifiable entre deux couleurs. Une façon de calculer la différence entre deux couleurs consiste à calculer leur distance euclidienne dans l'espace colorimétrique RVB. Cependant, la perception des couleurs par l'homme ne correspond pas très bien à la distance dans l'espace colorimétrique RVB.

Par conséquent, j’ai écrit une fonction permettant de convertir les couleurs RVB (sous la forme {1,1,1}) en YUV , un espace colorimétrique beaucoup plus performant pour l’approximation de la perception des couleurs:

(EDIT: @ cormullion et @ Drake a souligné que les espaces colorimétriques intégrés de Mathematica, CIELAB et CIELUV, conviendraient tout aussi bien ... on dirait que j'ai réinventé un peu la roue ici)

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
    ]

Ensuite, j'ai écrit une fonction pour calculer la distance de couleur avec la conversion ci-dessus:

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

Couleurs Dominantes

J'ai rapidement découvert que la fonction intégrée Mathematica DominantColors ne permettait pas un contrôle suffisamment fin pour approcher l'algorithme utilisé par iTunes. J'ai écrit ma propre fonction à la place ...

Une méthode simple pour calculer la couleur dominante dans un groupe de pixels consiste à rassembler tous les pixels dans des compartiments de couleurs similaires, puis à rechercher le plus grand compartiment.

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

Notez que .1 est la tolérance permettant de distinguer les différentes couleurs. Notez également que bien que l'entrée soit un tableau de pixels sous forme de triplet brut ({{1,1,1},{0,0,0}}), je retourne un élément Mathematica RGBColor pour mieux approcher la fonction intégrée DominantColors.

Ma fonction actuelle DominantColorsNew ajoute la possibilité de retourner jusqu'à n couleurs dominantes après avoir filtré une autre couleur. Il expose également les tolérances pour chaque comparaison de couleur:

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
    ]

Le reste de l'algorithme

J'ai d'abord redimensionné la couverture de l'album (36px, 36px) et réduit les détails avec un filtre bilatéral

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

iTunes choisit la couleur d'arrière-plan en recherchant la couleur dominante sur les bords de l'album. Cependant, il ignore les frontières étroites de la couverture de l'album en recadrant l'image.

thumb = ImageCrop[thumb, 34];

Ensuite, j'ai trouvé la couleur dominante (avec la nouvelle fonction ci-dessus) le long du bord le plus externe de l'image avec une tolérance par défaut de .1.

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

Enfin, j'ai renvoyé 2 couleurs dominantes dans l'ensemble de l'image, en indiquant à la fonction de filtrer également la couleur d'arrière-plan.

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

Les valeurs de tolérance ci-dessus sont les suivantes: .1 est la différence minimale entre les couleurs "séparées"; .2 est la différence minimale entre de nombreuses couleurs dominantes (une valeur faible peut retourner en noir et gris foncé, tandis qu'une valeur supérieure garantit une plus grande diversité des couleurs dominantes); .5 est la différence minimale entre les couleurs dominantes et l'arrière-plan (une valeur plus élevée produira des combinaisons de couleurs plus contrastées)

Voilà!

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

Final Output

Remarques

L'algorithme peut être appliqué de manière très générale. J'ai ajusté les paramètres et les valeurs de tolérance ci-dessus au point où ils produisent des couleurs généralement correctes pour environ 80% des couvertures d'albums que j'ai testées. Quelques cas de Edge se produisent lorsque DominantColorsNew ne trouve pas deux couleurs à renvoyer pour les points forts (c'est-à-dire lorsque la couverture de l'album est monochrome). Mon algorithme ne traite pas de ces cas, mais il serait trivial de dupliquer les fonctionnalités d'iTunes: lorsque l'album contient moins de deux temps forts, le titre devient blanc ou noir en fonction du meilleur contraste avec l'arrière-plan. Ensuite, les chansons deviennent la couleur de surbrillance s'il en existe une ou la couleur du titre s'estompe un peu dans l'arrière-plan.

Plus d'exemples

More Examples

422
Seth Thompson

Avec la réponse de @ Seth-thompson et le commentaire de @bluedog, je construis un petit projet Objective-C (Cocoa-Touch) pour générer des schémas de couleurs en fonction d'une image.

Vous pouvez vérifier le projet à:

https://github.com/luisespinoza/LEColorPicker

Pour le moment, LEColorPicker fait:

  1. L'image est redimensionnée à 36x36 px (cela réduit le temps de calcul).
  2. Il génère un tableau de pixels à partir de l'image.
  3. Convertit le tableau de pixels en espace YUV.
  4. Rassemblez les couleurs comme le code de Seth Thompson le fait.
  5. Les jeux de couleurs sont triés par nombre.
  6. L'algorithme sélectionne les trois couleurs les plus dominantes.
  7. La plus dominante est attribuée à Background.
  8. Les deuxième et troisième dominants sont testés à l'aide de la formule de contraste de couleurs w3c, afin de vérifier si les couleurs ont suffisamment contrasté avec l'arrière-plan.
  9. Si l'une des couleurs du texte ne réussit pas le test, elle est affectée au blanc ou au noir, en fonction du composant Y.

Pour le moment, je vérifierai le projet ColorTunes ( https://github.com/Dannvix/ColorTunes ) et le projet Wade Cosgrove pour les nouvelles fonctionnalités. J'ai aussi de nouvelles idées pour améliorer le résultat de la palette de couleurs.

Screenshot_Mona

44
LuisEspinoza

Wade Cosgrove de Panic a écrit un joli billet de blog décrivant son implémentation d’un algorithme qui se rapproche de celui d’iTunes. Il inclut un exemple d'implémentation dans Objective-C.

16
Mike Akers

Vous pouvez également passer à la caisse ColorTunes , qui est une implémentation HTML de la vue de l'album iTunes qui utilise l'algorithme MMCQ (quantification des couleurs de découpe médiane).

15
Matthias

Avec la réponse de @ Seth, j'ai implémenté l'algorithme pour obtenir la couleur dominante dans les deux bords latéraux d'une image en utilisant PHP et Imagick.

https://Gist.github.com/philix/5688064#file-simpleimage-php-L81

Il est utilisé pour remplir le fond des photos de couverture dans http://festea.com.br

5
philix

Je viens d'écrire une bibliothèque JS implémentant à peu près le même algorithme que celui décrit par @ Seth . Il est disponible gratuitement sur github.com/arcanis/colibrijs , et sur NPM en tant que colibrijs.

5
Maël Nison

J'ai posé la même question dans un contexte différent et j'ai été pointé vers http://charlesleifer.com/blog/using-python-and-k-means-to-find-the-dominant-colors-in- images / pour un algorithme d'apprentissage (k signifie) qui fait grossièrement la même chose en utilisant des points de départ aléatoires dans l'image. De cette façon, l'algorithme trouve les couleurs dominantes par lui-même.

4
thomi