protected override unsafe void ProcessFilter(UnmanagedImage sourceData, UnmanagedImage destinationData, Rectangle rect)
{
int pixelSize = Image.GetPixelFormatSize(sourceData.PixelFormat) / 8;
int pixelSize2 = pixelSize * 2;
// processing start and stop X,Y positions
int startX = rect.Left;
int startY = rect.Top;
int stopX = startX + rect.Width;
int stopY = startY + rect.Height;
int startXP2 = startX + 2;
int startYP2 = startY + 2;
int stopXM2 = stopX - 2;
int stopYM2 = stopY - 2;
int srcStride = sourceData.Stride;
int dstStride = destinationData.Stride;
int srcOffset = srcStride - rect.Width * pixelSize;
int dstOffset = dstStride - rect.Width * pixelSize;
// gradient and weights
double gx, gy, weight, weightTotal, total;
// precalculated factor value
double f = -8 * factor * factor;
// do the job
byte* src = (byte*)sourceData.ImageData.ToPointer() + srcStride * 2;
byte* dst = (byte*)destinationData.ImageData.ToPointer() + dstStride * 2;
// allign pointers to the first pixel to process
src += (startY * srcStride + startX * pixelSize);
dst += (startY * dstStride + startX * pixelSize);
for (int y = startYP2; y < stopYM2; y++)
{
src += pixelSize2;
dst += pixelSize2;
for (int x = startXP2; x < stopXM2; x++)
{
for (int i = 0; i < pixelSize; i++, src++, dst++)
{
weightTotal = 0;
total = 0;
// original formulas for weight calculation:
// w(x, y) = exp( -1 * (Gx^2 + Gy^2) / (2 * factor^2) )
// Gx(x, y) = (I(x + 1, y) - I(x - 1, y)) / 2
// Gy(x, y) = (I(x, y + 1) - I(x, y - 1)) / 2
//
// here is a little bit optimized version
// x - 1, y - 1
gx = src[-srcStride] - src[-pixelSize2 - srcStride];
gy = src[-pixelSize] - src[-pixelSize - 2 * srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[-pixelSize - srcStride];
weightTotal += weight;
// x, y - 1
gx = src[pixelSize - srcStride] - src[-pixelSize - srcStride];
gy = *src - src[-2 * srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[-srcStride];
weightTotal += weight;
// x + 1, y - 1
gx = src[pixelSize2 - srcStride] - src[-srcStride];
gy = src[pixelSize] - src[pixelSize - 2 * srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[pixelSize - srcStride];
weightTotal += weight;
// x - 1, y
gx = *src - src[-pixelSize2];
gy = src[-pixelSize + srcStride] - src[-pixelSize - srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[-pixelSize];
weightTotal += weight;
// x, y
gx = src[pixelSize] - src[-pixelSize];
gy = src[srcStride] - src[-srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * (*src);
weightTotal += weight;
// x + 1, y
gx = src[pixelSize2] - *src;
gy = src[pixelSize + srcStride] - src[pixelSize - srcStride];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[pixelSize];
weightTotal += weight;
// x - 1, y + 1
gx = src[srcStride] - src[-pixelSize2 + srcStride];
gy = src[-pixelSize + 2 * srcStride] - src[-pixelSize];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[-pixelSize + srcStride];
weightTotal += weight;
// x, y + 1
gx = src[pixelSize + srcStride] - src[-pixelSize + srcStride];
gy = src[2 * srcStride] - *src;
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[srcStride];
weightTotal += weight;
// x + 1, y + 1
gx = src[pixelSize2 + srcStride] - src[srcStride];
gy = src[pixelSize + 2 * srcStride] - src[pixelSize];
weight = System.Math.Exp((gx * gx + gy * gy) / f);
total += weight * src[pixelSize + srcStride];
weightTotal += weight;
// save destination value
*dst = (weightTotal == 0.0) ? *src : (byte)System.Math.Min(total / weightTotal, 255.0);
}
}
src += srcOffset + pixelSize2;
dst += dstOffset + pixelSize2;
}
}
}