/// <summary>
        /// Given a Window, this method will perform a full scan of the window using both UIAutomation and VisualRecognition
        /// of the UI-Window. This method may take some time to be executed.
        /// </summary>
        /// <param name="w"></param>
        /// <returns></returns>
        public CandidateSet Rank(IRankingPolicy policy, Window w)
        {
            CandidateSet res = new CandidateSet();

            try
            {
                // Scan all elements with UI Atuomation. Those are the "preferred ones"
                ScanWithUIAutomation(ref res, w, policy);

                using (Bitmap bitmap = w.GetWindowsScreenshot())
                {
                    if (bitmap == null)
                    {
                        return(res);
                    }
                    // Scan with Visual recognition.
                    ScanWithVisualRecognition(ref res, bitmap, false, _min_width, _min_height, w, policy);
                    ScanWithVisualRecognition(ref res, bitmap, true, _min_width, _min_height, w, policy);

                    // Calculate an hash starting from the bitmap and save it to the candidate set.
                    res.Hash = CalculateHash(bitmap);
                }
            }
            catch (Exception e) {
                // Many things may go wrong here. Assume this will fail.
                res.Clear();
                res.Hash = null;
            }

            return(res);
        }
        private void ScanWithUIAutomation(ref CandidateSet res, Window w, IRankingPolicy policy)
        {
            AutomationElementCollection elements = AutomationElement.FromHandle(w.Handle).FindAll(TreeScope.Descendants, _cond);

            foreach (var el in elements)
            {
                var ae        = (el as AutomationElement).Current;
                var windowLoc = w.WindowLocation;
                if (double.IsInfinity(ae.BoundingRectangle.Top) || double.IsInfinity(ae.BoundingRectangle.Left) || double.IsInfinity(ae.BoundingRectangle.Bottom) || double.IsInfinity(ae.BoundingRectangle.Right))
                {
                    continue;
                }

                UIControlCandidate u = new UIControlCandidate();
                var r = ae.BoundingRectangle;
                u.PositionScreenRelative = new Rectangle((int)r.X, (int)r.Y, (int)r.Width, (int)r.Height);
                u.PositionWindowRelative = new Rectangle((int)r.X - windowLoc.X, (int)r.Y - windowLoc.Y, (int)r.Width, (int)r.Height);
                u.Text           = ae.Name;
                u.IsEnabled      = ae.IsEnabled;
                u.AutoElementRef = el as AutomationElement;
                u.Score          = policy.RankElement(u);
                res.Add(u);
            }
        }
        /// <summary>
        /// Given the Window UI Screenshot, tries to detect all the buttons in it and returns all of them.
        /// </summary>
        /// <param name="res">Where to put candidate controls</param>
        /// <param name="bitmap">Bitmap containing the pixels of the UI to analyze</param>
        /// <param name="shouldInvert">If true, the bitmap will be inverted before analysis</param>
        /// <param name="minWidth">Minimum width of patterns to recognize</param>
        /// <param name="minHeight">Minimum height of patterns to recognize</param>
        /// <returns>void</returns>
        private void ScanWithVisualRecognition(ref CandidateSet res, Bitmap original, bool shouldInvert, int minWidth, int minHeight, Window w, IRankingPolicy policy)
        {
            // Setup the Blob counter
            BlobCounter blobCounter = new BlobCounter();

            blobCounter.BackgroundThreshold  = Color.FromArgb(10, 10, 10);
            blobCounter.FilterBlobs          = true;
            blobCounter.CoupledSizeFiltering = false;
            blobCounter.MinHeight            = minHeight;
            blobCounter.MinWidth             = minWidth;

            List <Blob> blobs = new List <Blob>();

            // Button scanning
            // Apply the grayscale. This is needed for AForge's filters
            using (Bitmap grey_scaled = Grayscale.CommonAlgorithms.BT709.Apply(original))
            {
                // Invert the image if requested
                if (shouldInvert)
                {
                    Invert invert = new Invert();
                    invert.ApplyInPlace(grey_scaled);
                }

                //grey_scaled.Save("C:\\users\\alberto geniola\\desktop\\dbg\\gray_scaled_" + toinvert + ".bmp");

                using (Bitmap t1 = new Threshold(64).Apply(grey_scaled))
                {
                    using (var tmp = new Bitmap(t1.Width, t1.Height))
                    {
                        using (Graphics g = Graphics.FromImage(tmp))
                        {
                            g.DrawImage(t1, 0, 0);
                        }

                        // The blob counter will analyze the bitmap looking for shapes
                        blobCounter.ProcessImage(tmp);
                        var tmparr = blobCounter.GetObjectsInformation();
                        blobs.AddRange(tmparr);
                    }
                }

                using (Bitmap t2 = new SISThreshold().Apply(grey_scaled))
                {
                    using (var tmp = new Bitmap(t2.Width, t2.Height))
                    {
                        using (Graphics g = Graphics.FromImage(tmp))
                        {
                            g.DrawImage(t2, 0, 0);
                        }
                        //tmp.Save("C:\\users\\alberto geniola\\desktop\\dbg\\t2_" + toinvert + ".bmp");
                        // The blob counter will analyze the bitmap looking for shapes
                        blobCounter.ProcessImage(tmp);
                        var tmparr = blobCounter.GetObjectsInformation();
                        blobs.AddRange(tmparr);
                    }
                }
            }

            // Let's analyze every single shape
            for (int i = 0, n = blobs.Count; i < n; i++)
            {
                List <IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]);
                if (edgePoints.Count > 1)
                {
                    IntPoint p0, p1;
                    PointsCloud.GetBoundingRectangle(edgePoints, out p0, out p1);
                    var r = new Rectangle(p0.X, p0.Y, p1.X - p0.X, p1.Y - p0.Y);

                    // Skip any shape representing the border of the whole window ( +10px padding)
                    if (r.Width >= (original.Width - 10))
                    {
                        continue;
                    }

                    // This is most-likely a button!
                    // Crop the image and pass it to the OCR engine for text recognition
                    using (Bitmap button = new Bitmap(r.Width, r.Height))
                    {
                        // Scan the original shape
                        String txt = null;
                        using (var g1 = Graphics.FromImage(button))
                        {
                            g1.DrawImage(original, 0, 0, r, GraphicsUnit.Pixel);
                        }

                        // Process OCR on that image
                        txt = scanButton(button);

                        if (String.IsNullOrEmpty(txt))
                        {
                            using (Bitmap tmp = Grayscale.CommonAlgorithms.BT709.Apply(button))
                            {
                                if (shouldInvert)
                                {
                                    new Invert().ApplyInPlace(tmp);
                                }

                                new SISThreshold().ApplyInPlace(tmp);
                                txt = scanButton(tmp);
                            }
                        }

                        // If still nothing is found, repeat the analysis with the second version of the filter
                        if (String.IsNullOrEmpty(txt))
                        {
                            using (Bitmap tmp = Grayscale.CommonAlgorithms.BT709.Apply(button))
                            {
                                if (shouldInvert)
                                {
                                    new Invert().ApplyInPlace(tmp);
                                }
                                new Threshold(64).ApplyInPlace(tmp);
                                txt = scanButton(tmp);
                            }
                        }

                        // At this point we should have a result. Add it to list if it does not overlap any UIAutomated element
                        UIControlCandidate t = new UIControlCandidate();
                        t.PositionWindowRelative = r;
                        var winLoc = w.WindowLocation;
                        t.PositionScreenRelative = new Rectangle(r.X + winLoc.X, r.Y + winLoc.Y, r.Width, r.Height);
                        t.Text  = txt;
                        t.Score = policy.RankElement(t);

                        // If the item falls into the same area of a UI element, ignore it.
                        bool overlaps = false;
                        foreach (var el in res)
                        {
                            if (el.AutoElementRef != null && el.PositionScreenRelative.IntersectsWith(t.PositionScreenRelative))
                            {
                                overlaps = true;
                                break;
                            }
                        }
                        if (!overlaps)
                        {
                            res.Add(t);
                        }
                    }
                }
            }
        }