简体   繁体   中英

Modification of Back Ground color(theme) According to an image

I am trying to find the color that most suits a loaded image and apply it in the background. To adapt to the image and make the UI feel more natural. i have so far found 2 schemes :

1> averaging the pixels(Code Below) :

final Color acclimatizeAverage(BufferedImage img) {
        long avgr = 0, avgb = 0, avgg = 0;
        for (int i = 0; i < img.getWidth(); i++) {
            for (int j = 0; j < img.getHeight(); j++) {
               Color c = new Color(img.getRGB(i, j));
               avgr += c.getRed(); avgb += c.getBlue(); avgg += c.getGreen();
            }
        }
        avgr = (avgr/(img.getHeight()*img.getWidth()));
        avgg = (avgg/(img.getHeight()*img.getWidth()));
        avgb = (avgb/(img.getHeight()*img.getWidth()));
        Color c = new Color((int)avgr, (int)avgg, (int)avgb);
        return c;
    }

2> Grouping the pixels into fixed bins of Colors(Code Below) :

 Map<Color, Integer> createBins() {
        Map<Color, Integer> bins = new HashMap<>();
        bins.put(Color.red, 0);
        bins.put(Color.magenta, 0);
        bins.put(Color.orange, 0);
        bins.put(Color.PINK, 0);
        bins.put(Color.yellow, 0);
        bins.put(Color.LIGHT_GRAY, 0);
        bins.put(Color.GREEN, 0);
        bins.put(Color.GRAY, 0);
        bins.put(Color.DARK_GRAY, 0);
        bins.put(Color.CYAN, 0);
        bins.put(Color.BLUE, 0);
        bins.put(Color.BLACK, 0);
        return bins;
    }

    int compare(Color a, Color b) {
        return (int)Math.sqrt((a.getRed() - b.getRed())*(a.getRed() - b.getRed()) 
                + (a.getBlue() - b.getBlue())*(a.getBlue() - b.getBlue()) 
                + (a.getGreen()- b.getGreen())*(a.getGreen()- b.getGreen()));
    }

    BufferedImage acclimatizeGrouping(BufferedImage img) {
        Map<Color, Integer> bins = createBins();
        for (int i = 0; i < img.getWidth(); i++) {
            int min = Integer.MAX_VALUE; Color minC = null;
            for (int j = 0; j < img.getHeight(); j++) {
               Color c = new Color(img.getRGB(i, j));
                for (Map.Entry<Color, Integer> entry : bins.entrySet()) {
                    Integer integer = compare(entry.getKey(), c);
                    if(integer < min) {
                        min = integer;
                        minC = entry.getKey();
                    }
                }
                bins.put(minC, bins.get(minC)+1);
            }
        }
        int max = -1, n = 1; Color c = null;
        for (Map.Entry<Color, Integer> entry : bins.entrySet()) {
            Integer integer = entry.getValue();
            if(integer > max) {
                max = integer;
                c = entry.getKey();
            }
        }
        return c;
    }

But the grouping is producing weird results....
left side is the Color produced as a result of grouping and right side is image
Why is it producing such results ??? 左侧是分组产生的颜色,右侧是图像

averaing is producing more correct results : 在此处输入图片说明

I think the problem is that RGB is not human euclidean space. You use euclidean distance to compare colors, but it is not good for human color sense. See this link for more information.

EDIT: More precise, you should use this algorithm:

typedef struct {
   unsigned char r, g, b;
} RGB;

double ColourDistance(RGB e1, RGB e2)
{
  long rmean = ( (long)e1.r + (long)e2.r ) / 2;
  long r = (long)e1.r - (long)e2.r;
  long g = (long)e1.g - (long)e2.g;
  long b = (long)e1.b - (long)e2.b;
  return sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}

This issue is, your compare(Color a, Color b) method is not implemented correctly and can use some basic refactoring using the Math.pow() method.

The basic formula to find similar colors programatically is

((r2 - r1) 2 + (g2 - g1) 2 + (b2 - b1) 2 ) 1/2

Applied to Java, that results in the modified compare(Color a, Color b)

int compare(Color a, Color b){
  return Math.sqrt(( Math.pow( b.getRed() - a.getRed() ) 
                   + ( Math.pow( b.getGreen() - a.getGreen() )
                   + ( Math.pow( b.getBlue() - a.getBlue() ));
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM