web-dev-qa-db-fra.com

Trouver la couleur dominante d'une image dans un Android @ Drawable

Vous pouvez comprendre pourquoi j'essaie de trouver la couleur dominante dans une image si vous utilisez Windows 7. Lorsque vous passez la souris sur un programme dans la barre des tâches, l'arrière-plan de ce programme change en fonction de la couleur la plus dominante de l'icône. J'ai aussi remarqué cette technique utilisée dans d'autres programmes, mais je ne m'en souviens pas par cœur.

Je peux voir que cela est utile dans un certain nombre de techniques d'interface utilisateur que j'utilise pour développer une application, et je me demandais comment la recherche de la couleur la plus courante serait réalisée à partir d'une ressource pouvant être dessinée sur Android.

36
styler1972

Dans Android 5.0 Lollipop, une classe a été ajoutée pour permettre d'extraire les couleurs utiles d'un bitmap. La classe Palette , située dans Android.support.v7.graphics, peut extraire les couleurs suivantes:

  • Vibrant
  • Sombre vibrant
  • Lumière vibrante
  • En sourdine
  • Sombre en sourdine
  • Lumière en sourdine

Cette page de formation sur Android fournit tous les détails nécessaires à l’utilisation de la classe (j’ai essayé moi-même sous Android Studio et c’était très simple): http://developer.Android.com/training/material/drawables.html#ColorExtract

Citer:

La bibliothèque de support Android r21 et supérieure comprend la Palette classe, qui vous permet d’extraire les couleurs saillantes d’une image. À extraire ces couleurs, passez un objet Bitmap à Palette.generate () méthode statique dans le fil d’arrière-plan où vous chargez vos images. Si vous ne pouvez pas utiliser ce fil, appelez la méthode Palette.generateAsync () et fournir un auditeur à la place. *

Vous pouvez récupérer les couleurs saillantes de l'image à l'aide du getter méthodes de la classe Palette, telles que Palette.getVibrantColor.

Pour utiliser la classe Palette dans votre projet, ajoutez le Gradle suivant dépendance au module de votre application:

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

* Si vous devez utiliser generateAsync (), voici comment:

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

EDIT: Puisque la question demande comment extraire les couleurs d’une ressource dessinable, vous devez d’abord convertir le dessinable en un bitmap pour utiliser la technique que j’ai décrite. Heureusement, c'est assez simple avec BitmapFactory:

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                       R.drawable.icon_resource);`
60
Tony Wickham

Il existe également une autre solution, plus approximative, mais si vous ne souhaitez pas attendre longtemps avant de rechercher une couleur, le travail est fait.

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;
}
25
Pdroid

J'ai écrit mes propres méthodes pour obtenir la couleur dominante:

Méthode 1 (Ma technique)

  1. Réduire à ARGB_4444 espace de couleur
  2. Calculer l'occurrence maximale d'éléments RGB individuels et obtenir 3 valeurs maximales distinctes
  3. Combinaison des valeurs maximales et de la couleur RVB 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;
     }
    

Méthode 2 (ancienne technique)

  1. Réduire à ARGB_4444 espace de couleur
  2. Calculer l'occurrence de chaque couleur et trouver le maximum en tant que couleur 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;
    }
    
4
Mohsen Afshin

Parcourez toutes les données de couleur du pixel et faites la moyenne des valeurs de couleur, ignorez tout ce qui est gris ou transparent. Je pense que c'est ce que Microsoft fait dans Windows 7 à partir d'un article de blog récent.

modifier
Le message de blog: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx

Ce lien indiquant comment Chrome sélectionne la couleur dominante peut également être utile. http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the-color-for-the-stripes-on-the-Most-visited-page-thumbnails

2
Bradley Uffner

Aucune des autres réponses n'a fait le travail pour moi, et je n'ai pas exclu la cause du problème.

C'est ce que j'ai fini par utiliser:

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;
}
0
rraallvv