예제 #1
0
        private void screenRecognition()
        {
#if FALSE // useful for debugging rotation
            List <double> rotateBy = new List <double> {
                Math.PI / 4, Math.PI / 2, Math.PI
            };
            foreach (double theta in rotateBy)
            {
                BitmapSymbol debug = (BitmapSymbol)Clone();
                debug.Rotate(theta);
            }
#endif
            List <SymbolRank> topPolar = _results.BestN(ResultType.POLAR, NUM_TOP_POLAR_TO_KEEP);
            foreach (SymbolRank sr in topPolar)
            {
#if JESSI
                Console.WriteLine("Doing screen recognition for template " + sr.SymbolName);
#endif
                // clone the BitmapSymbol so that we can rotate it without losing information
                BitmapSymbol clone = (BitmapSymbol)Clone();
                clone.Rotate(-sr.BestOrientation);

                // calculate the data using the rotated clone, but store the output in this symbol's results.
                _results.Add(ResultType.PARTIAL_HAUSDORFF, clone.Partial_Hausdorff(sr.Symbol));
                _results.Add(ResultType.MOD_HAUSDORFF, clone.Modified_Hausdorff(sr.Symbol));
                _results.Add(ResultType.TANIMOTO, clone.Tanimoto_Distance(sr.Symbol));
                _results.Add(ResultType.YULE, clone.Yule_Distance(sr.Symbol));
            }
        }
예제 #2
0
        public object Clone()
        {
            BitmapSymbol symbol = (BitmapSymbol)this.MemberwiseClone();

            //symbol._results = (RecoResult)this._results.Clone();
            symbol._sMesh  = (Matrix)this._sMesh.Clone();
            symbol._sDTM   = (Matrix)this._sDTM.Clone();
            symbol._pMesh  = (Matrix)this._pMesh.Clone();
            symbol._pDTM   = (Matrix)this._pDTM.Clone();
            symbol._points = (BitmapPoints)this._points.Clone();

            symbol._polarCoords = new List <Coord>();
            foreach (Coord cd in this._polarCoords)
            {
                symbol._polarCoords.Add((Coord)cd.Clone());
            }

            symbol._screenCoords = new List <Coord>();
            foreach (Coord cd in this._screenCoords)
            {
                symbol._screenCoords.Add((Coord)cd.Clone());
            }

            return(symbol);
        }
예제 #3
0
        /// <summary>
        /// Calculates the distance from every point in one BitmapSymbol to the closest point
        /// in another.
        /// </summary>
        private static List <double> directedScreenDistance(BitmapSymbol from, BitmapSymbol to)
        {
            List <double> dist = new List <double>();

            foreach (Coord pt in from._screenCoords)
            {
                dist.Add(to._sDTM[(int)pt.Y, (int)pt.X]);
            }
            return(dist);
        }
예제 #4
0
        public SymbolRank getSR(ResultType type, BitmapSymbol bs)
        {
            foreach (SymbolRank sr in _results[type])
            {
                if (sr.Symbol.ID == bs.ID)
                {
                    return(sr);
                }
            }

            throw new Exception("RecoResult could not find the specified BitmapSymbol in the list of "
                                + type.ToString() + " results.");
        }
예제 #5
0
        /// <summary>
        /// uses polar coordinate matching to find the orientation of a BitmapSymbol
        /// that makes it best match the given BitmapSymbol template.
        /// </summary>
        /// <param name="defn"></param>
        /// <returns></returns>
        public double bestOrientation(BitmapSymbol defn)
        {
            if (defn == null)
            {
                return(0.0);
            }

#if JESSI
            Console.WriteLine("Using template " + defn._name + " to orient shape.");
#endif

            return(Polar_Mod_Hausdorff(defn).BestOrientation);
        }
예제 #6
0
        /// <summary>
        /// Calculates the Yule Coefficient (or the coefficient of colligation) for the
        /// the calling BitmapSymbol and the BitmapSymbol S
        /// </summary>
        private SymbolRank Yule_Distance(BitmapSymbol S)
        {
            int A_count, B_count, black_overlap, white_overlap;

            Black_White(this, S, out A_count, out B_count, out black_overlap, out white_overlap);

            double lonely_A    = A_count - black_overlap; // the number of black pixels in A that do not have a match in B
            double lonely_B    = B_count - black_overlap;
            double overlapping = (double)(black_overlap * white_overlap);
            double numerator   = overlapping - lonely_A * lonely_B;
            double denominator = overlapping + lonely_A * lonely_B;

            return(new SymbolRank(numerator / denominator, S));
        }
