Fastest / easiest way to average ARGB color ints?

I have five colors saved in #AARRGGBB format as unsigned ints, and I need to take the average of all five. Obviously, I can't just divide each int into five and just add them, and the only way I've been thinking so far is to break them down in masses, make each channel separately, and then put them together again. Is there a smart or concise way of averaging all five of them?

+4
source share
5 answers

Halfway between your proposed solution (OP) and Patrick's solution, it looks pretty neat:

 Color colors[5]={ 0xAARRGGBB,...}; unsigned long sum1=0,sum2=0; for (int i=0;i<5;i++) { sum1+= colors[i] &0x00FF00FF; // 0x00RR00BB sum2+=(colors[i]>>8)&0x00FF00FF; // 0x00AA00GG } unsigned long output=0; output|=(((sum1&0xFFFF)/5)&0xFF); output|=(((sum2&0xFFFF)/5)&0xFF)<<8; sum1>>=16;sum2>>=16; // and now the top halves output|=(((sum1&0xFFFF)/5)&0xFF)<<16; output|=(((sum2&0xFFFF)/5)&0xFF)<<24; 

I don’t think you can really divide sum1 / sum2 by 5, because the bits from the upper half will spill ...

If the approximation were valid, you could try multiplying by something like 0.1875 (0.125 + 0.0625) (this means: multiply by 3 and shift down by 4 places. This can be done using bitmasking and leaving). The problem is that 0.2 has a crappy binary representation, so multiplying it is an ass.

As always, accuracy or speed. Your choice.

+3
source

When using x86 machines with at least SSE, and if you only need to get closer, you can use the PAVGB (Packed Average Byte) assembly instruction, which averages bytes. For an explanation, see http://www.tommesani.com/SSEPrimer.html .

Since you have 5 values, you will need to create declarations when calling PAVGB, since PAVGB will only execute two values ​​at a time.

+2
source

I found a smart solution to your problem, unfortunately, it only applies if the number of colors is 2. I will show it in the case of two colors:

 mask = 01010101 pom = ~(a^b & mask) # ^ means xor here, ~ negation a = a & pom b = b & pom avg = (a+b) >> 1 

The trick of this method - when calculating the average LSB value of the sum (in the case of two numbers) does not matter, since it will be reset in the division (we, of course, say integers). In your problem, the LSB of partial sums at the same time carries an adjacent color bit bit. Provided that the LSB of each color sum is 0 , you can safely add these two integers - the additions will not interfere with each other. A bit shift divides each color into two.

This method can also be used with four colors, but you must implement the detection flag of the transfer flag of the sum of numbers consisting of the last two bits of each color. You can also omit this part and only zero of the last two bits of each color - the biggest mistake made with this omission is 1 for each component.

+1
source

EDIT I will leave this attempt for posterity, but please note that this is incorrect and will not work.

One smart way you could do this is to insert zeros between components, divide by unsigned long, average the numbers, convert back to a hexadecimal string, delete zeros, and finally parse into unsigned int.

i.e. convert #AARRGGBB to # AA00RR00GG00BB

This method includes parsing and string manipulation, so it will undoubtedly be slower than the method you proposed.

If you carefully analyzed your own decision, it really would look very smart.

0
source

How about a pixel shader for working with a GPU?

0
source

All Articles