# How can I compute the average color of a texture?

I'm making a mini-map system for my tile based game, and I thought the best way to accomplish this would be the following:

At the beginning of the game, I calculate the predominant color of every block (tile type), and store it somewhere. Then, to create the mini-map, I just run through the block matrix and paint a single pixel for each block, instead of it's full 16x16 image.

To do this, I need to be able to get the pixel color of a given position in the texture (to compute the average color). The way I was doing it was using getTextureData().

This method, however, seems to be buggy and very poorly-documented. It returns a single array with all the data in what I thought was RGBA order. Thus, the code to get the average color of a rectangle starting at x and y with dimensions w and h from the texture t would be:

int r = 0, g = 0, b = 0;
byte[] bytes = t.getTextureData();
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
r += bytes[4*((y + i)*t.getImageWidth() + x + j)];
g += bytes[4*((y + i)*t.getImageWidth() + x + j) + 1];
b += bytes[4*((y + i)*t.getImageWidth() + x + j) + 2];
}
}

r /= bytes.length / 4;
g /= bytes.length / 4;
b /= bytes.length / 4;


However, this does not seem to work. It produces incorrect (often negative) values for each pixel. Is my approach correct or should be I handling the problem differently?

• I would recommend a separate sprite sheet with the mini-map colors for corresponding tiles as some tiles may have the same color but you may want to indicate them differently, or different colors but indicate them the same. – UnderscoreZero May 1 '13 at 16:00
• That is an amazing idea. I will implement it so that the last "block" in the sprite-sheet will actually be the pixel colors of all other blocks. Thanks! – Luan Nico May 1 '13 at 18:05

Your approach is sound (getTextureData is the right basic idea).

However, you aren't checking the texture's hasAlpha method to see if the texture has alpha, in which case each pixel would be three bytes and not four. Also, you assume that the texture is in RGBA format and that's not always necessarily going to be true (depending on where the underlying texture object is getting its data from).

Furthermore, in your loop you are trying to access a byte of a pixel via the computation

bytes[4 * ((y + i) * t.getImageWidth() + x + j)]


however, your loops (with i and j) are over the width and height of the source rectangle in pixels. For an input of (0,0), this works out fine. But for an input of (0, 1) (assuming x and y are both 0), you end up trying to access bytes, which is not what you want (you want to access bytes).

I'd write the loop thusly:

int pixelSize = t.hasAlpha() ? 4 : 3;
for (int row = y; row < y + h; ++row) {
for (int column = x; column < x + w; ++column) {
// Compute the pixel index.
int pixelIndex= row * t.getTextureWidth() + column;

// The byte index can be obtained by multiplying the pixel index
// by the size of each pixel; that will refer to the first component
// of the pixel.
int byteIndex = pixelSize * pixelIndex;

// Simple offsets can reach the remaining components of the pixel.
r += bytes[byteIndex];
g += bytes[byteIndex + 1];
b += bytes[byteIndex + 2]
}
}


(Note that this does not attempt to handle non-RGB-ordered textures, but it does suggest a way to deal with textures missing alpha).

Finally, once you have summed up each component, you only need to divide by the number of pixels that were in the subrectangle you measured to get the alpha:

int pixelCount = w * h;
r /= pixelCount;
g /= pixelCount;
b /= pixelCount;


(Previously, you were dividing by the number of pixels in the entire texture, which is not always the same size as the area you actually measured.)