Bug 867249 - Improve getDominantColor algorithm to return more accurate colors. r=bnicholson

This commit is contained in:
Margaret Leibovic 2013-05-02 11:53:13 -07:00
parent 95caf21d3c
commit 09c40b46be

View File

@ -55,48 +55,63 @@ public final class BitmapUtils {
}
public static int getDominantColor(Bitmap source, boolean applyThreshold) {
int[] colors = new int[37];
int[] sat = new int[11];
int[] val = new int[11];
int maxH = 0;
int maxS = 0;
int maxV = 0;
if (source == null)
return Color.argb(255,255,255,255);
// Keep track of how many times a hue in a given bin appears in the image.
// Hue values range [0 .. 360), so dividing by 10, we get 36 bins.
int[] colorBins = new int[36];
// The bin with the most colors. Initialize to -1 to prevent accidentally
// thinking the first bin holds the dominant color.
int maxBin = -1;
// Keep track of sum hue/saturation/value per hue bin, which we'll use to
// compute an average to for the dominant color.
float[] sumHue = new float[36];
float[] sumSat = new float[36];
float[] sumVal = new float[36];
for (int row = 0; row < source.getHeight(); row++) {
for (int col = 0; col < source.getWidth(); col++) {
int c = source.getPixel(col, row);
// Ignore pixels with a certain transparency.
if (Color.alpha(c) < 128)
continue;
float[] hsv = new float[3];
Color.colorToHSV(c, hsv);
// arbitrarily chosen values for "white" and "black"
if (applyThreshold && hsv[1] <= 0.35f && hsv[2] <= 0.35f)
// If a threshold is applied, ignore arbitrarily chosen values for "white" and "black".
if (applyThreshold && (hsv[1] <= 0.35f || hsv[2] <= 0.35f))
continue;
int h = Math.round(hsv[0] / 10.0f);
int s = Math.round(hsv[1] * 10.0f);
int v = Math.round(hsv[2] * 10.0f);
colors[h]++;
sat[s]++;
val[v]++;
// We compute the dominant color by putting colors in bins based on their hue.
int bin = (int) Math.floor(hsv[0] / 10.0f);
// we only care about the most unique non white or black hue - if threshold is applied
// we also store its saturation and value params to match the color better
if (colors[h] > colors[maxH]) {
maxH = h;
maxS = s;
maxV = v;
}
// Update the sum hue/saturation/value for this bin.
sumHue[bin] = sumHue[bin] + hsv[0];
sumSat[bin] = sumSat[bin] + hsv[1];
sumVal[bin] = sumVal[bin] + hsv[2];
// Increment the number of colors in this bin.
colorBins[bin]++;
// Keep track of the bin that holds the most colors.
if (maxBin < 0 || colorBins[bin] > colorBins[maxBin])
maxBin = bin;
}
}
// maxBin may never get updated if the image holds only transparent and/or black/white pixels.
if (maxBin < 0)
return Color.argb(255,255,255,255);
// Return a color with the average hue/saturation/value of the bin with the most colors.
float[] hsv = new float[3];
hsv[0] = maxH*10.0f;
hsv[1] = (float)maxS/10.0f;
hsv[2] = (float)maxV/10.0f;
hsv[0] = sumHue[maxBin]/colorBins[maxBin];
hsv[1] = sumSat[maxBin]/colorBins[maxBin];
hsv[2] = sumVal[maxBin]/colorBins[maxBin];
return Color.HSVToColor(hsv);
}