Join FlipAndroid.COM Telegram Group: https://t.me/joinchat/F_aqThGkhwcLzmI49vKAiw


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.

  • Cómo obtener cuando un ImageView está completamente cargado en Android
  • ¿Por qué dibujar bitmaps es muy lento en algunos teléfonos Android 2.2?
  • Guardar mapa de bits Android sin área transparente
  • Android fuera de la prevención de la memoria
  • Generar mapa de bits de HTML en Android
  • Android, ayuda a girar la imagen en el tacto
  • API básica de Android v2 MapActivity outOfMemory con 10 marcadores
  • Fuga de memoria de Android: InputMethodManager, mapa de bits
  • 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; } 
    FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.