2015-01-26 13 views
17

ModificaDifferenze tra Colori palette Android

Per ottenere una migliore sensazione per la classe Palette Android, ho deciso di fare una semplice applicazione per testare alcune delle sue caratteristiche - se siete interessati, potete trovare l'applicazione nel Play Store: https://play.google.com/store/apps/details?id=com.tonyw.sampleapps.palettecolorextraction. Fondamentalmente ha solo le immagini e i colori estratti dalla classe Palette (menzionati sotto), e puoi anche aggiungere le tue immagini per testare. È possibile trovare il mio codice sorgente su GitHub: https://github.com/tony-w/PaletteColorExtraction

Screenshots Some pictures with corresponding extracted colors Another picture with extracted colors Title and body text color extracted based on background color

Original post

Qualcuno può descrivere le differenze tra i colori che possono essere estratti da una bitmap utilizzando Android's Palette class?

  • vibrante
  • vibrante scuro
  • luce vibrante
  • sordina
  • sordina scuro
  • sordina Luce

E 'solo che i colori tenui sono più opaca rispetto colori vivaci? L'oscurità e la luce dovrebbero corrispondere meglio ai temi di design dei materiali scuri e chiari di Lollipop, rispettivamente?

risposta

27

Questa è davvero una bella domanda. Se guardi allo source code puoi vedere che i diversi campioni vengono scelti analizzando il profilo di colore HSL dei pixel sull'immagine, in base agli intervalli target di luminanza, saturazione e popolazione (quanti pixel nell'immagine sono rappresentati dal campione). Utilizza un calcolo della media ponderata con preferenza data a luminanza, quindi a saturazione, quindi a popolazione.

In generale, i colori vivaci sono più saturi rispetto ai colori tenui, i colori scuri sono più scuri e quelli chiari sono più chiari. Quale si utilizza dipende dall'effetto generale che si desidera.

Chris Banes wrote in his blog "Vibrant e Dark Vibrant sono quelli che gli sviluppatori useranno principalmente" ma in pratica non è così semplice.

Un esempio che ho trovato è il metodo in Romain Guy's sample app da Google IO 2014, anche se il codice presuppone che i vari campioni verranno trovati (probabilmente perché sta lavorando con immagini conosciute).

A seconda dell'immagine, è possibile che alcuni tipi di campioni non vengano trovati, quindi accertarsi di tenere conto di tale possibilità nel codice.

Ad esempio, è possibile provare a prelevare campioni dalla tavolozza in un ordine specifico, ad es. per un tema Dark potresti provare a ottenere Vibrant Dark, quindi Muted Dark, e quindi tornare su un colore predefinito.

Se si desidera qualcosa che è un po 'più prevedibile, è anche possibile afferrare il colore più rappresentato, in questo modo:

public static Palette.Swatch getDominantSwatch(Palette palette) { 
    // find most-represented swatch based on population 
    return Collections.max(palette.getSwatches(), new Comparator<Palette.Swatch>() { 
     @Override 
     public int compare(Palette.Swatch sw1, Palette.Swatch sw2) { 
      return Integer.compare(sw1.getPopulation(), sw2.getPopulation()); 
     } 
    }); 
} 

I valori HSL per ciascun campione sono anche accessibili, così si potrebbe scrivere una routine simile da scegliere, ad esempio, il campione più saturo che non sia il colore dominante.


Uso obiettivi personalizzati

Un'altra cosa che ho trovato utile è definire alcuni obiettivi personalizzati in aggiunta ai 6 obiettivi definiti nei Palette.Target, con diversi pesi e indirizzare valori di luminosità e saturazione, in per aumentare la possibilità di trovare un colore utile.

Ad esempio, si può chiedere di quantizzazione di Palette per includere un campione per il colore più dominante che soddisfa i criteri di filtro attuali con un obiettivo come questo:

public static final Target DOMINANT; 

static { 
    DOMINANT = new Target.Builder().setPopulationWeight(1f) 
            .setSaturationWeight(0f) 
            .setLightnessWeight(0f) 
            .setExclusive(false) 
            .build(); 
} 

E si può ottenere alcuni campioni utili che mettono a maggiore priorità sulla leggerezza rispetto agli obiettivi stock come questo:

public static final Target DARK; 
public static final Target LIGHT; 
public static final Target NEUTRAL; 

