Example #1
0
        /* If the user selects a card, returns the card, otherwise null */
        private Card AskUserToConfirm(Bitmap targetImage, Hashtable possibleMatches)
        {
            /*
             * if (possibleMatches.Count == 0)
             * {
             *  Globals.Director.WriteDebug(WRITE_DEBUG,"Warning: We should ask the user to confirm an image, but there are no possible matches...");
             *  return null;
             * }*/

            CardMatchSelectDialog dialog = new CardMatchSelectDialog();

            dialog.Location = cardMatchDialogSpawnLocation;
            dialog.DisplayImageToMatch(targetImage);

            // Create list
            List <String> orderedFilenames = new List <String>();

            foreach (String cardMatchFile in possibleMatches.Keys)
            {
                orderedFilenames.Add(cardMatchFile);

                Globals.Director.WriteDebug(WRITE_DEBUG, cardMatchFile + " has similarity of " + possibleMatches[cardMatchFile]);
            }

            orderedFilenames.Sort((delegate(String file1, String file2)
            {
                return(((double)possibleMatches[file2]).CompareTo((double)possibleMatches[file1]));
            }));

            // Create cards from filenames
            const int MAX_CARDS_TO_DISPLAY = 5;
            int       i = 0;

            foreach (String filename in orderedFilenames)
            {
                dialog.AddPossibleCardMatch(Card.CreateFromPath(filename));
                i++;
                if (i == MAX_CARDS_TO_DISPLAY)
                {
                    break;
                }
            }

            if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                // The user selected a card
                Card userCard = dialog.SelectedCard;

                /* Before returning to the caller, we replace the image associated with the card
                 * with the targetimage. This process allows us to slowly replace the common card images templates
                 * with images that come directly from the poker client, allowing us to achieve an almost perfect match
                 * the next time the same card is compared */
                ReplaceTemplateImageWith(userCard, targetImage);

                return(userCard);
            }

            return(null);
        }
Example #2
0
        /* It returns null if there are no good matches
         * If training mode is enabled, a window might ask the user to aid the algorithm find the best match */
        public Card MatchCard(Bitmap image, string player_card      = null,
                              double perfectMatchHistogramThreshold = 0,
                              double possibleMatchTemplateThreshold = 0,
                              double allowableSimilarityThreshold   = 0)
        {
            if (image == null)
            {
                return(null);
            }

            if (0.0d == perfectMatchHistogramThreshold)
            {
                perfectMatchHistogramThreshold = PERFECT_MATCH_HISTOGRAM_THRESHOLD;
            }

            if (0.0d == possibleMatchTemplateThreshold)
            {
                possibleMatchTemplateThreshold = POSSIBLE_MATCH_TEMPLATE_THRESHOLD;
            }

            if (0.0d == allowableSimilarityThreshold)
            {
                allowableSimilarityThreshold = ALLOWABLE_MATCH_TEMPLATE_THRESHOLD;
            }

            if (player_card == null)
            {
                player_card = "unk";
            }

            double minDifference     = Double.MaxValue;
            double maxSimilarity     = 0.0d;
            String bestMatchFilename = "";

            /* We keep a hashtable of possible matches (filename => match %)
             * so that if training mode is enabled we can access it to figure out which
             * are the most likely candidates */
            Hashtable possibleMatches = new Hashtable();


            foreach (String cardMatchFile in cardMatchFiles)
            {
                Bitmap candidateImage = new Bitmap(cardMatchFile);

                bool sizesMatch = candidateImage.Height == image.Height && candidateImage.Width == image.Width;

                // For template matching template should be smaller than image
                candidateImage = ScaleIfBiggerThan(image, candidateImage);


                String name = cardMatchFile.Substring(cardMatchFile.Length - 9) + "\n";

                Globals.Director.WriteDebug(WRITE_DEBUG, " --- STARTING COMP: " + name + " for: " + player_card);
                double difference = HistogramBitmapDifference(image, candidateImage);
                double similarity = TemplateMatchingSimilarity(image, candidateImage);

                Globals.Director.WriteDebug(WRITE_DEBUG, "--- " + player_card + " : " + name + " difference: (" + difference + ") similarity: (" + similarity + ")");


                if (difference < minDifference)
                {
                    Globals.Director.WriteDebug(WRITE_DEBUG, " ---- setting the minDifference to: " + difference);
                    minDifference     = difference;
                    bestMatchFilename = cardMatchFile;
                }

                if (similarity > maxSimilarity)
                {
                    Globals.Director.WriteDebug(WRITE_DEBUG, " ---- setting the maxSimilarity to: " + similarity);
                    maxSimilarity = similarity;
                }

                /* We use histogram difference to match perfect copies of the image (after the training phase is over)
                 * but if they are different, we use the template matching as an indicator of similarity */

                if (difference > perfectMatchHistogramThreshold && similarity > possibleMatchTemplateThreshold)
                {
                    /* Our set of common cards is typically larger than the actual client matches
                     * (although there could be rare exceptions that would not influence negatively the behavior of the algorithm).
                     * So, given that same size images have already been matched by the user during training mode,
                     * we can pretty safely ignore them, since
                     * they are likely to be perfectly matched with another target (and this block would have not been executed) */

                    // if (!sizesMatch)
                    // {
                    // Globals.Director.WriteDebug(WRITE_DEBUG,"\n\n\n --- Adding " + name + " to possible matches");
                    possibleMatches.Add(cardMatchFile, similarity);
                    // }
                }

                candidateImage.Dispose();
            }

            Card matchedCard = null; // Hold the return value

            /* If we have a possible match, but we are not too sure about it, we can ask the user to confirm our guesses */
            if (Globals.UserSettings.TrainingModeEnabled)
            {
                if (minDifference > perfectMatchHistogramThreshold && maxSimilarity > possibleMatchTemplateThreshold)
                {
                    Globals.Director.WriteDebug(WRITE_DEBUG, "Min difference too high (" + minDifference + ") and max similarity (" + maxSimilarity + ") above threshold, asking user to confirm our guesses");

                    Card userCard = null;
                    Globals.Director.RunFromGUIThread((Action) delegate()
                    {
                        userCard = AskUserToConfirm(image, possibleMatches);
                    }, false
                                                      );

                    if (userCard != null)
                    {
                        matchedCard = userCard;
                    }
                }
            }


            Globals.Director.WriteDebug(WRITE_DEBUG, "\n\t Card Position: " + player_card + "\n\t");
            Globals.Director.WriteDebug(WRITE_DEBUG, "Matched " + bestMatchFilename.Substring(bestMatchFilename.Length - 5) + " (Difference: " + minDifference + ")" + " (Similarity: " + maxSimilarity + ")");
            Globals.Director.WriteDebug(WRITE_DEBUG, "\n\t bestMatchFile: " + bestMatchFilename + "\n\t");
            Globals.Director.WriteDebug(WRITE_DEBUG, "\n\t allowableSimilarityThreshold: " + allowableSimilarityThreshold + "\n\t");
            // If the user has selected a card, matchedCard is an object and this is skipped
            if (minDifference < perfectMatchHistogramThreshold && matchedCard == null && bestMatchFilename != "")
            {
                Globals.Director.WriteDebug(WRITE_DEBUG, "\t --- creating from minDiff");
                matchedCard = Card.CreateFromPath(bestMatchFilename);
            }

            if (maxSimilarity > allowableSimilarityThreshold && matchedCard == null && bestMatchFilename != "")
            {
                Globals.Director.WriteDebug(WRITE_DEBUG, "\t --- creating from maxSim: " + maxSimilarity);
                matchedCard = Card.CreateFromPath(bestMatchFilename);
            }

            return(matchedCard);
        }
