//returns score & score after removing erroenously small rows and cols (null if segmentation algorithm doesn't support this)
        private static Tuple<double, double?> EvaluateByNumRowsAndCols(List<WordsearchImage> wordsearchImages, SegmentationAlgorithm segAlgorithm)
        {
            DefaultLog.Info("Evaluating Wordsearch Image Segmentation by number of rows and cols returned . . .");

            int numCorrect = 0;
            int numCorrectRemoveSmallRowsAndCols = 0;

            //Test the algorithm on each Wordsearch Image
            foreach(WordsearchImage wordsearchImage in wordsearchImages)
            {
                //Register an interest in the Bitmap of the Wordsearch Image
                wordsearchImage.RegisterInterestInBitmap();

                Segmentation proposedSegmentation = segAlgorithm.Segment(wordsearchImage.Bitmap);

                //Keep track of the number of correct
                if(proposedSegmentation.NumRows == wordsearchImage.Rows && 
                    proposedSegmentation.NumCols == wordsearchImage.Cols)
                {
                    numCorrect++;
                }

                //If this segmentation algorithm performs its segmentation with start & end character indices & can therefore have
                //  small rows and cols removed, do it
                if(segAlgorithm is SegmentationAlgorithmByStartEndIndices)
                {
                    Segmentation segRemoveSmallRowsAndCols = proposedSegmentation.RemoveSmallRowsAndCols();

                    if(segRemoveSmallRowsAndCols.NumRows == wordsearchImage.Rows &&
                        segRemoveSmallRowsAndCols.NumCols == wordsearchImage.Cols)
                    {
                        numCorrectRemoveSmallRowsAndCols++;
                    }
                }

                //Clean Up
                wordsearchImage.DeregisterInterestInBitmap();
            }

            DefaultLog.Info("Returned {0}/{1} Wordsearch Segmentations Correctly", numCorrect, wordsearchImages.Count);

            double score = (double)numCorrect / wordsearchImages.Count;
            double? scoreRemoveSmallRowsAndCols = null;
            if(segAlgorithm is SegmentationAlgorithmByStartEndIndices)
            {
                scoreRemoveSmallRowsAndCols = (double)numCorrectRemoveSmallRowsAndCols / wordsearchImages.Count;
                DefaultLog.Info("Returned {0}/{1} Wordsearch Segmentations Correctly after removing small rows and cols", 
                    numCorrectRemoveSmallRowsAndCols, wordsearchImages.Count);
            }

            DefaultLog.Info("Wordsearch Image Segmentation Evaluation Completed");

            return Tuple.Create(score, scoreRemoveSmallRowsAndCols);
        }
예제 #2
0
 //Constructors
 public AlgorithmCombination(SegmentationAlgorithm detectionSegmentationAlgorithm,
     bool detectionSegmentationRemoveSmallRowsAndCols, SegmentationAlgorithm segmentationAlgorithm, 
     bool segmentationRemoveSmallRowsAndCols, EvaluateFullSystem.SegmentationMethod segmentationMethod,
     Classifier probabilisticRotationCorrectionClassifier, Classifier classifier,
     Solver wordsearchSolver)
 {
     this.DetectionSegmentationAlgorithm = detectionSegmentationAlgorithm;
     this.DetectionSegmentationRemoveSmallRowsAndCols = detectionSegmentationRemoveSmallRowsAndCols;
     this.SegmentationAlgorithm = segmentationAlgorithm;
     this.SegmentationRemoveSmallRowsAndCols = segmentationRemoveSmallRowsAndCols;
     this.SegmentationMethod = segmentationMethod;
     this.ProbabilisticRotationCorrectionClassifier = probabilisticRotationCorrectionClassifier;
     this.Classifier = classifier;
     this.WordsearchSolver = wordsearchSolver;
 }
        private static double EvaluateReturnsWordsearch(List<Image> images, SegmentationAlgorithm segAlgorithm, bool removeSmallRowsAndCols)
        {
            DefaultLog.Info("Evaluating Wordsearch Detection by best wordsearch returned . . .");

            int numCorrect = 0;

            //Test the algorithm on each Image
            foreach (Image image in images)
            {
                //Register an interest in the Bitmap of the Image
                image.RegisterInterestInBitmap();

                Tuple<List<IntPoint>, Bitmap> bestCandidate = DetectionAlgorithm.ExtractBestWordsearch(image.Bitmap, segAlgorithm, removeSmallRowsAndCols);
                
                //If we found a valid best candidate
                if (bestCandidate != null)
                {
                    //Check if the best candidate is a wordsearch in this image
                    List<IntPoint> points = bestCandidate.Item1;

                    if(IsWordsearch(points, image))
                    {
                        numCorrect++;
                    }
                    else
                    {
                        //Console.WriteLine("Incorrect"); //Debug Point (for viewing incorrect Bitmaps)
                    }
                }
                else //Otherwise we couldn't find anything that resembeled a quadrilateral (and could therefore be a wordsearch)
                {
                    
                }

                //Clean up
                bestCandidate.Item2.Dispose();
                image.DeregisterInterestInBitmap();
            }

            DefaultLog.Info("Found a Wordsearch for {0} / {1} Images correctly", numCorrect, images.Count);
            DefaultLog.Info("Wordsearch Detection Evaluation Completed");

            return (double)numCorrect / images.Count;
        }
