Currently doing real-time processing where every frame counts, with a modified version of Peter Taylor's answer. Tested on a weak Raspberry PI it still resulted in 24 out of 25 frames per second. Which is amazing performance knowing what the specifications are of it and running it through Mono.
The method itself was hard to understand at first, but maybe this way of using it might clear a few things up.
Please note that this only works with 32bpp images due to the use of the Unsigned 32-bit integer to go through the memory.
public unsafe uint[] GetAverageColorInRegion(Bitmap source, Rectangle region)
{
var rectangle = new Rectangle(0, 0, source.Width, source.Height);
var bitmapData = source.LockBits(rectangle, ImageLockMode.ReadOnly, source.PixelFormat);
var pixelCount = region.Width * region.Height;
var scanWidth = bitmapData.Stride / 4;
uint[] totals = { 0, 0, 0 };
int flushCounter = 0;
uint sumRR00BB = 0;
uint sum00GG00 = 0;
for (var y = region.Y; y < region.Y + region.Height; y++)
{
uint* row = (uint*)bitmapData.Scan0 + y * scanWidth;
for (var x = region.X; x < region.X + region.Width; x++)
{
sumRR00BB += row[x] & 0xff00ff;
sum00GG00 += row[x] & 0x00ff00;
// Flush before overflow occurs.
if (flushCounter++ == 0xff)
{
totals[0] += sumRR00BB >> 16;
totals[1] += sum00GG00 >> 8;
totals[2] += sumRR00BB & 0xffff;
sumRR00BB = 0;
sum00GG00 = 0;
flushCounter = 0;
}
}
}
// Flush left-over's.
totals[0] += sumRR00BB >> 16;
totals[1] += sum00GG00 >> 8;
totals[2] += sumRR00BB & 0xffff;
// Average the totals.
totals[0] /= (uint)pixelCount;
totals[1] /= (uint)pixelCount;
totals[2] /= (uint)pixelCount;
source.UnlockBits(bitmapData);
return totals;
}