/// <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); }