예제 #4
0
        internal static WordsearchSolutionEvaluator EvaluateWordsearchBitmap(Bitmap wordsearchBitmap, string[] wordsToFind,
            Dictionary<string, List<WordPosition>> correctSolutions, SegmentationAlgorithm segmentationAlgorithm, 
            bool segmentationRemoveSmallRowsAndCols, SegmentationMethod segmentationMethod,
            Classifier probabilisticRotationCorrectionClassifier, Classifier classifier, Solver wordsearchSolver)
        {
            /*
             * Wordsearch Segmentation
             */
            Segmentation segmentation = segmentationAlgorithm.Segment(wordsearchBitmap);

            //Remove erroneously small rows and columns from the segmentation if that option is specified
            if(segmentationRemoveSmallRowsAndCols)
            {
                segmentation = segmentation.RemoveSmallRowsAndCols();
            }

            /*
             * Wordsearch Rotation Correction
             */
            WordsearchRotation originalRotation;

            //If we're using fixed row & col width
            if (segmentationMethod == SegmentationMethod.FixedWidth)
            {
                originalRotation = new WordsearchRotation(wordsearchBitmap, segmentation.NumRows, segmentation.NumCols);
            }
            else //Otherwise we're using varied row/col width segmentation, use the Segmentation object
            {
                originalRotation = new WordsearchRotation(wordsearchBitmap, segmentation);
            }

            WordsearchRotation rotatedWordsearch = WordsearchRotationCorrection.CorrectOrientation(originalRotation, probabilisticRotationCorrectionClassifier);

            Bitmap rotatedImage = rotatedWordsearch.Bitmap;

            //If the wordsearch has been rotated
            if (rotatedImage != wordsearchBitmap)
            {
                //Update the segmentation

                //If the wordsearch rotation won't have been passed a segmentation
                if (segmentationMethod == SegmentationMethod.FixedWidth)
                {
                    //Make a new fixed width segmentation from the WordsearchRotation
                    segmentation = new Segmentation(rotatedWordsearch.Rows, rotatedWordsearch.Cols,
                        rotatedImage.Width, rotatedImage.Height);
                }
                else
                {
                    //Use the rotated segmentation 
                    segmentation = rotatedWordsearch.Segmentation;
                }
            }

            /*
             * Classification
             */

            //Split image up into individual characters
            Bitmap[,] rawCharImgs = null;

            //If we're using fixed row & col width
            if (segmentationMethod == SegmentationMethod.FixedWidth)
            {
                ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH * segmentation.NumCols,
                    Constants.CHAR_WITH_WHITESPACE_HEIGHT * segmentation.NumRows);
                Bitmap resizedImage = resize.Apply(rotatedImage);

                rawCharImgs = SplitImage.Grid(resizedImage, segmentation.NumRows, segmentation.NumCols);

                //Resized image no longer required
                resizedImage.Dispose();
            }
            else //Otherwise we're using varied row/col width segmentation
            {
                rawCharImgs = SplitImage.Segment(rotatedImage, segmentation);

                //If the Segmentation Method is to resize the raw char imgs, resize them
                if (segmentationMethod == SegmentationMethod.VariedWidthWithResize)
                {
                    ResizeBicubic resize = new ResizeBicubic(Constants.CHAR_WITH_WHITESPACE_WIDTH, Constants.CHAR_WITH_WHITESPACE_HEIGHT);

                    for (int i = 0; i < rawCharImgs.GetLength(0); i++)
                    {
                        for (int j = 0; j < rawCharImgs.GetLength(1); j++)
                        {
                            //Only do the resize if it isn't already that size
                            if (rawCharImgs[i, j].Width != Constants.CHAR_WITH_WHITESPACE_WIDTH
                                || rawCharImgs[i, j].Height != Constants.CHAR_WITH_WHITESPACE_HEIGHT)
                            {
                                Bitmap orig = rawCharImgs[i, j];

                                rawCharImgs[i, j] = resize.Apply(orig);

                                //Remove the now unnecessary original/not resized image
                                orig.Dispose();
                            }
                        }
                    }
                }
            }

            //Full sized rotated image no longer required
            rotatedImage.Dispose();

            //Get the part of the image that actually contains the character (without any whitespace)
            Bitmap[,] charImgs = CharImgExtractor.ExtractAll(rawCharImgs);

            //Raw char img's are no longer required
            rawCharImgs.ToSingleDimension().DisposeAll();

            //Perform the classification on all of the images (returns probabilities for each possible class)
            double[][][] classifierOutput = classifier.Classify(charImgs);

            //Actual images of the characters are no longer required
            charImgs.ToSingleDimension().DisposeAll();

            /*
             * Solve Wordsearch
             */
            Solution solution = wordsearchSolver.Solve(classifierOutput, wordsToFind);

            /*
             * Evaluate the Proposed Solution
             */
            WordsearchSolutionEvaluator evaluator = new WordsearchSolutionEvaluator(solution, correctSolutions);

            return evaluator;
        }
