protected override unsafe void ProcessFilter( UnmanagedImage image )
{
UnmanagedImage bgImage = null;
BitmapData bgLockedData = null;
// get image size
int width = image.Width;
int height = image.Height;
int offset = image.Stride - ( ( image.PixelFormat == PixelFormat.Format8bppIndexed ) ? width : width * 3 );
// check if we have provided background
if ( ( backgroundImage == null ) && ( unmanagedBackgroundImage == null ) )
{
// resize image to 1/3 of its original size to make bluring faster
ResizeBicubic resizeFilter = new ResizeBicubic( (int) width / 3, (int) height / 3 );
UnmanagedImage tempImage = resizeFilter.Apply( image );
// create background image from the input image blurring it with Gaussian 5 times
GaussianBlur blur = new GaussianBlur( 5, 21 );
blur.ApplyInPlace( tempImage );
blur.ApplyInPlace( tempImage );
blur.ApplyInPlace( tempImage );
blur.ApplyInPlace( tempImage );
blur.ApplyInPlace( tempImage );
// resize the blurred image back to original size
resizeFilter.NewWidth = width;
resizeFilter.NewHeight = height;
bgImage = resizeFilter.Apply( tempImage );
tempImage.Dispose( );
}
else
{
if ( backgroundImage != null )
{
// check background image
if ( ( width != backgroundImage.Width ) || ( height != backgroundImage.Height ) || ( image.PixelFormat != backgroundImage.PixelFormat ) )
{
throw new InvalidImagePropertiesException( "Source image and background images must have the same size and pixel format" );
}
// lock background image
bgLockedData = backgroundImage.LockBits(
new Rectangle( 0, 0, width, height ),
ImageLockMode.ReadOnly, backgroundImage.PixelFormat );
bgImage = new UnmanagedImage( bgLockedData );
}
else
{
bgImage = unmanagedBackgroundImage;
}
}
// get background image's statistics (mean value is used as correction factor)
ImageStatistics bgStatistics = new ImageStatistics( bgImage );
byte* src = (byte*) image.ImageData.ToPointer( );
byte* bg = (byte*) bgImage.ImageData.ToPointer( );
// do the job
if ( image.PixelFormat == PixelFormat.Format8bppIndexed )
{
// grayscale image
double mean = bgStatistics.Gray.Mean;
for ( int y = 0; y < height; y++ )
{
for ( int x = 0; x < width; x++, src++, bg++ )
{
if ( *bg != 0 )
{
*src = (byte) Math.Min( mean * *src / *bg, 255 );
}
}
src += offset;
bg += offset;
}
}
else
{
// color image
double meanR = bgStatistics.Red.Mean;
double meanG = bgStatistics.Green.Mean;
double meanB = bgStatistics.Blue.Mean;
for ( int y = 0; y < height; y++ )
{
for ( int x = 0; x < width; x++, src += 3, bg += 3 )
{
// red
if ( bg[RGB.R] != 0 )
{
src[RGB.R] = (byte) Math.Min( meanR * src[RGB.R] / bg[RGB.R], 255 );
}
// green
if ( bg[RGB.G] != 0 )
{
src[RGB.G] = (byte) Math.Min( meanG * src[RGB.G] / bg[RGB.G], 255 );
}
// blue
if ( bg[RGB.B] != 0 )
{
src[RGB.B] = (byte) Math.Min( meanB * src[RGB.B] / bg[RGB.B], 255 );
}
}
src += offset;
bg += offset;
}
}
if ( backgroundImage != null )
{
backgroundImage.UnlockBits( bgLockedData );
}
// dispose background image if it was not set manually
if ( ( backgroundImage == null ) && ( unmanagedBackgroundImage == null ) )
{
bgImage.Dispose( );
}
}
}