Weighted average of colors [solved]

I’m trying to make a gradient effect. I want to make a method that returns returns a color for a position on a gradient. So for example, if variable “x” can be anything from 0 to 9, if x was 0 I might want the method to return black. If x was 9, I might want it to return white, and if x was 2 I mighy want the function to return a dark gray. The colors don’t have to be white and black, but any two colors. (The method would return a “Color” from the Java Color class)

I tried to make a weighted average for each rgb value and put them back together, but it doesn’t work properly. The colors don’t mix properly

Color gradientColor(float x){
		int r = (int) (x*color1.getRed() + (length-x)*color2.getRed())/length;
		int g = (int) (x*color1.getGreen() + (length-x)*color2.getGreen())/length;
		int b = (int) (x*color1.getBlue() + (length-x)*color2.getBlue())/length;
		return new Color(r*0xffff+g*0xff+b);
	}

“length” is the length of the gradient, which was 9 in the above example, and color1 might be white and color2 might be black

Thanks

Hmm.


// x = 0: black, x = 1: white
int red = 255*x;
int green = 255*x;
int blue = 255*x;
return new Color( (red << 16) | (green << 8) | blue );

Right, but that only works for black and white. In my applet I’m using many more colors and need a general solution for them.

if you substitute

return new Color(r*0xffff+g*0xff+b)

for

return new Color( (r << 16) | (g << 8) | b )

What happens?

[EDIT]: I’m not sure I’m getting the question, lemme try and re-read :o


public Color getColor(float x, Color c1, Color c2) {
   float y = 1-x;
   int red = (x*c1.getRed() + y*c2.getRed());
   int grn = (x*c1.getGreen() + y*c2.getGreen());
   int blu = (x*c1.getBlue() + y*c2.getBlue());
   int col = (red << 16) | (grn << 8) | blu;
   return new Color(col);
}

More like this? Or do you want to adjust only brightness or something?

Oh… I put in “return new Color( (r << 16) | (g << 8) | b )” and it worked. Huh… I had only read about these bit-wise operators and never used them. I wonder why my implementation didn’t work… Oh well, probably just messed up the math. Anyway, it works now. Thanks!

With this code:

x*0xff

you multiply by 255.

Whereas with this code:

x<<8

you multiply by 256.

An int can hold 32 bits of data. 32 bits == 4 bytes. Which further equals 1 int (I.e, an int is made up of 4 bytes).

A pixel/color is a bucket of data that holds 3 colours: Red, Green and Blue. Why? Because using those 3 colours we can trick the human eye to see over 16 million different colours (255 * 255 * 255).

http://i.imgur.com/B5Ipas.jpg

So because an int can hold up to 4 bytes a pixel is usually represented as an int. Sometimes the last byte is used for transparency (Alpha).

You are saving the r, g and b values as ints which make them all look something like this:

0000 0000 0000 0000 0000 0000 0000 0000

With the last first (bits are read from right to left) 2 bytes (8 bits) actually representing the given colour value (0-255).

So to pack them all together into 1 int you need to combine the bits and shift the Red colour 2 bytes (16 bits) to the left and the Green byte 1 byte (8 bits) to the left using the universal bitwise or operator so that you get them in the nice RGB order.

Or you could simply create the java Colour object using the “Color(int, int, int)” contructor. and skip the whole bit combining business.

No, RGB isn’t a very good colour space for interpolation. If you want to keep it simple, you could use HSV and Java’s built-in conversions between RGB and HSV [1]; otherwise you can either explore JAI (might have some useful stuff - I haven’t looked) or write some conversion code to and from Lab, perhaps porting it from http://www.codeproject.com/Articles/19045/Manipulating-colors-in-NET-Part-1

Colour is quite a big topic. If you can understand Spanish, there’s a 5 minute presentation I gave as a taster introduction to Lab on Youtube at http://www.youtube.com/watch?v=5HdY4XzZ0Ws

[1] Although if you do this, beware that as far as I’m aware they still haven’t fixed a bug I reported against it 9 years and 11 months ago. http://bugs.sun.com/view_bug.do?bug_id=4759386

While there’s also colorspace issues when interpolating colors, the problem our unvowelled monkey friend had was merely an arithmetic error.

If you’re not doing photo correction, HSV will probably be good enough.

This is important. Take, for example, converting to grayscale. A simple linear interpolation might do something like ((r+g+b)/255.0*3) * 255 and set all the r/g/b components to that value. It ends up looking like crap.

This works much better:


val brightness = math.sqrt(0.259 * color.getRed   * color.getRed +
                           0.587 * color.getGreen * color.getGreen +
                           0.114 * color.getBlue  * color.getBlue)

There are many other similar formulas available. It’s because the human eye is more sensitive to certain colors than others:

I think I’d use one of the cheap uniform colorspaces…like whatever that integer-to-integer one used in H264 is or the old cinepak one for instance.