在Android @drawab中查找图像的主色

您可以理解为什么使用Windows 7时为什么要尝试在图像中找到主要颜色。将鼠标悬停在任务栏中的某个程序上时,该特定程序的背景会根据图标中最主要的颜色而变化。 我也注意到其他程序中也使用了这种技术,但是我想不起来了。

我可以看到这对我用于开发应用程序的多种UI技术很有帮助,我想知道如何从Android可绘制资源中找到最常见的颜色。

styler1972 asked 2020-06-30T01:26:21Z
8个解决方案
71 votes

在Android 5.0 Lollipop中,添加了一个类,以帮助从位图中提取有用的颜色。 在android.support.v7.graphics中找到的Palette类可以提取以下颜色:

  • 充满活力
  • 充满活力的黑暗
  • 充满活力的光
  • 静音
  • 暗哑
  • 静音灯

这个Android培训页面提供了使用该类所需的所有详细信息(我自己在Android Studio中尝试了它,这非常简单):[http://developer.android.com/training/material/drawables.html#ColorExtract]

报价:

Android支持库r21及更高版本包含选板 类,使您可以从图像中提取突出的颜色。 至 提取这些颜色,然后将Bitmap对象传递给Palette.generate() 加载图像的后台线程中的静态方法。 如果 您不能使用该线程,请调用Palette.generateAsync()方法,然后 而是提供一个监听器。*

您可以使用吸气剂从图像中检索突出的颜色 Palette类中的方法,例如Palette.getVibrantColor。

要在项目中使用Palette类,请添加以下Gradle 对应用程序模块的依赖关系:

implementation 'androidx.palette:palette:1.0.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...
    }
});

编辑:由于该问题询问如何从可绘制资源中提取颜色,因此您必须首先将可绘制对象转换为位图,才能使用我已经描述的技术。 幸运的是,使用BitmapFactory非常简单:

Bitmap icon = BitmapFactory.decodeResource(context.getResources(),
                                       R.drawable.icon_resource);`
Tony Wickham answered 2020-06-30T01:27:32Z
30 votes

还有另一种解决方案,它更近似,但是如果您不想长时间延迟搜索颜色,则可以完成此工作。

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;
}
Pdroid answered 2020-06-30T01:27:52Z
7 votes

此类通过位图进行迭代,并返回最主要的颜色。请在必要时随意清理代码。

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();

Reid L Skipworth answered 2020-06-30T01:28:16Z
4 votes

我编写了自己的方法来获得主导色:

方法1(我的技术)

  1. 减少到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. 计算单个RGB元素的最大出现次数,并获得3个不同的最大值
  3. 将最大值与主要RGB颜色组合

    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(旧技术)

  1. 减少到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. 计算每种颜色的出现并找到最大的一种作为主色

    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;
    }
    
Mohsen Afshin answered 2020-06-30T01:29:07Z
3 votes

要从图像中找到主要/鲜艳/柔和的颜色,请使用调色板:

进口:

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

    } }
Francis answered 2020-06-30T01:29:35Z
2 votes

遍历所有像素的颜色数据并取平均颜色值,而忽略任何呈灰色或透明阴影的内容。 我相信这是Microsoft根据最近的博客文章在Windows 7中所做的事情。

编辑
博客文章:[http://blogs.msdn.com/b/oldnewthing/archive/2011/12/06/10244432.aspx]

该链接显示了Chrome如何选择主要颜色,这可能也会有所帮助。 [http://www.quora.com/Google-Chrome/How-does-Chrome-pick-the-color-for-the-stripes-on-the-Most-visited-page-thumbnails]

Bradley Uffner answered 2020-06-30T01:30:09Z
1 votes

添加到依赖项

implementation 'androidx.palette:palette:1.0.0'

和..

 AppCompatImageView imageView = findViewById(R.id.image_view);

 Bitmap bitmap = ((BitmapDrawable) imageView.getDrawable()).getBitmap();
 Palette.from(bitmap).generate(palette -> {
      int vibrant = palette.getVibrantColor(0x000000); // <=== color you want
      int vibrantLight = palette.getLightVibrantColor(0x000000);
      int vibrantDark = palette.getDarkVibrantColor(0x000000);
      int muted = palette.getMutedColor(0x000000);
      int mutedLight = palette.getLightMutedColor(0x000000);
      int mutedDark = palette.getDarkMutedColor(0x000000);
 });
Williaan Lopes answered 2020-06-30T01:30:33Z
0 votes

没有其他答案对我有帮助,我也不排除问题的原因。

我最终使用的是:

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;
}
rraallvv answered 2020-06-30T01:30:57Z
translate from https://stackoverflow.com:/questions/8471236/finding-the-dominant-color-of-an-image-in-an-android-drawable