Android Palette not chosing predominant colors

758 views Asked by At

I have the following images :

enter image description here enter image description here enter image description here

And I have the following method that returns me the Palette color from the bitmap of this images :

 public static int getPredominantColorFromPokemon(String pokemonId, Context context) {
    int pokemonImage = PokemonUtils.getPokemonSugimoriImageById(pokemonId, context);
    if (pokemonImage == 0) {
        return Color.WHITE;
    }
    Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), pokemonImage);
    Palette palette = Palette.from(bitmap).generate();
    int colorPalette1 = palette.getLightVibrantColor(Color.WHITE);
    int colorPalette2 = colorPalette1 == -1 ? palette.getVibrantColor(Color.WHITE) : colorPalette1;//Fallback
    int colorPalette3 = colorPalette2 == -1 ? palette.getLightMutedColor(Color.WHITE) : colorPalette2; //Fallback
    int colorPalette4 = colorPalette3 == -1 ? palette.getDominantColor(Color.WHITE) : colorPalette3;//Fallback
    return colorPalette4;
}

The result colors of this 3 images is the following :

However , this isn't what im looking for , my desired output would be this :

enter image description here

The first and second image results are OK , the background is a kind of green because the predominant color is green but in the case of the third image (Venusaur) is not because the result is a kind of pink/purple color and I want the Palette to detect green instead . How can I modify my method in order to detect the PREDOMINANT colors ?

1

There are 1 answers

2
muetzenflo On BEST ANSWER

Colors are very subjective and it is not always a clear decision which color is the dominant one. Keyfactors are lumincane, and the historgram. Obviously the implementation of google thinks that the pink color is more important than the blue. This is even understandable since red/orange/yellow are signal colors that are perceived more important by the human eye (unrelated to the amount of them within the image).

Imagine a big grey rectangle with a neon-pink small circle in it. You will likely perceive the neon-pink as the dominant color instead of the grey. Even so the amount of grey is larger.

So in short: If you want to use the Palette API, you have to deal with the result it gives you.

But since the Palette API offers several extracted colors, you could compare their Hue with the Historgram of the image and chose your favorite palette color accordingly.

Here is an example on how to convert a color from RGB to HSV and back.

  • H = Hue = The basic type of color you are dealing with (red, green, orange, etc.)
  • S = Saturation (How intense is the hue. heavy red or a light red)
  • V = Value (How bright is the hue. From completely dark to completely bright)
int color = Color.rgb(206, 43, 55);

int red = Color.red(color);
int green = Color.green(color);
int blue = Color.blue(color);
System.out.println(red + ", " + green + ", " + blue);
//prints: 206, 43, 55 (as expected)

float[] hsv = new float[3];
Color.RGBToHSV(red, green, blue, hsv);

float hue = hsv[0];
float sat = hsv[1];
float val = hsv[2];

int outputColor = Color.HSVToColor(hsv);
red = Color.red(outputColor);
green = Color.green(outputColor);
blue = Color.blue(outputColor);
System.out.println(red + ", " + green + ", " + blue);

I would try to use just HSV for starters, because for creating a histogram is very slow since you basically have to iterate over every pixel of the image and cumulate its color to a list. 3 times. For red, green and blue.

This is something where you will not find "the 1 perfect solution". Instead you might have to figure out the trade-off between maintainable code, speed and app requirements.

Good luck!