/// <summary>
/// Process image looking for corners.
/// </summary>
///
/// <param name="image">Source image data to process.</param>
///
/// <returns>Returns list of found corners (X-Y coordinates).</returns>
///
/// <exception cref="UnsupportedImageFormatException">
/// The source image has incorrect pixel format.
/// </exception>
///
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.");
}
// 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);
}
// get source image size
int width = grayImage.Width;
int height = grayImage.Height;
int stride = grayImage.Stride;
int offset = stride - width;
// 1. Calculate partial differences
UnmanagedImage diffx = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed);
UnmanagedImage diffy = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed);
UnmanagedImage diffxy = UnmanagedImage.Create(width, height, PixelFormat.Format8bppIndexed);
unsafe
{
// Compute dx and dy
byte *src = (byte *)grayImage.ImageData.ToPointer();
byte *dx = (byte *)diffx.ImageData.ToPointer();
byte *dy = (byte *)diffy.ImageData.ToPointer();
byte *dxy = (byte *)diffxy.ImageData.ToPointer();
// for each line
for (int y = 0; y < height; y++)
{
// for each pixel
for (int x = 0; x < width; x++, src++, dx++, dy++)
{
// TODO: Place those verifications
// outside the innermost loop
if (x == 0 || x == width - 1 ||
y == 0 || y == height - 1)
{
*dx = *dy = 0; continue;
}
int h = -(src[-stride - 1] + src[-1] + src[stride - 1]) +
(src[-stride + 1] + src[+1] + src[stride + 1]);
*dx = (byte)(h > 255 ? 255 : h < 0 ? 0 : h);
int v = -(src[-stride - 1] + src[-stride] + src[-stride + 1]) +
(src[+stride - 1] + src[+stride] + src[+stride + 1]);
*dy = (byte)(v > 255 ? 255 : v < 0 ? 0 : v);
}
src += offset;
dx += offset;
dy += offset;
}
// Compute dxy
dx = (byte *)diffx.ImageData.ToPointer();
dxy = (byte *)diffxy.ImageData.ToPointer();
// for each line
for (int y = 0; y < height; y++)
{
// for each pixel
for (int x = 0; x < width; x++, dx++, dxy++)
{
if (x == 0 || x == width - 1 ||
y == 0 || y == height - 1)
{
*dxy = 0; continue;
}
int v = -(dx[-stride - 1] + dx[-stride] + dx[-stride + 1]) +
(dx[+stride - 1] + dx[+stride] + dx[+stride + 1]);
*dxy = (byte)(v > 255 ? 255 : v < 0 ? 0 : v);
}
dx += offset;
dxy += offset;
}
}
// 2. Smooth the diff images
if (sigma > 0.0)
{
GaussianBlur blur = new GaussianBlur(sigma);
blur.ApplyInPlace(diffx);
blur.ApplyInPlace(diffy);
blur.ApplyInPlace(diffxy);
}
// 3. Compute Harris Corner Response
float[,] H = new float[height, width];
unsafe
{
byte *ptrA = (byte *)diffx.ImageData.ToPointer();
byte *ptrB = (byte *)diffy.ImageData.ToPointer();
byte *ptrC = (byte *)diffxy.ImageData.ToPointer();
float M, A, B, C;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
A = *(ptrA++);
B = *(ptrB++);
C = *(ptrC++);
// Harris corner measure
M = (A * B - C * C) - (k * ((A + B) * (A + B)));
if (M > threshold)
{
H[y, x] = M;
}
else
{
H[y, x] = 0;
}
}
ptrA += offset;
ptrB += offset;
ptrC += offset;
}
}
// Free resources
diffx.Dispose();
diffy.Dispose();
diffxy.Dispose();
if (image.PixelFormat != PixelFormat.Format8bppIndexed)
{
grayImage.Dispose();
}
// 4. Suppress non-maximum points
List <IntPoint> cornersList = new List <IntPoint>();
// for each row
for (int y = r, maxY = height - r; y < maxY; y++)
{
// for each pixel
for (int x = r, maxX = width - r; x < maxX; x++)
{
float currentValue = H[y, x];
// for each windows' row
for (int i = -r; (currentValue != 0) && (i <= r); i++)
{
// for each windows' pixel
for (int j = -r; j <= r; j++)
{
if (H[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);
}