private float DetectTemplate(ScanAreaImageDictionary lookup, string key)
        {
            if (!lookup.ContainsKey(key))
            {
                Log.Error("No scan data found for requested template: {0}", key);
                return(-1);
            }

            var      template = lookup[key];
            var      rect     = new Rectangle();
            int      theResolution;
            Bitmap   matchhash;
            ScanArea area = null;

            if (template.ContainsKey(this.lastResolution))
            {
                area = template[this.lastResolution].Item2;
                // rect = new Rectangle(area.X, area.Y, area.Width, area.Height);
                matchhash     = template[this.lastResolution].Item1;
                theResolution = this.lastResolution;
            }
            else if (template.ContainsKey(this.BaseResolution))
            {
                area = template[this.BaseResolution].Item2;
                // rect = new Rectangle(area.X, area.Y, area.Width, area.Height);
                matchhash     = template[this.BaseResolution].Item1;
                theResolution = this.BaseResolution;
            }
            else
            {
                Log.Error("No scan data found for requested template: " + key);
                return(-1);
            }
            var source = this.image;

            rect = new Rectangle(area.X, area.Y, area.Width, area.Height);
            if (area.BaseResolution > 0)
            {
                // theResolution = area.BaseResolution;
            }
            var templatesize = new Size(matchhash.Width, matchhash.Height);
            var roiRect      = ResolutionHelper.CorrectRectangle(source.Size, rect, theResolution);

            //var roiRect = ResolutionHelper.CorrectPoints(source.Size, rect, theResolution);
            templatesize = ResolutionHelper.CorrectSize(source.Size, templatesize, area.BaseResolution > 0 ? area.BaseResolution : theResolution);
            roiRect.Inflate(5, 5);
            // roiRect.X -= 5;
            // roiRect.Y -= 5;
            using (var roi = source.Clone(roiRect, PixelFormat.Format24bppRgb))
            {
                var newhash = new Bitmap(templatesize.Width, templatesize.Height, PixelFormat.Format24bppRgb);
                var graph   = Graphics.FromImage(newhash);
                graph.InterpolationMode = InterpolationMode.HighQualityBicubic;
                graph.DrawImage(matchhash, 0, 0, templatesize.Width, templatesize.Height);
                var ismatch = templateMatcher.IsMatch(roi, newhash);
                graph.Dispose();
                newhash.Dispose();
                return(ismatch);
            }
        }
        private void ScanDeckScreenshot()
        {
            if (deckScreenshotRequestedCanceled)
            {
                Log.Debug("Deck Screenshot Requested Canceled.");
                if (cancelDeckScreenshot != null)
                {
                    cancelDeckScreenshot.Cancel();
                }
                deckScreenshotRequestedCanceled = false;
                deckScreenshotRequested         = false;
                takeDeckScreenshot = false;
            }

            if (deckScreenshotRequested)
            {
                var detect1 = Detect(this.areas, "deckscreen");
                var detect2 = Detect(this.areas, "deckscreen2");
                if (detect1 && detect2)
                {
                    this.deckScreenshotRequested = false;
                    if (cancelDeckScreenshot != null)
                    {
                        cancelDeckScreenshot.Cancel();
                        cancelDeckScreenshot.Dispose();
                    }
                    cancelDeckScreenshot = new CancellationTokenSource();
                    Log.Debug("Deck Screenshot Requested. Found!");

                    Task.Delay(500, this.cancelDeckScreenshot.Token).ContinueWith(
                        (t) =>
                    {
                        if (t.IsCanceled)
                        {
                            return;
                        }
                        takeDeckScreenshot = true;
                    });
                }
                else
                {
                    Log.Debug("Deck Screenshot Requested. Not found. deckscreen1: {0}, deckscreen2: {1}", detect1.Distance, detect2.Distance);
                }
            }

            if (takeDeckScreenshot)
            {
                takeDeckScreenshot = false;
                var deckRect = this.areas["deckarea_cards"][BaseResolution].Rect;
                deckRect = ResolutionHelper.CorrectRectangle(this.image.Size, deckRect, BaseResolution);
                var deck = this.image.Clone(deckRect, this.image.PixelFormat);
                Log.Debug("Deck Screenshot Requested. Sending screenshot...");
                events.PublishOnBackgroundThread(new DeckScreenshotTaken(deck));
            }
        }
 private void ScanArenaDeckScreenshot()
 {
     if (arenadeckScreenshotRequested && gameMode == GameMode.Arena)
     {
         arenadeckScreenshotRequested = false;
         var deckRect = this.areas["deckarea_arena"][BaseResolution].Rect;
         deckRect = ResolutionHelper.CorrectRectangle(this.image.Size, deckRect, BaseResolution);
         var deck = this.image.Clone(deckRect, this.image.PixelFormat);
         Log.Debug("Arena deck Screenshot Requested. Sending screenshot...");
         events.PublishOnBackgroundThread(new ArenaDeckScreenshotTaken(deck));
     }
 }
        //private string DetectBest(ScanAreaDictionary lookup, IDictionary<int, Tuple<ulong, Rectangle>> useArea, string debugkey)
        //{
        //    var hashes = new List<ulong>();
        //    var keys = new List<string>();

        //    var rect = new Rectangle();
        //    int theResolution;
        //    foreach (var key in lookup.Keys)
        //    {
        //        var template = lookup[key];
        //        ulong matchhash;
        //        if (template.ContainsKey(this.lastResolution))
        //        {
        //            matchhash = template[this.lastResolution].Hash;
        //        }
        //        else if (template.ContainsKey(this.BaseResolution))
        //        {
        //            matchhash = template[this.BaseResolution].Hash;
        //        }
        //        else
        //        {
        //            Log.Error("No scan data found for requested template: " + debugkey);
        //            return null;
        //        }
        //        hashes.Add(matchhash);
        //        keys.Add(key);
        //    }

        //    if (useArea.ContainsKey(this.lastResolution))
        //    {
        //        rect = useArea[this.lastResolution].Rect;
        //        theResolution = this.lastResolution;
        //    }
        //    else if (useArea.ContainsKey(this.BaseResolution))
        //    {
        //        rect = useArea[this.BaseResolution].Rect;
        //        theResolution = this.BaseResolution;
        //    }
        //    else
        //    {
        //        Log.Error("No scan data found for requested template: " + debugkey);
        //        return null;
        //    }

        //    var source = this.image;
        //    using (var roi = source.Clone(ResolutionHelper.CorrectRectangle(source.Size, rect, theResolution), PixelFormat.Format32bppRgb))
        //    {
        //        var hash = this.imageHasher.Create(roi);
        //        var best = PerceptualHash.FindBest(hash, hashes);
        //        if (best.Distance <= ThreshHold)
        //        {
        //            Log.Diag("Detected best hash: '{0}' Distance: {1}", debugkey, best.Distance);
        //            return keys[best.Index];
        //        }
        //    }

        //    return null;
        //}

        private string DetectBest(ScanAreaDictionary lookup, string debugkey, int?threshold = null)
        {
            threshold = threshold ?? ThreshHold;
            var hashes = new List <ulong>();
            var keys   = new List <string>();

            var rect          = new Rectangle();
            int theResolution = BaseResolution;

            foreach (var key in lookup.Keys)
            {
                var   template = lookup[key];
                ulong matchhash;
                if (template.ContainsKey(this.lastResolution))
                {
                    matchhash     = template[this.lastResolution].Hash;
                    rect          = template[this.lastResolution].Rect;
                    theResolution = this.lastResolution;
                }
                else if (template.ContainsKey(this.BaseResolution))
                {
                    matchhash     = template[this.BaseResolution].Hash;
                    rect          = template[this.BaseResolution].Rect;
                    theResolution = this.BaseResolution;
                }
                else
                {
                    Log.Error("No scan data found for requested template: " + debugkey);
                    return(null);
                }
                hashes.Add(matchhash);
                keys.Add(key);
            }

            var source = this.image;

            using (var roi = source.Lock(ResolutionHelper.CorrectRectangle(source.Size, rect, theResolution), PixelFormat.Format32bppRgb))
            {
                var hash = this.imageHasher.Create(roi.Data);
                var best = PerceptualHash.FindBest(hash, hashes);
                TraceLog.Log("Detected best hash: '{0}' Distance: {1}", debugkey, best.Distance);
                if (best.Distance <= threshold)
                {
                    return(keys[best.Index]);
                }
            }

            return(null);
        }
        /// <summary>The detect.</summary>
        /// <param name="lookup">The lookup.</param>
        /// <param name="key">The key.</param>
        /// <param name="useArea"></param>
        /// <param name="i"></param>
        /// <returns>The <see cref="bool"/>.</returns>
        private DetectionResult Detect(ScanAreaDictionary lookup, string key, IDictionary <int, ScanArea> useArea = null, int threshold = -1)
        {
            threshold = threshold >= 0 ? threshold : ThreshHold;
            if (!lookup.ContainsKey(key))
            {
                Log.Error("No scan data found for requested template: {0}", key);
                return(new DetectionResult(false, -1));
            }

            var template = lookup[key];
            // var rect = new Rectangle();
            int theResolution;
            // ulong matchhash;
            ScanArea area = null;

            if (template.ContainsKey(this.lastResolution))
            {
                // rect = template[this.lastResolution].Rect;
                // matchhash = template[this.lastResolution].Hash;
                area          = template[this.lastResolution];
                theResolution = this.lastResolution;
            }
            else if (template.ContainsKey(this.BaseResolution))
            {
                // rect = template[this.BaseResolution].Rect;
                // matchhash = template[this.BaseResolution].Hash;
                area          = template[this.BaseResolution];
                theResolution = this.BaseResolution;
            }
            else
            {
                Log.Error("No scan data found for requested template: " + key);
                return(new DetectionResult(false, -1));
            }
            if (useArea != null)
            {
                if (useArea.ContainsKey(this.lastResolution))
                {
                    // rect = useArea[this.lastResolution].Rect;
                    area          = useArea[this.lastResolution];
                    theResolution = this.lastResolution;
                }
                else if (useArea.ContainsKey(this.BaseResolution))
                {
                    // rect = useArea[this.BaseResolution].Rect;
                    area          = useArea[this.BaseResolution];
                    theResolution = this.BaseResolution;
                }
                else
                {
                    Log.Error("No scan data found for requested template: " + key);
                    return(new DetectionResult(false, -1));
                }
            }
            var             source   = this.image;
            int             distance = -1;
            DetectionResult result   = new DetectionResult();

            using (var roi = source.Lock(ResolutionHelper.CorrectRectangle(source.Size, area.Rect, theResolution), source.PixelFormat))
            {
                // var roi = source.Clone(ResolutionHelper.CorrectRectangle(source.Size, area.Rect, theResolution), source.PixelFormat);
                //Tuple<byte[], DetectionResult> cached = null;
                //byte[] roiBytes = roi.GetBytes();
                //if (hashCache.TryGetValue(key, out cached))
                //{
                //    if (ImageUtils.AreEqual(cached.Item1, roiBytes))
                //    {
                //        TraceLog.Log("hash cache hit: {0}, hit: {1} distance: {2}", key, cached.Item2.Found, cached.Item2.Distance);
                //        return cached.Item2;
                //    }
                //}

                var hash = this.imageHasher.Create(roi.Data);
                distance = PerceptualHash.HammingDistance(hash, area.Hash);
                TraceLog.Log("Detecting '{0}'. Distance: {1}", key, distance);

                if (distance <= threshold)
                {
                    TraceLog.Log("Detected '{0}'. Distance: {1}", key, distance);
                    Mostly mostly;
                    if (!String.IsNullOrEmpty(area.Mostly) && Enum.TryParse(area.Mostly, out mostly))
                    {
                        result = new DetectionResult(roi.Data.IsMostly(mostly), distance);
                    }
                    else
                    {
                        result = new DetectionResult(true, distance);
                    }
                }
                else
                {
                    result = new DetectionResult(false, distance);
                }
                // hashCache.Set(key, new Tuple<byte[], DetectionResult>(roiBytes, result));
            }
            return(result);
        }