예제 #5
0
        private static double Evaluate(List<Image> images, SegmentationAlgorithm detectionSegmentationAlgorithm, 
            bool detectionSegmentationRemoveSmallRowsAndCols, SegmentationAlgorithm segmentationAlgorithm, 
            bool segmentationRemoveSmallRowsAndCols, SegmentationMethod segmentationMethod, 
            Classifier probabilisticRotationCorrectionClassifier, Classifier classifier, Solver wordsearchSolver)
        {
            DefaultLog.Info("Evaluating Full System . . .");

            int numCorrect = 0;
            List<WordsearchSolutionEvaluator> evaluators = new List<WordsearchSolutionEvaluator>();

            foreach(Image image in images)
            {
                //Register an interest in the Bitmap of the image
                image.RegisterInterestInBitmap();

                /*
                 * Wordsearch Detection
                 */
                Tuple<List<IntPoint>, Bitmap> wordsearchImageTuple = DetectionAlgorithm.ExtractBestWordsearch(image.Bitmap, detectionSegmentationAlgorithm, detectionSegmentationRemoveSmallRowsAndCols);
                
                //Original wordsearch image is no longer required
                image.DeregisterInterestInBitmap();

                //If the system failed to find anything remotely resembling a wordsearch, fail now
                if(wordsearchImageTuple == null)
                {
                    continue;
                }

                //Get the words to look for later from this image & the correct solutions
                string[] wordsToFind = null; //Requires default, but won't even get used
                Dictionary<string, List<WordPosition>> correctSolutions = null;
                //If the image contains more than one wordsearch, we need to work out which one has been found
                if(image.WordsearchImages.Length > 1)
                {
                    List<IntPoint> coordinates = wordsearchImageTuple.Item1;
                    bool found = false;

                    //Select the wordsearch found using the algorithm for checking if the returned wordsearch is correct in EvaluateWordsearchDetection
                    foreach(WordsearchImage wordsearchImage in image.WordsearchImages)
                    {
                        //If it's this wordsearch
                        if(EvaluateWordsearchDetection.IsWordsearch(coordinates, wordsearchImage))
                        {
                            wordsToFind = wordsearchImage.Wordsearch.Words;
                            correctSolutions = wordsearchImage.Wordsearch.Solutions;
                            found = true;
                            break;
                        }
                    }

                    //If this isn't one of the wordsearches in the image, then fail now 
                    if(!found)
                    {
                        //Clean up
                        wordsearchImageTuple.Item2.Dispose();

                        continue;
                    }
                }
                else //Otherwise just use the one wordsearch that's in the image
                {
                    wordsToFind = image.WordsearchImages[0].Wordsearch.Words;
                    correctSolutions = image.WordsearchImages[0].Wordsearch.Solutions;
                }
                
                Bitmap extractedImage = wordsearchImageTuple.Item2;

                /*
                 * Image Segmentation onwards happen in EvaluateWordsearchBitmap
                 */
                WordsearchSolutionEvaluator evaluator = EvaluateWordsearchBitmap(extractedImage, wordsToFind, correctSolutions,
                    segmentationAlgorithm, segmentationRemoveSmallRowsAndCols, segmentationMethod, 
                    probabilisticRotationCorrectionClassifier, classifier, wordsearchSolver);

                //Clean up
                extractedImage.Dispose();

                //Log Evaluation
                evaluators.Add(evaluator);

                DefaultLog.Info(evaluator.ToString());

                if(evaluator.Correct)
                {
                    numCorrect++;
                }
            }

            DefaultLog.Info("System found all words correctly for {0} / {1} Images correctly", numCorrect, images.Count);

            //Calculate some extra statistics
            int numWordsearchesNoWordsFound = 0;
            int numDidntReachEvaluation = images.Count - evaluators.Count;
            double fMeasureSum = 0;
            int numValidFMeasures = 0;

            foreach (WordsearchSolutionEvaluator evaluator in evaluators)
            {
                //If no words were found correctly
                if(evaluator.TruePositive == 0)
                {
                    numWordsearchesNoWordsFound++;
                }

                //If there was a valid F-Measure
                if(!double.IsNaN(evaluator.FMeasure))
                {
                    fMeasureSum += evaluator.FMeasure;
                    numValidFMeasures++;
                }
            }

            DefaultLog.Info("In {0} wordsearches no words were found correctly at all", numWordsearchesNoWordsFound);
            DefaultLog.Info("{0} wordsearch images got discarded before reaching the evaluation stage", numDidntReachEvaluation);
            DefaultLog.Info("Average F-Measure (when not NaN): {0}", fMeasureSum / numValidFMeasures);

            DefaultLog.Info("Full System Evaluation Completed");

            return (double)numCorrect / images.Count;
        }
