protected override unsafe void ProcessFilter( UnmanagedImage source, UnmanagedImage destination, Rectangle rect )
{
int pixelSize = Image.GetPixelFormatSize( source.PixelFormat ) / 8;
// 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 srcStride = source.Stride;
int dstStride = destination.Stride;
int srcOffset = srcStride - rect.Width * pixelSize;
int dstOffset = srcStride - rect.Width * pixelSize;
// loop and array indexes
int i, j, t;
// brush radius
int radius = brushSize >> 1;
// intensity values
byte intensity, maxIntensity;
int[] intensities = new int[256];
byte* src = (byte*) source.ImageData.ToPointer( );
byte* dst = (byte*) destination.ImageData.ToPointer( );
byte* p;
// allign pointers to the first pixel to process
src += ( startY * srcStride + startX * pixelSize );
dst += ( startY * dstStride + startX * pixelSize );
if ( destination.PixelFormat == PixelFormat.Format8bppIndexed )
{
// Grayscale image
// for each line
for ( int y = startY; y < stopY; y++ )
{
// for each pixel
for ( int x = startX; x < stopX; x++, src++, dst++ )
{
// clear arrays
Array.Clear( intensities, 0, 256 );
// for each kernel row
for ( i = -radius; i <= radius; i++ )
{
t = y + i;
// skip row
if ( t < startY )
continue;
// break
if ( t >= stopY )
break;
// for each kernel column
for ( j = -radius; j <= radius; j++ )
{
t = x + j;
// skip column
if ( t < startX )
continue;
if ( t < stopX )
{
intensity = src[i * srcStride + j];
intensities[intensity]++;
}
}
}
// get most frequent intesity
maxIntensity = 0;
j = 0;
for ( i = 0; i < 256; i++ )
{
if ( intensities[i] > j )
{
maxIntensity = (byte) i;
j = intensities[i];
}
}
// set destination pixel
*dst = maxIntensity;
}
src += srcOffset;
dst += dstOffset;
}
}
else
{
// RGB image
int[] red = new int[256];
int[] green = new int[256];
int[] blue = new int[256];
// for each line
for ( int y = startY; y < stopY; y++ )
{
// for each pixel
for ( int x = startX; x < stopX; x++, src += pixelSize, dst += pixelSize )
{
// clear arrays
Array.Clear( intensities, 0, 256 );
Array.Clear( red, 0, 256 );
Array.Clear( green, 0, 256 );
Array.Clear( blue, 0, 256 );
// for each kernel row
for ( i = -radius; i <= radius; i++ )
{
t = y + i;
// skip row
if ( t < startY )
continue;
// break
if ( t >= stopY )
break;
// for each kernel column
for ( j = -radius; j <= radius; j++ )
{
t = x + j;
// skip column
if ( t < startX )
continue;
if ( t < stopX )
{
p = &src[i * srcStride + j * pixelSize];
// grayscale value using BT709
intensity = (byte) ( 0.2125 * p[RGB.R] + 0.7154 * p[RGB.G] + 0.0721 * p[RGB.B] );
//
intensities[intensity]++;
// red
red[intensity] += p[RGB.R];
// green
green[intensity] += p[RGB.G];
// blue
blue[intensity] += p[RGB.B];
}
}
}
// get most frequent intesity
maxIntensity = 0;
j = 0;
for ( i = 0; i < 256; i++ )
{
if ( intensities[i] > j )
{
maxIntensity = (byte) i;
j = intensities[i];
}
}
// set destination pixel
dst[RGB.R] = (byte) ( red[maxIntensity] / intensities[maxIntensity] );
dst[RGB.G] = (byte) ( green[maxIntensity] / intensities[maxIntensity] );
dst[RGB.B] = (byte) ( blue[maxIntensity] / intensities[maxIntensity] );
}
src += srcOffset;
dst += dstOffset;
}
}
}
}