Encontrar el color dominante de una imagen en un @drawable de Android

Puedes entender por qué estoy tratando de encontrar el color dominante en una imagen si usas Windows 7. Cuando el ratón sobre un programa en la barra de tareas, el fondo de ese programa en particular cambia basado en el color más dominante en el icono. He notado esta técnica usada en otros programas también, pero no puedo recordarlos de la tapa de mi cabeza.

Puedo ver esto ser útil en una serie de técnicas de interfaz de usuario que estoy usando para desarrollar una aplicación, y me preguntaba cómo encontrar el color más común se lograría de un recurso de Android drawable.

7 Solutions collect form web for “Encontrar el color dominante de una imagen en un @drawable de Android”

En Android 5.0 Lollipop, se agregó una clase para ayudar a extraer colores útiles de un mapa de bits. La clase Palette , que se encuentra en android.support.v7.graphics, puede extraer los siguientes colores:

  • Vibrante
  • Vibrante oscuro
  • Luz vibrante
  • Apagado
  • Oscuro
  • Luz apagada

Esta página de formación de Android ofrece todos los detalles que necesitas para usar la clase (lo probé yo mismo en Android Studio y fue muy sencillo): http://developer.android.com/training/material/drawables.html#ColorExtract

Citar:

La Biblioteca de soporte de Android r21 y superior incluye la clase Paleta , que le permite extraer colores prominentes de una imagen. Para extraer estos colores, pase un objeto Bitmap al método estático Palette.generate () en el subproceso de fondo donde cargue sus imágenes. Si no puede utilizar ese hilo, llame al método Palette.generateAsync () y proporcione un oyente en su lugar. *

Puede recuperar los colores prominentes de la imagen utilizando los métodos getter de la clase Palette, como Palette.getVibrantColor.

Para utilizar la clase Palette en su proyecto, añada la siguiente dependencia de Gradle al módulo de su aplicación:

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

* Si necesitas usar generateAsync (), veremos cómo:

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

EDIT: Desde la pregunta se pregunta cómo extraer los colores de un recurso de dibujo, primero tendría que convertir el dibujable a un mapa de bits para utilizar la técnica que he descrito. Por suerte, eso es bastante simple con BitmapFactory:

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

También hay una otra solución, es más aproximativo, pero si no desea tener mucho tiempo para buscar el color, puede hacer el trabajo.

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

Esta clase itera a través de un mapa de bits y devuelve el color más dominante. Siéntase libre de limpiar el código cuando sea necesario.

 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"; } } 

Para obtener el hexágono simplemente llame a returnColour();

Escribí mis propios métodos para obtener el color dominante:

Método 1 (Mi técnica)

  1. Reducir a ARGB_4444 espacio de color
  2. Calcular la máxima aparición de elementos RGB individuales y obtener 3 valores máximos distintivos
  3. Combinación de valores máximos con el color 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; } 

Método 2 (Técnica anterior)

  1. Reducir a ARGB_4444 espacio de color
  2. Calcular la ocurrencia de cada color y encontrar el máximo como color 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; } 

Bucle a través de todos los datos de color del píxel y el promedio de los valores de color, ignorar todo lo que es un tono de gris o transparente. Creo que eso es lo que hace Microsoft en Windows 7 basado en una publicación reciente.

editar
La entrada del blog: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx

Este enlace que muestra cómo Chrome selecciona el color dominante también puede ser útil. http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the-color-for-the-stripes-on-the-Most-visited-page-thumbnails

He estado tratando de lograr algo similar. No fue capaz de encontrar cualquier API ready-made para Android sin embargo.

Al final escribí mi propia función para calcular el color promedio de un Drawable, basado en una pequeña muestra de píxeles. Esto ahorra tener que iterar a través de todos los píxeles de la imagen, lo que podría tomar mucho tiempo para las imágenes grandes. No es exactamente lo mismo que encontrar el color dominante , pero funcionó para mis propósitos (establecer el color de fondo para los iconos del lanzador)

La fuente completa está disponible en http://makingmoneywithandroid.com/forum/showthread.php?tid=433

Espero que esto puede ser de alguna ayuda para usted!

Nota: Este código hace uso de un BitmapDrawable, no sólo un Drawable regular. Consulte ¿Cómo convertir un dibujable en un mapa de bits? Para más información sobre esta distinción.

Ninguna de las otras respuestas hizo el trabajo para mí, y no descarté la causa del problema.

Esto es lo que terminé usando:

 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; } 
  • Fuga de memoria de Android: InputMethodManager, mapa de bits
  • Uso de Fresco de Facebook para cargar un mapa de bits
  • ¿Dónde desasignar correctamente el mapa de bits en Android View?
  • Android - Lienzo drawLine dentro de ImageView
  • Aplicación de una superposición (filtro de imagen) a un mapa de bits
  • Azulejo de un mapa de bits en SurfaceView Canvas
  • Android Bitmap.createScaledBitmap arroja java.lang.OutOfMemoryError sobre todo en Jelly Bean 4.1
  • Inclinar un mapa de bits sólo en la dirección vertical
  • Visualización de lienzo / mapa de bits al instante durante la depuración en eclipse
  • Cómo combinar el mapa de bits de superposición y la imagen capturada en android?
  • ImageView se estrelló la aplicación
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.