예제 #7
0
        /// <summary>
        /// Calculates information about the number of black pixels and how they overlap.
        /// </summary>
        /// <param name="A">A BitmapSymbol</param>
        /// <param name="B">Another BitmapSymbol</param>
        /// <param name="A_count">The number of black pixels in A</param>
        /// <param name="B_count">The number of black pixels in B</param>
        /// <param name="black_overlap">The number of black pixels that "overlap" in the two</param>
        /// <param name="white_overlap">The number of white pixels in A that don't "overlap"
        ///     with a black pixel in B</param>
        private static void Black_White(BitmapSymbol A, BitmapSymbol B,
                                        out int A_count, out int B_count,
                                        out int black_overlap, out int white_overlap)
        {
            // we consider pixels to be overlapping if they are separated
            // by less than a certain fraction of the image's diagonal length
            double E = OVERLAP_THRESHOLD * Math.Sqrt(Math.Pow(GRID_X_SIZE, 2.0) + Math.Pow(GRID_Y_SIZE, 2.0));

            A_count = B_count = black_overlap = white_overlap = 0; // initialize them all to zero!

            for (int i = 0; i < A._sDTM.ColumnCount; i++)
            {
                for (int j = 0; j < A._sDTM.RowCount; j++)
                {
                    if (A._sDTM[i, j] == 0.0)
                    {
                        A_count++;
                    }

                    if (B._sDTM[i, j] == 0.0)
                    {
                        B_count++;
                    }

                    if ((A._sDTM[i, j] == 0.0 && B._sDTM[i, j] < E))
                    {
                        black_overlap++;
                    }

                    if (A._sDTM[i, j] > 0.0 && B._sDTM[i, j] > 0.0)
                    {
                        white_overlap++;
                    }
                }
            }


            // We need to do some sanity checking. Because pixels are considered to
            // overlap if they are separated by a certain distance, black_overlap
            // might be as large as max(A_count, B_count). However, we would not
            // expect it to be larger than min(A_count, B_count). The same goes
            // for the white overlap. NOTE: This particular fine point is not
            // mentioned in the paper as far as we can tell, but they do state that
            // the tanimoto coefficient is supposed to be in the range [0, 1], so
            // I feel justified in this.
            int area = GRID_X_SIZE * GRID_Y_SIZE;

            black_overlap = Math.Min(Math.Min(A_count, B_count), black_overlap);
            white_overlap = Math.Min(Math.Min(area - A_count, area - B_count), white_overlap);
        }
예제 #8
0
        /// <summary>
        /// Calculates the Tanimoto Similarity Coefficient for the calling BitmapSymbol
        /// and the BitmapSymbol S.
        /// </summary>
        private SymbolRank Tanimoto_Distance(BitmapSymbol S)
        {
            int A_count, B_count, black_overlap, white_overlap;

            Black_White(this, S, out A_count, out B_count, out black_overlap, out white_overlap);

            double Tanim      = (double)black_overlap / (double)(A_count + B_count - black_overlap);
            double TanimComp  = (double)white_overlap / (double)(A_count + B_count - 2 * black_overlap + white_overlap);
            double image_size = (double)_sDTM.ColumnDimension * _sDTM.RowDimension;
            double p          = (double)(A_count + B_count) / (2.0 * image_size);
            // this has magic numbers. Sorry. We didn't make them up. See the image recognition paper. (Link at top)
            double alpha    = 0.75 - 0.25 * p;
            double distance = 1.0 - (alpha * Tanim + (1.0 - alpha) * TanimComp);

            // return the Tanimoto Similarity Coefficient
            return(new SymbolRank(distance, S));
        }
예제 #9
0
        private RecoResult screenRecognition(List <SymbolRank> topPolar)
        {
            RecoResult screenResults = new RecoResult();

            foreach (SymbolRank sr in topPolar)
            {
#if JESSI
                Console.WriteLine();
                Console.WriteLine("Doing screen recognition for template " + sr.SymbolName);
#endif
                // clone the BitmapSymbol so that we can rotate it without losing information
                BitmapSymbol clone = (BitmapSymbol)Clone();
                clone.Rotate(-sr.BestOrientation);

                // calculate the data using the rotated clone, but store the output in this symbol's results.
                screenResults.Add(ResultType.PARTIAL_HAUSDORFF, clone.Partial_Hausdorff(sr.Symbol));
                screenResults.Add(ResultType.MOD_HAUSDORFF, clone.Modified_Hausdorff(sr.Symbol));
                screenResults.Add(ResultType.TANIMOTO, clone.Tanimoto_Distance(sr.Symbol));
                screenResults.Add(ResultType.YULE, clone.Yule_Distance(sr.Symbol));
            }
            return(screenResults);
        }
