public override void Compute(UnmanagedImage image, Rectangle area)
{
int height = image.Height;
int width = image.Width;
int stride = image.Stride;
if (area == Rectangle.Empty)
area = new Rectangle(0, 0, width, height);
Reset();
// stay inside the image
int windowX = Math.Max(area.X, 0);
int windowY = Math.Max(area.Y, 0);
int windowWidth = Math.Min(windowX + area.Width, width);
int windowHeight = Math.Min(windowY + area.Height, height);
unsafe
{
if (image.PixelFormat == PixelFormat.Format8bppIndexed)
{
int offset = stride - (windowWidth - windowX);
byte* src = (byte*)image.ImageData.ToPointer() + windowY * stride + windowX;
for (int j = windowY; j < windowHeight; j++)
{
float y = j - windowY;
for (int i = windowX; i < windowWidth; i++, src++)
{
float x = i - windowX;
float v = *src;
M00 += v;
M01 += y * v;
M10 += x * v;
if (Order >= 2)
{
M11 += x * y * v;
M02 += y * y * v;
M20 += x * x * v;
}
if (Order >= 3)
{
M12 += x * y * y * v;
M21 += x * x * y * v;
M30 += x * x * x * v;
M03 += y * y * y * v;
}
}
src += offset;
}
}
else
{
// color images
int pixelSize = Bitmap.GetPixelFormatSize(image.PixelFormat) / 8;
int offset = stride - (windowWidth - windowX) * pixelSize;
byte* src = (byte*)image.ImageData.ToPointer() + windowY * stride + windowX * pixelSize;
for (int j = windowY; j < windowHeight; j++)
{
float y = j - windowY;
for (int i = windowX; i < windowWidth; i++, src += pixelSize)
{
float x = i - windowX;
// BT709 - 0.2125, 0.7154, 0.0721
float v = (float)(0.2125 * src[RGB.R] + 0.7154 * src[RGB.G] + 0.0721 * src[RGB.B]);
M00 += v;
M01 += y * v;
M10 += x * v;
if (Order >= 2)
{
M11 += x * y * v;
M02 += y * y * v;
M20 += x * x * v;
}
if (Order >= 3)
{
M12 += x * y * y * v;
M21 += x * x * y * v;
M30 += x * x * x * v;
M03 += y * y * y * v;
}
}
src += offset;
}
}
}
InvM00 = 1f / M00;
CenterX = M10 * InvM00;
CenterY = M01 * InvM00;
}