2011-12-12 8 views
26

Puoi capire perché sto cercando di trovare il colore dominante in un'immagine se usi Windows 7. Quando passi il mouse su un programma nella barra delle applicazioni, lo sfondo di quel particolare programma cambia in base al colore più dominante nell'icona. Ho notato questa tecnica anche in altri programmi, ma non riesco a ricordarli in cima alla mia testa.Trovare il colore dominante di un'immagine in un dispositivo Android @ estraibile

Riesco a vedere che questo è utile in una serie di tecniche di interfaccia utente che sto usando per sviluppare un'applicazione, e mi chiedevo come trovare il colore più comune sarebbe stato ottenuto da una risorsa disegnabile Android.

+0

una nuova API è stato aggiunto con il Lollipop che aiuta a estrarre i colori di primo piano da una bitmap. Vedi [la mia risposta sotto] (http://stackoverflow.com/a/28145358/1956632) per i dettagli. Poiché la classe Palette menzionata si trova nella libreria support7, dovrebbe funzionare anche nelle versioni precedenti di Android. –

+0

supporto per la tavolozza di Android v7 lib lo fa per noi. Tutti cercano demo http://code2concept.blogspot.in/2015/10/android-support-v7-palette-demo.html – nitesh

risposta

48

In Android 5.0 Lollipop, una classe è stato aggiunto per aiutare a estrarre i colori utili da una bitmap. La classe Palette, trovata in android.support.v7.grafica, possono estrarre i seguenti colori:

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

Questa pagina di allenamento Android dà tutti i dettagli necessari per utilizzare la classe (l'ho provato io stesso in Android Studio ed è stato molto semplice): http://developer.android.com/training/material/drawables.html#ColorExtract

Per citare:

L'Android Support Library r21 e soprattutto include la classe Palette , che permette di estrarre i colori di primo piano da un'immagine. Per estrarre questi colori, passare un oggetto Bitmap al metodo statico Palette.generate() nel thread in background in cui si caricano le immagini. Se non è possibile utilizzare quel filo, chiamare il metodo Palette.generateAsync() e fornire un ascoltatore invece. *

È possibile recuperare i colori di spicco l'immagine utilizzando il getter metodi nella classe Palette, come ad come Palette.getVibrantColor.

per utilizzare la classe Palette nel progetto, aggiungere il seguente Gradle dipendenza modulo della tua app:

dependencies { 
    ... 
    compile 'com.android.support:palette-v7:21.0.+' 
} 

* Se avete bisogno di utilizzare generateAsync(), ecco come fare:

Palette.generateAsync(bitmap, new Palette.PaletteAsyncListener() { 
    public void onGenerated(Palette palette) { 
     // Do something with colors... 
    } 
}); 

MODIFICA: Poiché la domanda chiede come estrarre i colori da una risorsa estraibile, è necessario convertire il drawable in una bitmap per utilizzare la tecnica che ho descritto. Per fortuna, che è abbastanza semplice utilizzando BitmapFactory:

Bitmap icon = BitmapFactory.decodeResource(context.getResources(), 
             R.drawable.icon_resource);` 
+0

Se vuoi sperimentare con quali colori viene estratta la classe Palette, controlla la mia app sul Play Store: https://play.google.com/store/apps/details?id=com.tonyw.sampleapps.palettecolorextraction. Puoi trovare il codice sorgente su GitHub: https://github.com/tony-w/PaletteColorExtraction –

+2

Ottima risposta. Ciò rende la maggior parte delle librerie e dei metodi disponibili ridondanti. – Baz

+0

Penso che sarebbe meglio spiegare tutto, in questo modo sarebbe più chiaro ... –

2

Passa attraverso tutti i dati dei colori del pixel e media i valori dei colori, ignora tutto ciò che è una sfumatura di grigio o trasparente. Credo che sia ciò che Microsoft fa in Windows 7 sulla base di un recente post sul blog.

modificare
Il post sul blog: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx

Questo link che mostra come Chrome prende il colore dominante può anche essere utile. http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the-color-for-the-stripes-on-the-Most-visited-page-thumbnails

+0

speravo che ci fosse una funzione API sepolto in profondità da qualche parte. Questa è una buona informazione – styler1972

+2

Ho trovato un semplice trucco: copia come bitmap 1x1 e ottieni il colore: http://aerilys.fr/blog/?p = 1341 – radley

7

Questa classe scorre su una bitmap e restituisce il colore più dominante. Sentiti libero di ripulire il codice dove necessario.

public class ImageColour { 

String colour; 


public ImageColour(Bitmap image) throws Exception { 

    int height = image.getHeight(); 
    int width = image.getWidth(); 

    Map m = new HashMap(); 

     for(int i=0; i < width ; i++){ 

      for(int j=0; j < height ; j++){ 

       int rgb = image.getPixel(i, j); 
       int[] rgbArr = getRGBArr(rgb);     

       if (!isGray(rgbArr)) { 

         Integer counter = (Integer) m.get(rgb); 
         if (counter == null) 
          counter = 0; 
         counter++;         
         m.put(rgb, counter);  

       }     
      } 
     }   

     String colourHex = getMostCommonColour(m); 
    } 



    public static String getMostCommonColour(Map map) { 

     List list = new LinkedList(map.entrySet()); 
     Collections.sort(list, new Comparator() { 
       public int compare(Object o1, Object o2) { 

       return ((Comparable) ((Map.Entry) (o1)).getValue()) 
        .compareTo(((Map.Entry) (o2)).getValue()); 

       } 

     });  

     Map.Entry me = (Map.Entry)list.get(list.size()-1); 
     int[] rgb= getRGBArr((Integer)me.getKey()); 

     return Integer.toHexString(rgb[0])+" "+Integer.toHexString(rgb[1])+" "+Integer.toHexString(rgb[2]);   
    }  


    public static int[] getRGBArr(int pixel) { 

     int red = (pixel >> 16) & 0xff; 
     int green = (pixel >> 8) & 0xff; 
     int blue = (pixel) & 0xff; 

     return new int[]{red,green,blue}; 

    } 

    public static boolean isGray(int[] rgbArr) { 

     int rgDiff = rgbArr[0] - rgbArr[1]; 
     int rbDiff = rgbArr[0] - rgbArr[2]; 

     int tolerance = 10; 

     if (rgDiff > tolerance || rgDiff < -tolerance) 
      if (rbDiff > tolerance || rbDiff < -tolerance) { 

       return false; 

      }     

     return true; 
    } 


public String returnColour() { 

    if (colour.length() == 6) { 
     return colour.replaceAll("\\s", ""); 
    } else { 
     return "ffffff"; 
    } 
} 

per ottenere l'esagono sufficiente chiamare returnColour();

+0

Suggerisco a chiunque usi questo approccio di giocare con la variabile di tolleranza. A seconda del valore impostato, l'algoritmo viene eseguito più velocemente o più lentamente. –

3

ho scritto i miei metodi per ottenere il colore dominante:

Metodo 1 (La mia tecnica)

  1. ridurre al ARGB_4444 spazio colore
  2. Comp ute il verificarsi massima dei singoli elementi RGB e ottenendo 3 valori massimi distintivi
  3. Combinando valori massimi di colore RGB dominante

    public int getDominantColor1(Bitmap bitmap) { 
    
    if (bitmap == null) 
        throw new NullPointerException(); 
    
    int width = bitmap.getWidth(); 
    int height = bitmap.getHeight(); 
    int size = width * height; 
    int pixels[] = new int[size]; 
    
    Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false); 
    
    bitmap2.getPixels(pixels, 0, width, 0, 0, width, height); 
    
    final List<HashMap<Integer, Integer>> colorMap = new ArrayList<HashMap<Integer, Integer>>(); 
    colorMap.add(new HashMap<Integer, Integer>()); 
    colorMap.add(new HashMap<Integer, Integer>()); 
    colorMap.add(new HashMap<Integer, Integer>()); 
    
    int color = 0; 
    int r = 0; 
    int g = 0; 
    int b = 0; 
    Integer rC, gC, bC; 
    for (int i = 0; i < pixels.length; i++) { 
        color = pixels[i]; 
    
        r = Color.red(color); 
        g = Color.green(color); 
        b = Color.blue(color); 
    
        rC = colorMap.get(0).get(r); 
        if (rC == null) 
         rC = 0; 
        colorMap.get(0).put(r, ++rC); 
    
        gC = colorMap.get(1).get(g); 
        if (gC == null) 
         gC = 0; 
        colorMap.get(1).put(g, ++gC); 
    
        bC = colorMap.get(2).get(b); 
        if (bC == null) 
         bC = 0; 
        colorMap.get(2).put(b, ++bC); 
    } 
    
    int[] rgb = new int[3]; 
    for (int i = 0; i < 3; i++) { 
        int max = 0; 
        int val = 0; 
        for (Map.Entry<Integer, Integer> entry : colorMap.get(i).entrySet()) { 
         if (entry.getValue() > max) { 
          max = entry.getValue(); 
          val = entry.getKey(); 
         } 
        } 
        rgb[i] = val; 
    } 
    
    int dominantColor = Color.rgb(rgb[0], rgb[1], rgb[2]); 
    
    return dominantColor; 
    } 
    

Metodo 2 (Old tecnica)

  1. Ridurre a ARGB_4444 spazio colore
  2. Calcolo il verificarsi di ogni colore e di trovare il massimo come Colore dominante

    public int getDominantColor2(Bitmap bitmap) { 
    if (bitmap == null) 
        throw new NullPointerException(); 
    
    int width = bitmap.getWidth(); 
    int height = bitmap.getHeight(); 
    int size = width * height; 
    int pixels[] = new int[size]; 
    
    Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false); 
    
    bitmap2.getPixels(pixels, 0, width, 0, 0, width, height); 
    
    HashMap<Integer, Integer> colorMap = new HashMap<Integer, Integer>(); 
    
    int color = 0; 
    Integer count = 0; 
    for (int i = 0; i < pixels.length; i++) { 
        color = pixels[i]; 
        count = colorMap.get(color); 
        if (count == null) 
         count = 0; 
        colorMap.put(color, ++count); 
    } 
    
    int dominantColor = 0; 
    int max = 0; 
    for (Map.Entry<Integer, Integer> entry : colorMap.entrySet()) { 
        if (entry.getValue() > max) { 
         max = entry.getValue(); 
         dominantColor = entry.getKey(); 
        } 
    } 
    return dominantColor; 
    } 
    
+0

domanda: A cosa serve Bitmap2? sembra che non lo si usi dopo aver copiato dalla bitmap originale. –

20

C'è anche un un'altra soluzione, è più approssimativa, ma se non si vuole avere lungo ritardo per la ricerca del colore, si può fare il lavoro.

public static int getDominantColor(Bitmap bitmap) { 
    Bitmap newBitmap = Bitmap.createScaledBitmap(bitmap, 1, 1, true); 
    final int color = newBitmap.getPixel(0, 0); 
    newBitmap.recycle(); 
    return color; 
} 
+0

Questa è una risposta molto utile. Stavo usando il metodo loop, ma quello stava rendendo l'interfaccia utente a scatti. Ora è molto liscio. –

+0

C'è comunque un errore di sintassi nel codice. –

+0

Come supporto: palette-v7: 25.0.0, questo non ha più bisogno di un metodo personalizzato - basta usare palette.getDominantSwatch(). –

0

Nessuna delle altre risposte ha fatto il lavoro per me, e non mi ha escluso la causa del problema.

Questo è quello che ho finito per usare:

public static int getDominantColor(Bitmap bitmap) { 
    if (bitmap == null) { 
     return Color.TRANSPARENT; 
    } 
    int width = bitmap.getWidth(); 
    int height = bitmap.getHeight(); 
    int size = width * height; 
    int pixels[] = new int[size]; 
    //Bitmap bitmap2 = bitmap.copy(Bitmap.Config.ARGB_4444, false); 
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height); 
    int color; 
    int r = 0; 
    int g = 0; 
    int b = 0; 
    int a; 
    int count = 0; 
    for (int i = 0; i < pixels.length; i++) { 
     color = pixels[i]; 
     a = Color.alpha(color); 
     if (a > 0) { 
      r += Color.red(color); 
      g += Color.green(color); 
      b += Color.blue(color); 
      count++; 
     } 
    } 
    r /= count; 
    g /= count; 
    b /= count; 
    r = (r << 16) & 0x00FF0000; 
    g = (g << 8) & 0x0000FF00; 
    b = b & 0x000000FF; 
    color = 0xFF000000 | r | g | b; 
    return color; 
} 
Problemi correlati