gator
gator

Reputation: 3523

Averaging four pixels of image yields wonky colors

I have an image of specified height and width to be shrunk down 1/4th. My method for doing so has been to take 4 pixels (so (0,0),(1,0),(0,1),(1,1) for example), grab the RGB values of each and then average out the RGB values and inject it to a new image as one pixel (so those four pixel co-ords mentioned earlier will become (0,0) of a new image).

It works, sort of; I get some color wonkiness in the result.

image

The left is the original image, and to the right is it processed through the method above. I can't for the life of me figure out why the colors are screwy.

For what it's worth, I'm using the below methods:

getPixel();
getColor();
setColor();

And the RGB values are grabbed separately via getRed(), etc. These are stored as integers.

Upvotes: 2

Views: 287

Answers (4)

Geobits
Geobits

Reputation: 22342

You never reset r,g,b in your loop, so the next pixel isn't getting the right value(in any case). It's adding the four pixels to the last pixel result, then dividing by 4.

Since there are five numbers added together, you're getting a creep up in your color values. For instance, if the previous pixel red value was 240, and the next four are 220,220,220,220, you get an "average" of 280, even though all four pixels are 220. The next pixel is then messed up even further, etc.

That's why you get a "creep" to overflow. When one goes over 255, you get overflow when the numbers are combined back together with setColor(). You can see clearly where each byte is overflowing. First come the red(in the cyan areas), then the yellow drops out(in the dark blueish).

Just make sure you reset r,g,b to zero after you call setColor() and it should be fine.

Upvotes: 2

Joel
Joel

Reputation: 358

Where do you reset the variables r, g, b?

b is used both for color and to iterate?

Upvotes: 2

lead_the_zeppelin
lead_the_zeppelin

Reputation: 2052

Just declare r,g,b as long unsigned int.

long unsigned int r,g,b;

In spots where the color could be (255,0,0) and if the format is RGBA. The R component is bit-shifted 24 bits to use up the most significant 8 bits. Even multiplying it by 2 could potentially cause an overflow of the unsigned 32 bit int. Using 64 bit(signed or unsigned) would solve this problem

Upvotes: 0

DarenW
DarenW

Reputation: 16906

Looks like overflow. What data type are R, G and B? If they're 8-bit unsigned, convert to 16-bit unsigned before adding and shifting. An average will come out in the proper range, since an average cannot exceed the range from the smallest value to the largest value given, but the intermediate sum will easily do so.

If you don't mind slower processing, convert to floats, add and divide by 4, then convert back. A whole lot more math can be done such as logarithms, hyperbolic tangents (my fave), etc. But your question does not suggest any need for such things. It is the nearly universal cure, however, for overflows when the math gets heavy.

Upvotes: 2

Related Questions