Jak działa algorytm pokolorowania listy utworów w iTunes 11? [Zamknięte]

297

Nowy iTunes 11 ma bardzo ładny widok na listę utworów z albumu, wybierając kolory czcionek i tła w zależności od okładki albumu. Czy ktoś zorientował się, jak działa algorytm?

Trzeci przykład

LuisEspinoza
źródło
9
Formuła kontrastu kolorów w3c może być częścią odpowiedzi. Moje własne testy empiryczne pokazują, że ta formuła jest używana przez MS Word do decydowania o tym, że jest to czcionka automatycznie kolorująca. Wyszukaj „Jasność kolorów zależy od następującego wzoru” [formuła kontrastu kolorów w3c] [1] [1]: w3.org/TR/AERT#color-contrast
bluedog
@bluedog, myślę, że masz rację. Próbowałem wielu okładek albumów i zawsze czcionka ma wystarczający kontrast z tłem, aby wyraźnie je obejrzeć.
LuisEspinoza
1
Należy jeszcze zauważyć, że wydaje się różnić między Mac OS i Windows: twitter.com/grimfrog/status/275187988374380546
Tom Irving
2
Mogłem sobie wyobrazić, że może nie tylko ilość kolorów, ale także ich wartości nasycenia są częścią obliczeń: moje eksperymenty doprowadziły mnie do wniosków, że kolory podświetlenia są często wybierane jako kolor tła, chociaż występują w kilku obszarach wizerunek. Dlatego uważam, że spojrzenie na histogram obrazu okładki i jego pików może być użyteczne, a na podstawie niektórych dokładnie dostrojonych parametrów wybierany jest kolor.
Raffael,
2
Zobacz kolejną odpowiedź na panic.com/blog/2012/12/itunes-11-and-colours
Mark Ransom,

Odpowiedzi:

423

Przykład 1

Przybliżyłem algorytm kolorów iTunes 11 w Mathematica, biorąc pod uwagę okładkę albumu jako dane wejściowe:

Wyjście 1

Jak to zrobiłem

Dzięki próbom i błędom opracowałem algorytm, który działa na ~ 80% albumów, z którymi go testowałem.

Różnice kolorów

Większość algorytmu dotyczy znalezienia dominującego koloru obrazu. Warunkiem znalezienia dominujących kolorów jest jednak obliczenie mierzalnej różnicy między dwoma kolorami. Jednym ze sposobów obliczenia różnicy między dwoma kolorami jest obliczenie ich odległości euklidesowej w przestrzeni kolorów RGB. Jednak postrzeganie kolorów przez ludzi nie pasuje zbyt dobrze do odległości w przestrzeni kolorów RGB.

Dlatego napisałem funkcję konwersji kolorów RGB (w formularzu {1,1,1}) na YUV , przestrzeń kolorów, która jest znacznie lepsza w przybliżeniu postrzegania kolorów:

(EDYCJA: @cormullion i @Drake wskazali, że wbudowane przestrzenie kolorów CIELAB i CIELUV Mathematiki byłyby równie odpowiednie ... wygląda na to, że wymyśliłem nieco koło tutaj)

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
    ]

Następnie napisałem funkcję do obliczania odległości kolorów z powyższą konwersją:

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

Dominujące kolory

Szybko odkryłem, że wbudowana funkcja Mathematica DominantColorsnie pozwala na wystarczająco precyzyjną kontrolę, aby zbliżyć się do algorytmu używanego przez iTunes. Zamiast tego napisałem własną funkcję ...

Prostą metodą obliczenia dominującego koloru w grupie pikseli jest zebranie wszystkich pikseli w wiadra o podobnych kolorach, a następnie znalezienie największego wiadra.

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

Należy pamiętać, że .1jest to tolerancja dla tego, jak różne kolory muszą być uważane za osobne. Zauważ też, że chociaż wejściem jest tablica pikseli w surowej formie trypletu ( {{1,1,1},{0,0,0}}), zwracam RGBColorelement Mathematica , aby lepiej przybliżyć wbudowaną DominantColorsfunkcję.

Moja faktyczna funkcja DominantColorsNewdodaje opcję powrotu do ndominujących kolorów po odfiltrowaniu danego innego koloru. Ujawnia również tolerancje dla każdego porównania kolorów:

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
    ]

Reszta algorytmu

Najpierw zmieniłem rozmiar okładki albumu ( 36px, 36px) i zmniejszyłem szczegółowość dzięki dwustronnemu filtrowi

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

iTunes wybiera kolor tła, znajdując dominujący kolor wzdłuż krawędzi albumu. Jednak ignoruje wąskie ramki okładek albumów, przycinając obraz.

thumb = ImageCrop[thumb, 34];

Następnie znalazłem dominujący kolor (z nową funkcją powyżej) wzdłuż najbardziej zewnętrznej krawędzi obrazu z domyślną tolerancją wynoszącą .1.

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

Na koniec zwróciłem 2 dominujące kolory na obrazie jako całości, mówiąc funkcji odfiltrowania również koloru tła.

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

Powyższe wartości tolerancji są następujące: .1minimalna różnica między „oddzielnymi” kolorami; .2to minimalna różnica między wieloma dominującymi kolorami (niższa wartość może zwrócić czerń i ciemnoszary, a wyższa wartość zapewnia większą różnorodność dominujących kolorów);.5to minimalna różnica między dominującymi kolorami a tłem (wyższa wartość da kombinacje kolorów o większym kontraście)

Voila!

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

Ostateczne wyjście

Notatki

