public GeneralMatrix QuantizeScreen(int grid_x, int grid_y) { // create a general matrix full of 0s GeneralMatrix mesh = new GeneralMatrix(grid_x, grid_y, 0.0); // Find the bounding box of the points. System.Drawing.Rectangle bBox = BoundingBox(); if (_points.Count == 0) { return(mesh); } // find the step we want // Note: this is an intentional deviation from the original paper. // We do not maintain the original aspect ratio of the shape. double stepX = bBox.Width / (double)(grid_x - 1); double stepY = bBox.Height / (double)(grid_y - 1); // find the center of the image double cx = (double)(bBox.Left + bBox.Right) / 2.0; double cy = (double)(bBox.Top + bBox.Bottom) / 2.0; foreach (GenericPoint pt in _points) { // normalize the point's coordinates int x_index = (int)Math.Floor(((pt.X - cx) / stepX) + grid_x / 2); int y_index = (int)Math.Floor(((pt.Y - cy) / stepY) + grid_y / 2); if (x_index < grid_x && y_index < grid_y) { mesh.SetElement(y_index, x_index, 1.0); } } #if JESSI Console.WriteLine("Quantized screen"); Console.Write(mesh.ToString()); #endif return(mesh); }
/// <summary> /// Calculates and saves the distance transform map for the polar coordinates. /// Uses _pMesh and saves to _pDTM. /// A distance transform map is a matrix in which every entry represents the /// distance from that point to the nearest point with ink. /// </summary> private void PolarDistanceTransform() { List <Coord> indices = IndexList(_pMesh); for (int i = 0; i < GRID_Y_SIZE; i++) { for (int j = 0; j < GRID_X_SIZE; j++) { Coord cp = new Coord(j, i); double mindist = double.PositiveInfinity; foreach (Coord pt in indices) { // the straight distance between current point and current index double dx = Math.Abs(cp.X - pt.X); double dy = Math.Abs(cp.Y - pt.Y); double straightDist = Math.Sqrt(dx * dx + dy * dy); dx = (double)GRID_X_SIZE - dx; double wrapDist = Math.Sqrt(dx * dx + dy * dy); double distan = Math.Min(straightDist, wrapDist); if (distan < mindist) { mindist = distan; } } _pDTM.SetElement(i, j, mindist); } } #if FALSE Console.WriteLine("Your polar distance transform map:"); Console.Write(_pDTM.ToString()) #endif }
/// <summary> /// Calculates the dissimilarity between the calling BitmapSymbol and /// BitmapSymbol S in terms of their polar coordinates using the /// modified Hausdorff distance (aka the mean distance). /// </summary> private SymbolRank Polar_Mod_Hausdorff(BitmapSymbol S) { int lower_rot_index = (int)Math.Floor(ALLOWED_ROTATION_AMOUNT * GRID_X_SIZE / 720.0); int upper_rot_index = GRID_X_SIZE - lower_rot_index; //trick List <Coord> A = new List <Coord>(_polarCoords); List <Coord> B = new List <Coord>(S._polarCoords); if (A.Count == 0 || B.Count == 0) { return(new SymbolRank()); } double minA2B = double.PositiveInfinity; double distan = 0.0; int besti = 0; // the best translation in theta #if FALSE Console.WriteLine("Your gate: "); Console.Write(_pMesh.ToString()); Console.WriteLine("Your template: "); Console.Write(S._pMesh.ToString()); #endif // rotations in screen coordinates are the same as translations in polar coords // we have polar coords, so translate in X (theta) until you get the best orientation for (int i = 0; i < GRID_X_SIZE; i++) { if (i > lower_rot_index && i < upper_rot_index) { continue; } distan = 0.0; // find the distance from each point in A to the nearest point in B using B_DTM foreach (Coord a in A) { int y_ind = (int)a.Y; int x_ind = (int)a.X - i; // translate by i on the theta (X) axis if (x_ind < 0) { x_ind += GRID_X_SIZE; // make sure we're still on the graph } //putting less weight on points that have small rel dist - y double weight = Math.Pow((double)y_ind, POLAR_WEIGHT_DECAY_RATE); distan += S._pDTM.GetElement(y_ind, x_ind) * weight; } // this is the best orientation if the total distance is the smallest if (distan < minA2B) { minA2B = distan; besti = i; } } // set the best rotation angle (in radians) double bestRotAngle = besti * 2.0 * Math.PI / (double)GRID_X_SIZE; // we've already found the best orientation // find the distance from each point in B to the nearest point in A using A_DTM double minB2A = 0.0; foreach (Coord b in B) { int y_ind = (int)b.Y; int x_ind = (int)b.X - besti; // slide B back by besti if (x_ind < 0) { x_ind += GRID_X_SIZE; } double weight = Math.Pow((double)y_ind, POLAR_WEIGHT_DECAY_RATE); minB2A += _pDTM.GetElement(y_ind, x_ind) * weight; } minA2B /= (double)A.Count; minB2A /= (double)B.Count; #if FALSE Console.WriteLine("Finding best orientation match of your gate and " + S._name); Console.WriteLine("The best translation is " + besti + " which is " + bestRotAngle + " radians."); Console.WriteLine("A2B distance: " + minA2B + ", B2A distance: " + minB2A); string templateName = S._name; #endif return(new SymbolRank(Math.Max(minA2B, minB2A), S, bestRotAngle)); }