protected override unsafe void ProcessFilter( UnmanagedImage source, UnmanagedImage destination, Rectangle rect )
{
int pixelSize = Image.GetPixelFormatSize( source.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 = source.Stride;
int dstStride = destination.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*) source.ImageData.ToPointer( ) + srcStride * 2;
byte* dst = (byte*) destination.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;
}
}
}