private static double scoreBitmap(WordsearchRotation rotation, Classifier classifier) { //Extract each charcater in this wordsearch, then run them through the classifier and sum the liklihoods of // the most probable class to determine an overall score for the image Bitmap[,] chars = null; //If using number of rows & cols for a fixed row/col width/height if(rotation.Segmentation == null) { //Use standardised width & height for characters (do this by first resizing the image) int wordsearchWidth = Constants.CHAR_WITH_WHITESPACE_WIDTH * rotation.Cols; int wordsearchHeight = Constants.CHAR_WITH_WHITESPACE_HEIGHT * rotation.Rows; ResizeBicubic resize = new ResizeBicubic(wordsearchWidth, wordsearchHeight); Bitmap resizedImg = resize.Apply(rotation.Bitmap); //Split the bitmap up into a 2D array of bitmaps chars = SplitImage.Grid(resizedImg, rotation.Rows, rotation.Cols); //If the image got resized, dispose of the resized copy if(resizedImg != rotation.Bitmap) { resizedImg.Dispose(); } } else //Otherwise we have a Segmentation object to use { chars = SplitImage.Segment(rotation.Bitmap, rotation.Segmentation); } double score = 0; foreach(Bitmap charImg in chars) { //Remove all of the whitespace etc... returning an image that can be used for classification Bitmap extractedCharImg = CharImgExtractor.Extract(charImg); //Classify this bitmap double[] charResult = classifier.Classify(extractedCharImg); //Get the largest probability from the classifier output and add it to the overall score double largest = charResult[0]; for(int i = 1; i < charResult.Length; i++) { if(charResult[i] > largest) { largest = charResult[i]; } } score += largest; //Clean up extractedCharImg.Dispose(); charImg.Dispose(); } return score; }
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; }