Example #3
0
        /* It returns null if there are no good matches
         * If training mode is enabled, a window might ask the user to aid the algorithm find the best match */
        public Card MatchCard(Bitmap image)
        {
            if (image == null)
            {
                return(null);
            }

            double minDifference     = Double.MaxValue;
            double maxSimilarity     = 0.0d;
            String bestMatchFilename = "";

            /* We keep a hashtable of possible matches (filename => match %)
             * so that if training mode is enabled we can access it to figure out which
             * are the most likely candidates */
            Hashtable possibleMatches = new Hashtable();


            foreach (String cardMatchFile in cardMatchFiles)
            {
                Bitmap candidateImage = new Bitmap(cardMatchFile);

                bool sizesMatch = candidateImage.Height == image.Height && candidateImage.Width == image.Width;

                // For template matching template should be smaller than image
                candidateImage = ScaleIfBiggerThan(image, candidateImage);


                double difference = HistogramBitmapDifference(image, candidateImage);
                double similarity = TemplateMatchingSimilarity(image, candidateImage);

                if (difference < minDifference)
                {
                    minDifference     = difference;
                    bestMatchFilename = cardMatchFile;
                }

                if (similarity > maxSimilarity)
                {
                    maxSimilarity = similarity;
                }

                /* We use histogram difference to match perfect copies of the image (after the training phase is over)
                 * but if they are different, we use the template matching as an indicator of similarity */

                if (difference > PERFECT_MATCH_HISTOGRAM_THRESHOLD && similarity > POSSIBLE_MATCH_TEMPLATE_THRESHOLD)
                {
                    /* Our set of common cards is typically larger than the actual client matches
                     * (although there could be rare exceptions that would not influence negatively the behavior of the algorithm).
                     * So, given that same size images have already been matched by the user during training mode,
                     * we can pretty safely ignore them, since
                     * they are likely to be perfectly matched with another target (and this block would have not been executed) */

                    if (!sizesMatch)
                    {
                        possibleMatches.Add(cardMatchFile, similarity);
                    }
                }

                candidateImage.Dispose();
            }

            //Trace.WriteLine("Matched " + bestMatchFilename + " (Difference: " + minDifference + ")");

            Card matchedCard = null; // Hold the return value

            /* If we have a possible match, but we are not too sure about it, we can ask the user to confirm our guesses */
            if (Globals.UserSettings.TrainingModeEnabled)
            {
                if (minDifference > PERFECT_MATCH_HISTOGRAM_THRESHOLD && maxSimilarity > POSSIBLE_MATCH_TEMPLATE_THRESHOLD)
                {
                    Trace.WriteLine("Min difference too high (" + minDifference + ") and max similarity above threshold, asking user to confirm our guesses");

                    Card userCard = null;
                    Globals.Director.RunFromGUIThread((Action) delegate()
                    {
                        userCard = AskUserToConfirm(image, possibleMatches);
                    }, false
                                                      );

                    if (userCard != null)
                    {
                        matchedCard = userCard;
                    }
                }
            }

            // If the user has selected a card, matchedCard is an object and this is skipped
            if (minDifference < PERFECT_MATCH_HISTOGRAM_THRESHOLD && matchedCard == null && bestMatchFilename != "")
            {
                matchedCard = Card.CreateFromPath(bestMatchFilename);
            }

            return(matchedCard);
        }