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?
J'ai approximé l'algorithme de couleur iTunes 11 dans Mathematica en me servant de la couverture de l'album:
Par essais et erreurs, j'ai mis au point un algorithme qui fonctionne sur environ 80% des albums avec lesquels je l'ai testé.
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]
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
]
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[]}]
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.
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:
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.
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.
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).
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
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
.
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.