How can I get the average colour of an image

Building off Dan O's solution, here's a method that automatically takes into account the alpha channel and makes the optimization/ tradeoff of getPixels vs getPixel.

The cost is memory but the benefit is performance, invocation of a virtual method in a loop that could possibly be run several million times [i.e. an 8MP image has 3,456x2,304 = 7,962,624 pixels]). I've even taken things one step further by removing the looped android.graphics.Color method calls.

public static int getDominantColor(Bitmap bitmap) {
   if (null == bitmap) return Color.TRANSPARENT;

   int redBucket = 0;
   int greenBucket = 0;
   int blueBucket = 0;
   int alphaBucket = 0;

   boolean hasAlpha = bitmap.hasAlpha();
   int pixelCount = bitmap.getWidth() * bitmap.getHeight();
   int[] pixels = new int[pixelCount];
   bitmap.getPixels(pixels, 0, bitmap.getWidth(), 0, 0, bitmap.getWidth(), bitmap.getHeight());

   for (int y = 0, h = bitmap.getHeight(); y < h; y++)
   {
       for (int x = 0, w = bitmap.getWidth(); x < w; x++)
       {
           int color = pixels[x + y * w]; // x + y * width
           redBucket += (color >> 16) & 0xFF; // Color.red
           greenBucket += (color >> 8) & 0xFF; // Color.greed
           blueBucket += (color & 0xFF); // Color.blue
           if (hasAlpha) alphaBucket += (color >>> 24); // Color.alpha
       }
   }

   return Color.argb(
           (hasAlpha) ? (alphaBucket / pixelCount) : 255,
           redBucket / pixelCount,
           greenBucket / pixelCount,
           blueBucket / pixelCount);
}

Bitmap bitmap = someFunctionReturningABitmap();
long redBucket = 0;
long greenBucket = 0;
long blueBucket = 0;
long pixelCount = 0;

for (int y = 0; y < bitmap.getHeight(); y++)
{
    for (int x = 0; x < bitmap.getWidth(); x++)
    {
        Color c = bitmap.getPixel(x, y);

        pixelCount++;
        redBucket += Color.red(c);
        greenBucket += Color.green(c);
        blueBucket += Color.blue(c);
        // does alpha matter?
    }
}

Color averageColor = Color.rgb(redBucket / pixelCount,
                                greenBucket / pixelCount,
                                blueBucket / pixelCount);

You can use Palete class from AndroidX, or from the the v7-support library.

It provides additional methods to extract colours from a Bitmap, such as getting:

  • Most Dominant color
  • Vibrant colors
  • Muted color
  • much more

I think you will have to do that yourself.

Just create an int array with all the colors:

Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.icon);  
bmp = bmp.copy(Bitmap.Config.ARGB_8888, true);    
int intArray[] = new int[bmp.getWidth()*bmp.getHeight()];  
bmp.getPixels(intArray, 0, bmp.getWidth(), 0, 0, bmp.getWidth(), bmp.getHeight());

Then you can get the color with intArray[0], the value could be 0xFFFF0000 for red (last 6 numbers are the RGB color value).

Here is another easy solution:

  • Get you full-size image in a bitmap.

  • Create a scaled bitmap of 1*1px.

  • Get this bitmap color.

Tags:

Java

Android