public List<IntPoint> ProcessImage( UnmanagedImage image )
{
// check image format
if (
( image.PixelFormat != PixelFormat.Format8bppIndexed ) &&
( image.PixelFormat != PixelFormat.Format24bppRgb ) &&
( image.PixelFormat != PixelFormat.Format32bppRgb ) &&
( image.PixelFormat != PixelFormat.Format32bppArgb )
)
{
throw new UnsupportedImageFormatException( "Unsupported pixel format of the source image." );
}
// get source image size
int width = image.Width;
int height = image.Height;
// make sure we have grayscale image
UnmanagedImage grayImage = null;
if ( image.PixelFormat == PixelFormat.Format8bppIndexed )
{
grayImage = image;
}
else
{
// create temporary grayscale image
grayImage = Grayscale.CommonAlgorithms.BT709.Apply( image );
}
int[,] susanMap = new int[height, width];
// do the job
unsafe
{
int stride = grayImage.Stride;
int offset = stride - width;
byte* src = (byte*) grayImage.ImageData.ToPointer( ) + stride * 3 + 3;
// for each row
for ( int y = 3, maxY = height - 3; y < maxY; y++ )
{
// for each pixel
for ( int x = 3, maxX = width - 3; x < maxX; x++, src++ )
{
// get value of the nucleus
byte nucleusValue = *src;
// usan - number of pixels with similar brightness
int usan = 0;
// center of gravity
int cx = 0, cy = 0;
// for each row of the mask
for ( int i = -3; i <= 3; i++ )
{
// determine row's radius
int r = rowRadius[i + 3];
// get pointer to the central pixel of the row
byte* ptr = src + stride * i;
// for each element of the mask's row
for ( int j = -r; j <= r; j++ )
{
// differenceThreshold
if ( System.Math.Abs( nucleusValue - ptr[j] ) <= differenceThreshold )
{
usan++;
cx += x + j;
cy += y + i;
}
}
}
// check usan size
if ( usan < geometricalThreshold )
{
cx /= usan;
cy /= usan;
if ( ( x != cx ) || ( y != cy ) )
{
// cornersList.Add( new Point( x, y ) );
usan = ( geometricalThreshold - usan );
}
else
{
usan = 0;
}
}
else
{
usan = 0;
}
// usan = ( usan < geometricalThreshold ) ? ( geometricalThreshold - usan ) : 0;
susanMap[y, x] = usan;
}
src += 6 + offset;
}
}
if ( image.PixelFormat != PixelFormat.Format8bppIndexed )
{
// free grayscale image
grayImage.Dispose( );
}
// collect interesting points - only those points, which are local maximums
List<IntPoint> cornersList = new List<IntPoint>( );
// for each row
for ( int y = 2, maxY = height - 2; y < maxY; y++ )
{
// for each pixel
for ( int x = 2, maxX = width - 2; x < maxX; x++ )
{
int currentValue = susanMap[y, x];
// for each windows' row
for ( int i = -2; ( currentValue != 0 ) && ( i <= 2 ); i++ )
{
// for each windows' pixel
for ( int j = -2; j <= 2; j++ )
{
if ( susanMap[y + i, x + j] > currentValue )
{
currentValue = 0;
break;
}
}
}
// check if this point is really interesting
if ( currentValue != 0 )
{
cornersList.Add( new IntPoint( x, y ) );
}
}
}
return cornersList;
}
}