예제 #10
0
        /// <summary>
        /// Calculates the Hausdorff distance between the calling BitmapSymbol and the
        /// BitmapSymbol S.
        /// </summary>
        /// <returns>The maximum of the two partial Hausdorff distances.</returns>
        private SymbolRank Partial_Hausdorff(BitmapSymbol S)
        {
            List <double> distancesAB = directedScreenDistance(this, S);
            List <double> distancesBA = directedScreenDistance(S, this);

            distancesAB.Sort();
            distancesBA.Sort();

            double hAB = double.PositiveInfinity;
            double hBA = double.PositiveInfinity;

            if (distancesAB.Count != 0)
            {
                hAB = distancesAB[(int)Math.Floor(((distancesAB.Count - 1) * HAUSDORFF_QUANTILE))];
            }
            if (distancesBA.Count != 0)
            {
                hBA = distancesBA[(int)Math.Floor(((distancesBA.Count - 1) * HAUSDORFF_QUANTILE))];
            }

            return(new SymbolRank(Math.Max(hAB, hBA), S));
        }
예제 #11
0
        /// <summary>
        /// Calculates the average directed distance between the calling BitmapSymbol
        /// and the BitmapSymbol S.
        /// </summary>
        /// <returns>The average distance between the two sets of points.</returns>
        private SymbolRank Modified_Hausdorff(BitmapSymbol S)
        {
            List <double> distancesAB = directedScreenDistance(this, S);
            List <double> distancesBA = directedScreenDistance(S, this);

            double AB = 0.0;
            double BA = 0.0;

            foreach (double dist in distancesAB)
            {
                AB += dist;
            }

            foreach (double dist in distancesBA)
            {
                BA += dist;
            }

            AB /= this._screenCoords.Count;
            BA /= S._screenCoords.Count;

            return(new SymbolRank(Math.Max(AB, BA), S));
        }
예제 #12
0
        /// <summary>
        /// Calculates information about the number of black pixels and how they overlap.
        /// </summary>
        /// <param name="A">A BitmapSymbol</param>
        /// <param name="B">Another BitmapSymbol</param>
        /// <param name="A_count">The number of black pixels in A</param>
        /// <param name="B_count">The number of black pixels in B</param>
        /// <param name="black_overlap">The number of black pixels that "overlap" in the two</param>
        /// <param name="white_overlap">The number of white pixels in A that don't "overlap"
        ///     with a black pixel in B</param>
        private static void Black_White(BitmapSymbol A, BitmapSymbol B,
                                        out int A_count, out int B_count,
                                        out int black_overlap, out int white_overlap)
        {
            // we consider pixels to be overlapping if they are separated
            // by less than a certain fraction of the image's diagonal length
            double E = OVERLAP_THRESHOLD * Math.Sqrt(Math.Pow((double)GRID_X_SIZE, 2.0) + Math.Pow((double)GRID_Y_SIZE, 2.0));

            A_count = B_count = black_overlap = white_overlap = 0; // initialize them all to zero!

            for (int i = 0; i < A._sDTM.ColumnDimension; i++)
            {
                for (int j = 0; j < A._sDTM.RowDimension; j++)
                {
                    if (A._sDTM.GetElement(i, j) == 0.0)
                    {
                        A_count++;
                    }

                    if (B._sDTM.GetElement(i, j) == 0.0)
                    {
                        B_count++;
                    }

                    if ((A._sDTM.GetElement(i, j) == 0.0 && B._sDTM.GetElement(i, j) < E))
                    {
                        black_overlap++;
                    }

                    if (A._sDTM.GetElement(i, j) > 0.0 && B._sDTM.GetElement(i, j) > 0.0)
                    {
                        white_overlap++;
                    }
                }
            }
        }
예제 #13
0
        /// <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 JESSI
            Console.WriteLine("Your gate: ");
            _points.printPrettyMatrix(_pMesh, GRID_X_SIZE, GRID_Y_SIZE);
            //Console.Write(_pMesh.ToString());
            Console.WriteLine();

            Console.WriteLine("Your template: ");
            //Console.Write(S._pMesh.ToString());
            _points.printPrettyMatrix(S._pMesh, GRID_X_SIZE, GRID_Y_SIZE);
            Console.WriteLine();
#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[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[y_ind, x_ind] * weight;
            }

            minA2B /= (double)A.Count;
            minB2A /= (double)B.Count;

#if JESSI
            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));
        }
예제 #14
0
 public SymbolRank(double distance, BitmapSymbol symbol, double bestOrientation)
 {
     _dist       = distance;
     _symbol     = symbol;
     _bestOrient = bestOrientation;
 }
예제 #15
0
 public SymbolRank(double distance, BitmapSymbol symbol)
 {
     _dist       = distance;
     _symbol     = symbol;
     _bestOrient = 0.0;
 }
예제 #16
0
 public SymbolRank()
 {
     _dist       = double.MaxValue;
     _symbol     = new BitmapSymbol();
     _bestOrient = 0.0;
 }