/// <summary> /// Compute the dct of a given vector /// </summary> /// <param name="featureVector">vector of input series</param> /// <returns>the dct of R</returns> internal static Digest ComputeDct(float[] featureVector) { int N = featureVector.Length; float[] R = featureVector; float[] coefficients = new float[Digest.LENGTH]; float max = 0f; float min = 0f; float div2n = MathF.PI / (2 * N); float divSq = 1 / MathF.Sqrt(N); for (int k = 0; k < Digest.LENGTH; k++) { float sum = 0f; for (int n = 0; n < N; n++) { sum += R[n] * MathF.Cos((2 * n + 1) * k * div2n); } float v = coefficients[k] = sum * divSq * (k == 0 ? 1 : SQRT_TWO); max = Math.Max(max, v); min = Math.Min(min, v); } return(NormalizeDigest(coefficients, max, min)); }
private static float GetCrossCorrelationCore(float[] x, float[] y) { float max = 0f; for (int d = 0; d < x.Length; d++) { float v; v = GetCrossCorrelationForOffset(x, y, d); max = Math.Max(max, v); } return(MathF.Sqrt(max)); }
/// <summary> /// return dct matrix, C Return DCT matrix of square size, <paramref name="size" /> /// </summary> /// <param name="size">int denoting the size of the square matrix to create.</param> /// <returns>size <paramref name="size" />x<paramref name="size" /> containing the dct matrix</returns> internal static FloatImage CreateDctMatrix(int size) { FloatImage ret = new FloatImage(size, size, 1 / (float)Math.Sqrt(size)); float c1 = MathF.Sqrt(2f / size); float rad = MathF.PI / 2 / size; for (int x = 0; x < size; x++) { for (int y = 1; y < size; y++) { ret[x, y] = c1 * MathF.Cos(rad * y * (2 * x + 1)); } } return(ret); }
internal static FloatImage CreateMHKernel(float alpha, float level) { int sigma = (int)(4 * MathF.Pow(alpha, level)); FloatImage kernel = new FloatImage(2 * sigma + 1, 2 * sigma + 1); for (int y = 0; y < kernel.Width; y++) { for (int x = 0; x < kernel.Height; x++) { float xpos = MathF.Pow(alpha, -level) * (x - sigma); float ypos = MathF.Pow(alpha, -level) * (y - sigma); float A = xpos * xpos + ypos * ypos; kernel[x, y] = (float)((2 - A) * MathF.Exp(-A / 2)); } } return(kernel); }
/// <summary> /// compute the feature vector from a radon projection map. /// </summary> /// <param name="projections">Projections struct</param> /// <returns>Features struct</returns> internal static float[] ComputeFeatureVector(Projections projections) { FloatImage map = projections.Region; int[] ppl = projections.PixelsPerLine; int N = ppl.Length; int D = map.Height; float[] fv = new float[N]; float sum = 0f; float sum_sqd = 0f; for (int k = 0; k < N; k++) { float line_sum = 0f; float line_sum_sqd = 0f; int nb_pixels = ppl[k]; for (int i = 0; i < D; i++) { line_sum += map[k, i]; line_sum_sqd += map[k, i] * map[k, i]; } fv[k] = (float)(nb_pixels > 0 ? (line_sum_sqd / nb_pixels) - (line_sum * line_sum) / (nb_pixels * nb_pixels) : 0); sum += fv[k]; sum_sqd += fv[k] * fv[k]; } float mean = sum / N; float var = 1 / MathF.Sqrt((sum_sqd / N) - (sum * sum) / (N * N)); for (int i = 0; i < N; i++) { fv[i] = (fv[i] - mean) * var; } return(fv); }
/// <summary> /// Find radon projections of N lines running through the image center for lines angled 0 to 180 degrees from horizontal. /// </summary> /// <param name="img">CImg src image</param> /// <param name="numberOfLines">int number of angled lines to consider.</param> /// <returns>Projections struct</returns> internal static Projections FindRadonProjections(FloatImage img, int numberOfLines) { int width = img.Width; int height = img.Height; int D = (width > height) ? width : height; float x_center = width / 2f; float y_center = height / 2f; int x_off = (int)MathF.Floor(x_center + GetRoundingFactor(x_center)); int y_off = (int)MathF.Floor(y_center + GetRoundingFactor(y_center)); Projections projs = new Projections(numberOfLines, D, numberOfLines); FloatImage radonMap = projs.Region; int[] ppl = projs.PixelsPerLine; for (int k = 0; k < numberOfLines / 4 + 1; k++) { float theta = k * MathF.PI / numberOfLines; float alpha = MathF.Tan(theta); for (int x = 0; x < D; x++) { float y = alpha * (x - x_off); int yd = (int)MathF.Floor(y + GetRoundingFactor(y)); if ((yd + y_off >= 0) && (yd + y_off < height) && (x < width)) { radonMap[k, x] = img[x, yd + y_off]; ppl[k] += 1; } if ((yd + x_off >= 0) && (yd + x_off < width) && (k != numberOfLines / 4) && (x < height)) { radonMap[numberOfLines / 2 - k, x] = img[yd + x_off, x]; ppl[numberOfLines / 2 - k] += 1; } } } int j = 0; for (int k = 3 * numberOfLines / 4; k < numberOfLines; k++) { float theta = k * MathF.PI / numberOfLines; float alpha = MathF.Tan(theta); for (int x = 0; x < D; x++) { float y = alpha * (x - x_off); int yd = (int)MathF.Floor(y + GetRoundingFactor(y)); if ((yd + y_off >= 0) && (yd + y_off < height) && (x < width)) { radonMap[k, x] = img[x, yd + y_off]; ppl[k] += 1; } if ((y_off - yd >= 0) && (y_off - yd < width) && (2 * y_off - x >= 0) && (2 * y_off - x < height) && (k != 3 * numberOfLines / 4)) { radonMap[k - j, x] = img[-yd + y_off, -(x - y_off) + y_off]; ppl[k - j] += 1; } } j += 2; } return(projs); }
private static byte ToByte(this float f) => (byte)Math.Max(byte.MinValue, Math.Min(MathF.Round(f), byte.MaxValue));