/// <summary> /// Returns an enumerator that iterates through the collection. /// </summary> /// /// <returns> /// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection. /// </returns> /// public IEnumerator <ResponseLayer[]> GetEnumerator() { ResponseLayer[] pyramid = new ResponseLayer[3]; for (int i = 0; i < octaves; i++) { // for each set of response layers for (int j = 0; j <= 1; j++) { // Grab the three layers forming the pyramid pyramid[0] = responses[map[i, j + 0]]; pyramid[1] = responses[map[i, j + 1]]; pyramid[2] = responses[map[i, j + 2]]; yield return(pyramid); } } }
private static double[] interpolate(int y, int x, ResponseLayer top, ResponseLayer mid, ResponseLayer bot) { int bs = bot.Width / top.Width; int ms = mid.Width / top.Width; int xp1 = x + 1, yp1 = y + 1; int xm1 = x - 1, ym1 = y - 1; // Compute first order scale-space derivatives double dx = (mid.Responses[y * ms, xp1 *ms] - mid.Responses[y * ms, xm1 *ms]) / 2f; double dy = (mid.Responses[yp1 * ms, x *ms] - mid.Responses[ym1 * ms, x *ms]) / 2f; double ds = (top.Responses[y, x] - bot.Responses[y * bs, x *bs]) / 2f; double[] d = { -dx, -dy, -ds }; // Compute Hessian double v = mid.Responses[y * ms, x *ms] * 2.0; double dxx = (mid.Responses[y * ms, xp1 *ms] + mid.Responses[y * ms, xm1 *ms] - v); double dyy = (mid.Responses[yp1 * ms, x *ms] + mid.Responses[ym1 * ms, x *ms] - v); double dxs = (top.Responses[y, xp1] - top.Responses[y, x - 1] - bot.Responses[y * bs, xp1 *bs] + bot.Responses[y * bs, xm1 *bs]) / 4f; double dys = (top.Responses[yp1, x] - top.Responses[y - 1, x] - bot.Responses[yp1 * bs, x *bs] + bot.Responses[ym1 * bs, x *bs]) / 4f; double dss = (top.Responses[y, x] + bot.Responses[y * ms, x *ms] - v); double dxy = (mid.Responses[yp1 * ms, xp1 *ms] - mid.Responses[yp1 * ms, xm1 *ms] - mid.Responses[ym1 * ms, xp1 *ms] + mid.Responses[ym1 * ms, xm1 *ms]) / 4f; double[,] H = { { dxx, dxy, dxs }, { dxy, dyy, dys }, { dxs, dys, dss }, }; // Compute interpolation offsets return(H.Inverse(true).Multiply(d)); }
/// <summary> /// Process image looking for interest points. /// </summary> /// /// <param name="image">Source image data to process.</param> /// /// <returns>Returns list of found interest points.</returns> /// /// <exception cref="UnsupportedImageFormatException"> /// The source image has incorrect pixel format. /// </exception> /// public List <SurfPoint> 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); } // 1. Compute the integral for the given image integral = IntegralImage.FromBitmap(grayImage); // 2. Compute interest point response map if (responses == null || image.Width != responses.Width || image.Height != responses.Height) { responses = new ResponseFilters(image.Width, image.Height, octaves, initial); } responses.Compute(integral); // 3. Suppress non-maximum points List <SurfPoint> featureList = new List <SurfPoint>(); // for each image pyramid in the response map foreach (ResponseLayer[] layers in responses) { // Grab the three layers forming the pyramid ResponseLayer bot = layers[0]; // bottom layer ResponseLayer mid = layers[1]; // middle layer ResponseLayer top = layers[2]; // top layer int border = (top.Size + 1) / (2 * top.Step); int tstep = top.Step; int mstep = mid.Size - bot.Size; int mscale = mid.Width / top.Width; int bscale = bot.Width / top.Width; int r = 1; // for each row for (int y = border + 1; y < top.Height - border; y++) { // for each pixel for (int x = border + 1; x < top.Width - border; x++) { float currentValue = mid.Responses[y * mscale, x *mscale]; // for each windows' row for (int i = -r; (currentValue >= threshold) && (i <= r); i++) { // for each windows' pixel for (int j = -r; j <= r; j++) { int yi = y + i; int xj = x + j; // for each response layer if (top.Responses[yi, xj] >= currentValue || bot.Responses[yi * bscale, xj *bscale] >= currentValue || ((i != 0 || j != 0) && mid.Responses[yi * mscale, xj *mscale] >= currentValue)) { currentValue = 0; break; } } } // check if this point is really interesting if (currentValue >= threshold) { // interpolate to sub-pixel precision double[] offset = interpolate(y, x, top, mid, bot); if (System.Math.Abs(offset[0]) < 0.5 && System.Math.Abs(offset[1]) < 0.5 && System.Math.Abs(offset[2]) < 0.5) { featureList.Add(new SurfPoint( (float)((x + offset[0]) * tstep), (float)((y + offset[1]) * tstep), (float)(0.1333f * (mid.Size + offset[2] * mstep)), mid.Laplacian[y * mscale, x * mscale])); } } } } } return(featureList); }
private List <SpeededUpRobustFeaturePoint> processImage(UnmanagedImage 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); } // 1. Compute the integral for the given image integral = IntegralImage.FromBitmap(grayImage); // 2. Create and compute interest point response map if (responses == null) { // re-create only if really needed responses = new ResponseLayerCollection(image.Width, image.Height, octaves, initial); } else { responses.Update(image.Width, image.Height, initial); } // Compute the response map responses.Compute(integral); // 3. Suppress non-maximum points List <SpeededUpRobustFeaturePoint> featureList = new List <SpeededUpRobustFeaturePoint>(); // for each image pyramid in the response map foreach (ResponseLayer[] layers in responses) { // Grab the three layers forming the pyramid ResponseLayer bot = layers[0]; // bottom layer ResponseLayer mid = layers[1]; // middle layer ResponseLayer top = layers[2]; // top layer int border = (top.Size + 1) / (2 * top.Step); int tstep = top.Step; int mstep = mid.Size - bot.Size; int r = 1; // for each row for (int y = border + 1; y < top.Height - border; y++) { // for each pixel for (int x = border + 1; x < top.Width - border; x++) { int mscale = mid.Width / top.Width; int bscale = bot.Width / top.Width; double currentValue = mid.Responses[y * mscale, x *mscale]; // for each windows' row for (int i = -r; (currentValue >= threshold) && (i <= r); i++) { // for each windows' pixel for (int j = -r; j <= r; j++) { int yi = y + i; int xj = x + j; // for each response layer if (top.Responses[yi, xj] >= currentValue || bot.Responses[yi * bscale, xj *bscale] >= currentValue || ((i != 0 || j != 0) && mid.Responses[yi * mscale, xj *mscale] >= currentValue)) { currentValue = 0; break; } } } // check if this point is really interesting if (currentValue >= threshold) { // interpolate to sub-pixel precision double[] offset = interpolate(y, x, top, mid, bot); if (System.Math.Abs(offset[0]) < 0.5 && System.Math.Abs(offset[1]) < 0.5 && System.Math.Abs(offset[2]) < 0.5) { featureList.Add(new SpeededUpRobustFeaturePoint( (x + offset[0]) * tstep, (y + offset[1]) * tstep, 0.133333333 * (mid.Size + offset[2] * mstep), mid.Laplacian[y * mscale, x * mscale])); } } } } } descriptor = null; if (featureType != SpeededUpRobustFeatureDescriptorType.None) { descriptor = new SpeededUpRobustFeaturesDescriptor(integral); descriptor.Extended = featureType == SpeededUpRobustFeatureDescriptorType.Extended; descriptor.Invariant = computeOrientation; descriptor.Compute(featureList); } else if (computeOrientation) { descriptor = new SpeededUpRobustFeaturesDescriptor(integral); foreach (var p in featureList) { p.Orientation = descriptor.GetOrientation(p); } } return(featureList); }