Нахождение доминирующего цвета изображения в Android @drawable - PullRequest
43 голосов
/ 12 декабря 2011

Вы можете понять, почему я пытаюсь найти доминирующий цвет на изображении, если вы используете Windows 7. Когда вы наводите курсор мыши на программу на панели задач, фон этой конкретной программы изменяется в зависимости от самого доминирующего цвета взначок.Я заметил, что эта техника используется и в других программах, но я не могу вспомнить их из головы.

Я вижу, что это полезно в ряде техник пользовательского интерфейса, которые я использую для разработкиприложение, и мне было интересно, как найти наиболее распространенный цвет на ресурсе для рисования на Android.

Ответы [ 7 ]

66 голосов
/ 26 января 2015

В Android 5.0 Lollipop был добавлен класс для извлечения полезных цветов из растрового изображения. Класс Палитра , найденный в android.support.v7.graphics, может извлекать следующие цвета:

  • Яркий
  • Яркий Темный
  • Яркий свет
  • приглушенный
  • Приглушенный темнота
  • Приглушенный свет

Эта обучающая страница Android содержит все детали, необходимые для использования класса (я сам попробовал это сделать в Android Studio, и это было очень просто): http://developer.android.com/training/material/drawables.html#ColorExtract

Цитировать:

Библиотека поддержки Android r21 и выше включает в себя Палитра класс, который позволяет вам извлечь выдающиеся цвета из изображения. к распакуйте эти цвета, передайте объект Bitmap в Palette.generate () статический метод в фоновом потоке, куда вы загружаете ваши изображения. Если Вы не можете использовать этот поток, вызовите метод Palette.generateAsync () и вместо этого предоставьте слушателя. *

Вы можете получить заметные цвета из изображения, используя геттер методы в классе Palette, такие как Palette.getVibrantColor.

Чтобы использовать класс Palette в вашем проекте, добавьте следующий Gradle зависимость от модуля вашего приложения:

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

Или, если вы используете androidx:

implementation 'androidx.palette:palette:1.0.0'

Если вам нужно использовать generateAsync (), вот как:

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

EDIT: Поскольку вопрос состоит в том, как извлечь цвета из прорисовываемого ресурса, вам сначала нужно преобразовать прорисовку в растровое изображение, чтобы использовать описанную мной технику. К счастью, это довольно просто, используя BitmapFactory:

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                       R.drawable.icon_resource);`
28 голосов
/ 21 марта 2015

Есть и другое решение, оно более приблизительное, но если вы не хотите иметь длительную задержку для поиска цвета, оно может выполнить эту работу.

7 голосов
/ 18 июля 2013

Этот класс выполняет итерацию по растровому изображению и возвращает наиболее доминирующий цвет. Не стесняйтесь очищать код при необходимости.

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

чтобы получить гекс просто позвоните returnColour();

4 голосов
/ 13 августа 2013

Я написал свои собственные методы, чтобы получить доминирующий цвет:

Метод 1 (Моя техника)

  1. Уменьшить до ARGB_4444 цветовое пространство
  2. Вычислить максимальное вхождение отдельных элементов RGB и получить 3 отличительных максимальных значения
  3. Объединение максимальных значений с доминирующим цветом RGB

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

Метод 2 (Старая техника)

  1. Уменьшить до ARGB_4444 цветового пространства
  2. Рассчитать вхождение каждого цвета и найти максимальный в качестве доминирующего цвета

    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;
    }
    
2 голосов
/ 12 декабря 2011

Переберите все данные о цвете пикселя и усредните значения цвета, игнорируйте все, что имеет серый или прозрачный оттенок.Я полагаю, что именно это делает Microsoft в Windows 7 на основе недавнего сообщения в блоге.

edit
Сообщение в блоге: http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx

Эта ссылка показывает, какХром выбирает доминирующий цвет, также может быть полезным.http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the-color-for-the-stripes-on-the-Most-visited-page-thumbnails

0 голосов
/ 14 июня 2019

Чтобы найти цвет Доминант / Яркий / Приглушенный на изображении, используйте Палитра :

Импорт:

implementation 'androidx.palette:palette:1.0.0'

использование:

    val bitmap = BitmapFactory.decodeResource(resources, R.drawable.image)

    Palette.Builder(bitmap).generate { it?.let {  palette ->
        val dominantColor = palette.getDominantColor(ContextCompat.getColor(context!!, R.color.defaultColor))

        // TODO: use dominant color

    } }
0 голосов
/ 31 марта 2017

Ни один из других ответов не помог мне, и я не исключил причину проблемы.

Вот что я в итоге использовал:

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