예제 #6
0
        //Method to extract a Bitmap of the best match for a wordsearch in an image using a specified Wordsearch Segmentation Algorithm
        //returns null if no Wordsearch candidate could be found in the image
        public static Tuple<List<IntPoint>, Bitmap> ExtractBestWordsearch(Bitmap image, SegmentationAlgorithm segAlg, bool removeSmallRowsAndCols)
        {
            double blobMinDimensionDbl = BLOB_MIN_DIMENSION_PERCENTAGE / 100;
            int minWidth = (int)Math.Ceiling(image.Width * blobMinDimensionDbl); //Round up, so that the integer comaprison minimum will always be correct
            int minHeight = (int)Math.Ceiling(image.Height * blobMinDimensionDbl);

            List<List<IntPoint>> quads = ShapeFinder.Quadrilaterals(image, minWidth, minHeight);

            //Check that there are some quads found to search through for the best wordsearch candidate
            if(quads.Count != 0)
            {
                double bestScore = double.NegativeInfinity;
                List<IntPoint> bestCoords = null;
                Bitmap bestBitmap = null;

                //Search for the Bitmap that yields the best score
                foreach (List<IntPoint> quad in quads)
                {
                    //Extract the Bitmap of this quad
                    QuadrilateralTransformation quadTransform = new QuadrilateralTransformation(quad);
                    Bitmap quadBitmap = quadTransform.Apply(image);

                    //Score this wordsearch candidate
                    double score;
                    //If an InvalidRowsAndCols Exception gets throw by the segmentation 
                    //  (due to there being 0 rows/cols in the returned segmentation)
                    //  this is obviously not a good wordsearch candidate
                    try
                    {
                        Segmentation segmentation = segAlg.Segment(quadBitmap);
                        
                        //If removing erroneously small rows and cols before scoring the segmentation, do so now
                        if(removeSmallRowsAndCols)
                        {
                            segmentation = segmentation.RemoveSmallRowsAndCols();
                        }

                        CandidateScorer scorer = new CandidateScorer(segmentation);
                        score = scorer.WordsearchRecognitionScore;
                    }
                    catch(InvalidRowsAndColsException)
                    {
                        //This is slightly better than the default score of Negative Infinity as any candidate
                        //  (even one with no rows or cols found in it) is better than no candidate whatsoever
                        score = double.MinValue;
                    }

                    //If this score is better than the previous best (don't 
                    //  override equal scores as the list is size ordered and 
                    //  we'll default to the biggest wordsearch as being better)
                    if(score > bestScore)
                    {
                        bestScore = score;
                        bestCoords = quad;

                        //Dispose of the previously best Bitmap resource
                        if(bestBitmap != null)
                        {
                            bestBitmap.Dispose();
                        }
                        //Update the ptr to the new one
                        bestBitmap = quadBitmap;
                    }
                    else
                    {
                        //Clean up
                        quadBitmap.Dispose();
                    }
                }

                return Tuple.Create(bestCoords, bestBitmap);
            }
            else //Otherwise there are no quads to search through
            {
                return null;
            }
        }
예제 #7
0
 public static Tuple<List<IntPoint>, Bitmap> ExtractBestWordsearch(Bitmap image, SegmentationAlgorithm segAlg)
 {
     return ExtractBestWordsearch(image, segAlg, false); //Don't remove the erroneously small rows and cols by default
 }