Algorytm można zastosować bardzo ogólnie. Poprawiłem powyższe ustawienia i wartości tolerancji do punktu, w którym działają one w celu uzyskania ogólnie poprawnych kolorów dla ~ 80% testowanych okładek albumów. Kilka przypadków krawędzi występuje, gdyDominantColorsNew nie można znaleźć dwóch kolorów, które można by zwrócić w celu wyróżnienia (tj. Gdy okładka albumu jest monochromatyczna). Mój algorytm nie zajmuje się tymi przypadkami, ale powielenie funkcjonalności iTunes byłoby trywialne: gdy album zawiera mniej niż dwie podświetlenia, tytuł staje się biały lub czarny, w zależności od najlepszego kontrastu z tłem. Następnie piosenki stają się jednym wyróżnionym kolorem, jeśli taki istnieje, lub kolor tytułu nieco wyblakł w tle.

Więcej przykładów

Więcej przykładów

Seth Thompson
źródło
3
OK @Seth Thompson, wydaje się to bardzo obiecujące. Spróbuję sam, zajmie mi to kilka dni, proszę o cierpliwość.
LuisEspinoza,
6
Całkiem niesamowite rozwiązanie. Teraz potrzebujesz portu od Mathematica do Objective-C, co jest trudną walką.
loretoparisi,
1
+1 za tę bardzo szczegółową odpowiedź!
Marius Schulz,
1
@ Cormullion LUV (i LAB) oba dążą do jednorodności percepcyjnej. Nie znalazłem jednak żadnych wyraźnych odniesień do używania odległości euklidesowych w żadnej z przestrzeni kolorów. Domyślam się, że gdyby nic innego, oba byłyby lepsze niż RGB.
Seth Thompson,
6
To, co lubię nazywać „odpowiedzią Chucka Norrisa”
MCKapur
44

Z odpowiedzią @ Seth-Thompson i komentarzem @bluedog buduję mały projekt Objective-C (Cocoa-Touch) w celu generowania schematów kolorów w funkcji obrazu.

Możesz sprawdzić projekt na:

https://github.com/luisespinoza/LEColorPicker

Na razie LEColorPicker wykonuje:

  1. Obraz jest skalowany do 36 x 36 pikseli (skraca to czas obliczeń).
  2. Generuje tablicę pikseli z obrazu.
  3. Konwertuje tablicę pikseli na przestrzeń YUV.
  4. Zbieraj kolory tak, jak robi to kod Setha Thompsona.
  5. Zestawy kolorów są sortowane według liczby.
  6. Algorytm wybiera trzy najbardziej dominujące kolory.
  7. Najbardziej dominujący jest przypisany jako Tło.
  8. Drugi i trzeci najbardziej dominujący testowany jest przy użyciu formuły kontrastu kolorów w3c, aby sprawdzić, czy kolory mają wystarczający kontrast z tłem.
  9. Jeśli jeden z kolorów tekstu nie przejdzie testu, zostanie przypisany do białego lub czarnego, w zależności od komponentu Y.

Na razie sprawdzę projekt ColorTunes ( https://github.com/Dannvix/ColorTunes ) i projekt Wade Cosgrove pod kątem nowych funkcji. Mam też kilka nowych pomysłów na ulepszenie wyniku schematu kolorów.

Screenshot_Mona

LuisEspinoza
źródło
2
+1 - Bardzo fajne rzeczy i świetny przykład tego, jak rozwój algorytmu i aplikacji może być bardzo interesujący sam w sobie
Yuval Karmi
1
+1 za sprawdzenie kontrastu.
brianmearns
Tak fajnie, ale jak zaokrąglasz wartości skrótu dla każdego koloru? Myślę, że mógłbym łatwo złamać ten algorytm, po prostu dodając małe czarno-białe logo „Explicit” w prawym dolnym rogu, naprawdę dodajesz skupienie na czerni i bieli. W każdym razie ten algorytm działałby lepiej w przypadku obrazów opartych na rysunkach, ale jeśli masz obraz o wymiarach 36 x 36, przypadki niepowodzenia będą rzadsze dzięki wygładzaniu krawędzi
Jack Franzen
Jedno słowo: FANTASTYCZNY!
Teddy
16

Wade Cosgrove z Panic napisał fajny post na blogu opisujący swoją implementację algorytmu zbliżonego do tego z iTunes. Zawiera przykładową implementację w Objective-C.

Mike Akers
źródło
15

Możesz także pobrać ColorTunes, która jest implementacją HTML widoku albumu Itunes, która korzysta z algorytmu MMCQ (mediana kwantyzacji koloru cięcia).

Matthias
źródło
tak, już to sprawdziłem. Niestety wydaje się ledwo udokumentowane.
LuisEspinoza
Ważnym komentarzem w ColorTunes jest odniesienie do (algorytm kwantyzacji cięcia mediany) [ leptonica.com/papers/mediancut.pdf] . Właśnie zaimplementowałem to w pythonie w ciągu około 2 godzin, po prostu stwórz opis w artykule i wolę to niż moja implementacja powyższego algorytmu Setha. Wyniki podoba mi się trochę lepiej, ale co najważniejsze, jest nieco szybsze (oczywiście mogłem niepoprawnie zaimplementować algorytm Setha).
brianmearns
@ sh1ftst0rm czy masz implementację Pythona na github czy gdzieś? na zdrowie
Anentropic 03
@Anentropic Przepraszamy, nie mam. Był to część prywatnego projektu, nad którym pracowałem i wcale go nie wyodrębniłem. Jeśli będę miał okazję, postaram się gdzieś opublikować, ale prawdopodobnie nie będzie to możliwe w najbliższym czasie.
brianmearns
5

Właśnie napisałem bibliotekę JS implementującą mniej więcej ten sam algorytm, który opisał @Seth . Jest dostępny za darmo na github.com/arcanis/colibrijs i na NPM as colibrijs.

Maël Nison
źródło