static { 
    DARK = new Target.Builder().setMinimumLightness(0f) 
           .setTargetLightness(0.26f) 
           .setMaximumLightness(0.5f) 
           .setMinimumSaturation(0.1f) 
           .setTargetSaturation(0.6f) 
           .setMaximumSaturation(1f) 
           .setPopulationWeight(0.18f) 
           .setSaturationWeight(0.22f) 
           .setLightnessWeight(0.60f) 
           .setExclusive(false) 
           .build(); 

    LIGHT = new Target.Builder().setMinimumLightness(0.50f) 
           .setTargetLightness(0.74f) 
           .setMaximumLightness(1.0f) 
           .setMinimumSaturation(0.1f) 
           .setTargetSaturation(0.7f) 
           .setMaximumSaturation(1f) 
           .setPopulationWeight(0.18f) 
           .setSaturationWeight(0.22f) 
           .setLightnessWeight(0.60f) 
           .setExclusive(false) 
           .build(); 

    NEUTRAL = new Target.Builder().setMinimumLightness(0.20f) 
            .setTargetLightness(0.5f) 
            .setMaximumLightness(0.8f) 
            .setMinimumSaturation(0.1f) 
            .setTargetSaturation(0.6f) 
            .setMaximumSaturation(1f) 
            .setPopulationWeight(0.18f) 
            .setSaturationWeight(0.22f) 
            .setLightnessWeight(0.60f) 
            .setExclusive(false) 
            .build(); 
} 

è possibile accedere al campione trovato per un target personalizzato dopo che è stato generato utilizzando Palette.getSwatchForTarget, ad esempio:

Palette.Swatch neutral = Palette.getSwatchForTarget(NEUTRAL); 

Siate consapevoli del filtro predefinito

Per impostazione predefinita Palette ha un Palette.Filter che rifiuta i colori molto vicino al bianco o nero, così come i colori "molto vicino alla linea I rossa" che credo si riferisca a colori isocroni che sono difficili per le persone con cecità ai daltonici.

La mia teoria è che rifiuta i colori quasi bianco e quasi nero al fine di evitare che vengano scelti come colori "saturi" quando la saturazione è fortemente ponderata.

Il risultato di questo filtro tuttavia è che non verrà trovato alcun campione per le immagini che consistono interamente di pixel quasi bianchi e/o quasi neri, nonché una tendenza ad evitare di scegliere i colori con una tonalità rosata.

Tuttavia, è possibile rimuovere questo filtro utilizzando Palette.Builder.clearFilters() e aggiungere il proprio filtro con Palette.Builder.addFilter().

Nel mio codice ho scelto di fare un secondo tentativo di generare una tavolozza se il primo tentativo non restituisce alcun campioni:

Palette palette = new Palette.Builder(bitmap).addTarget(DOMINANT) 
              .addTarget(DARK) 
              .addTarget(LIGHT) 
              .addTarget(NEUTRAL) 
              .generate(); 
if(palette.getSwatches().isEmpty()) { 
    Log.v(TAG, "Getting alternate (UNFILTERED) palette."); 
    palette = new Palette.Builder(bitmap).addTarget(DOMINANT) 
             .addTarget(DARK) 
             .addTarget(LIGHT) 
             .addTarget(NEUTRAL) 
             .clearFilters() /// allow isBlack(), isWhite(), isNearRedILine() 
             .generate(); 
} 

concatenazione i tentativi conserva l'utilità del filtro di default nella maggior parte casi, ma consente comunque di trovare campioni per le immagini che l'impostazione predefinita rifiuterebbe completamente.

+1

Ottima risposta, grazie! Apprezzo anche le idee per buoni fallback quando non si trovano campioni. :) –

+0

A partire dalla palette-v7: 25.0.0, ora esiste un metodo di convenienza chiamato getDominantSwatch: l'implementazione di un metodo personalizzato non dovrebbe più essere necessaria. Il resto della risposta è ancora valida e buona però! –

+0

@DavidDoyle Sì, è vero! Hanno aggiunto un metodo equivalente che seleziona il campione con la popolazione più alta. Tuttavia devo ammettere che nel mio codice ho trovato più efficace usare il bersaglio dominante (con peso di popolazione 1f e gli altri pesi 0f) perché trova un colore più dominante in generale, invece di scegliere il campione più popolato tra quelli che ha soddisfatto gli altri criteri di destinazione (VIBRANT, MUTED, ecc.). –