/// <summary> /// Extracts corners from the gradient image. The method used here is one which uses the eigensystem at each /// pixel (computed from the smoothed second moments) to determine whether a corner is present. A corner is /// one in which both eigenvalues are above the threshold. /// </summary> /// <param name="grad">Gradient image of source</param> /// <param name="threshold">Threshold used to determine corners</param> /// <returns>A list of corners</returns> public static unsafe Vector[] Extract(GradientImage grad, float threshold) { EigensystemImage eigen = EigensystemImage.Compute(SecondMomentImage.Compute(grad)); List <Vector> points = new List <Vector>(); int rows = eigen.Rows; int columns = eigen.Columns; fixed(float *src = eigen.RawArray) { float *srcPtr = src; int channels = eigen.Channels; for (int r = 0; r < rows; r++) { for (int c = 0; c < columns; c++, srcPtr += channels) { float lambda1 = srcPtr[0]; float lambda2 = srcPtr[1]; if (lambda1 > threshold && lambda2 > threshold) { points.Add(new DenseVector(new float[] { c, r })); } } } } return(points.ToArray()); }
/// <summary> /// Computes the second moments at each pixel based on the provided gradient image. /// </summary> /// <param name="grad">The gradient of the source image</param> /// <returns>The second moment image</returns> public static unsafe SecondMomentImage Compute(GradientImage grad) { int rows = grad.Rows; int columns = grad.Columns; float[, ,] data = new float[rows, columns, 3]; fixed(float *src = grad.RawArray, dst = data) { float *srcPtr = src; float *dstPtr = dst; int length = rows * columns; for (int i = 0; i < length; i++, srcPtr += 4) { float ix = srcPtr[2]; float iy = srcPtr[3]; * dstPtr++ = ix * ix; * dstPtr++ = iy * iy; * dstPtr++ = ix * iy; } } SecondMomentImage image = new SecondMomentImage(); image.SetData(data); return(image); }
/// <summary> /// Computes DiscreteContours at the samples provided. /// </summary> /// <param name="samples">Samples to compute contours at</param> /// <param name="pyramid">Image pyramid to use for samples</param> /// <returns>DiscreteContours</returns> public static List <Keypoint> Compute(List <ScaleSpaceSample> samples, ScaleSpacePyramid <GrayscaleImage> pyramid) { GradientImage[,] grads = new GradientImage[pyramid.Octaves, pyramid.Levels]; List <Keypoint> points = new List <Keypoint>(); foreach (ScaleSpaceSample sample in samples) { if (grads[sample.Octave, sample.Level] == null) { grads[sample.Octave, sample.Level] = GradientImage.Compute(pyramid[sample.Octave, sample.Level], false); } points.Add(Compute(sample, grads[sample.Octave, sample.Level], pyramid.ComputeSigma(sample.Octave, sample.Level))); } return(points); }
/// <summary> /// Compute the Discrete Contour descriptor from the provided patch. This match must be of gradients and /// of the size specified by <see cref="RequiredPatchSize"/>. A raw image patch, or a patch of different /// dimensions, will not work. /// </summary> /// <param name="sample">Sample to compute DiscreteContour at</param> /// <param name="gradImage">Gradient image to use</param> /// <param name="scale">The scale of the sample (the value returned by ComputeSigma() in ScaleSpacePyramid)</param> /// <returns>Discrete Contour descriptor</returns> public static unsafe Keypoint Compute(ScaleSpaceSample sample, GradientImage gradImage, float scale) { Keypoint point = new Keypoint(sample.X, sample.Y, sample.ImageScale, scale, 0); float[] desc = new float[DESCRIPTOR_LENGTH]; int startR = sample.Row - SQUARE_SIZE / 2; int startC = sample.Column - SQUARE_SIZE / 2; int rows = gradImage.Rows; int columns = gradImage.Columns; int channels = gradImage.Channels; int stride = columns * channels; fixed(int *mask = MASK) { fixed(float *patch = gradImage.RawArray) { int *maskPtr = mask; float *patchPtr; if (startR < 0) { if (startC < 0) { patchPtr = patch; } else { patchPtr = patch + startC * channels; } } else if (startC < 0) { patchPtr = patch + startR * stride; } else { patchPtr = patch + startR * stride + startC * channels; } for (int r = 0; r < SQUARE_SIZE; r++) { int rr = startR + r; float *patchScan = patchPtr; if (rr >= 0 && rr < rows - 1) { patchPtr += stride; } for (int c = 0; c < SQUARE_SIZE; c++, maskPtr++) { int bin = *maskPtr; //MASK[rr, cc]; float mag = patchScan[0]; //gradientPatch[rr, cc, 0]; float dir = patchScan[1]; //gradientPatch[rr, cc, 1]; int cc = startC + c; if (cc >= 0 && cc < columns - 1) { patchScan += channels; } //if (mag != gradImage[Math.Max(0, Math.Min(rr, rows - 1)), Math.Max(0, Math.Min(cc, columns - 1)), 0]) // throw new Exception("testing"); if (bin < BINS) { addValue(bin, dir, mag * 2, desc); } else { bin -= BINS; int bin1 = HALF[bin, 0]; int bin2 = HALF[bin, 1]; addValue(bin1, dir, mag, desc); addValue(bin2, dir, mag, desc); } } } } } point.Descriptor = desc; return(point); }
/// <summary> /// Extracts corners from the gradient image using the default threshold. /// </summary> /// <param name="grad">Gradient image of source</param> /// <returns>A list of corners</returns> public static Vector[] Extract(GradientImage grad) { return(Extract(grad, EigensystemImage.SENSITIVITY)); }
/// <summary> /// Computes a gradient image from the source image. /// </summary> /// <param name="sigma">The sigma to use when blurring the source image.</param> /// <param name="image">Source image</param> /// <returns>Gradient image</returns> public static unsafe GradientImage Compute(GrayscaleImage image, float sigma) { int rows = image.Rows; int columns = image.Columns; if (sigma > 0) { image = Convolution.ConvolveGaussian <GrayscaleImage>(image, sigma); } float[, ,] data = new float[rows, columns, 4]; fixed(float *src = image.RawArray, dst = data) { float *srcPtr = src; float *srcPtrP = srcPtr + 1; float *dstPtr = dst; dstPtr += 2; // X derivative for (int r = 0; r < rows; r++) { *dstPtr = *srcPtrP - *srcPtr; dstPtr += 4; srcPtrP++; for (int c = 1; c < columns - 1; c++, srcPtr++, srcPtrP++, dstPtr += 4) { *dstPtr = *srcPtrP - *srcPtr; } srcPtrP--; *dstPtr = *srcPtrP - *srcPtr; dstPtr += 4; srcPtr += 2; srcPtrP += 2; } srcPtr = src; srcPtrP = srcPtr + columns; dstPtr = dst; dstPtr += 3; int stride = 4 * columns; for (int c = 0; c < columns; c++, srcPtr++, srcPtrP++, dstPtr += 4) { float *srcScan = srcPtr; float *srcScanP = srcPtrP; float *dstScan = dstPtr; * dstScan = *srcScanP - *srcScan; dstScan += stride; srcScanP += columns; for (int r = 1; r < rows - 1; r++, dstScan += stride, srcScan += columns, srcScanP += columns) { *dstScan = *srcScanP - *srcScan; } srcScanP -= columns; *dstScan = *srcScanP - *srcScan; } dstPtr = dst; int length = rows * columns; for (int i = 0; i < length; i++, dstPtr += 4) { setData(dstPtr); } } GradientImage result = new GradientImage(); result.SetData(data); return(result); }