/// <summary> /// Trains the classifier to recognise a single letter based on an image from our 'sample-data' folder /// </summary> private static void TrainSampleCharacter(Classifier <char> classifier, char character) { WrappedBitmap wb = WrappedBitmap.FromFile($@"..\..\..\..\sample-data\{character}.png"); Console.Write(character); classifier.Train(wb, character, TuningParams.TrainingRounds); }
/// <summary> /// Trains the model to recognise the specified input as the specified symbol /// </summary> public void Train(WrappedBitmap inputData, TSymbol representedValue, uint rounds) { var initialGeneration = Enumerable.Range(0, (int)rounds) .Select(i => new Scorer(new TuningParams.Scoring())) // TODO nested constructors is smelly .Select(s => new ScorerScorePair(s, s.Score(inputData))) .AsParallel() .OrderByDescending(s => s.Score); // Having acquired the initial set of sampling pixels via sheer randomness, we'll work with // the best we've got and try and massage them into something better. var mutParams = new TuningParams.Mutation(); var initialBestCandidates = initialGeneration.Take(100); // TODO parameterise magic value (which was decided totally arbitrarily anyway) var initialBestCandidatesWithMutatedVariants = from p in initialBestCandidates let mutatedOffspring = p.Scorer.MutateMany(mutParams) let mutatedScores = from m in mutatedOffspring let mutatedScore = m.Score(inputData) select new ScorerScorePair(m, mutatedScore) select new ParentChildScoreCollection(p, mutatedScores); var bestOftheMutantStrains = initialBestCandidatesWithMutatedVariants .SelectMany(x => x.Children) .OrderByDescending(s => s.Score) .First(); // Compute some stats for these mutations. These stats are for interest only, they don't affect any computation. Benchmarking.Mutation.AddDataPoints(initialBestCandidatesWithMutatedVariants); var rec = new Recogniser <TSymbol>(representedValue, bestOftheMutantStrains.Scorer); RegisterRecogniser(rec); }
/// <summary> /// Calculates a score for the given input data. The higher the score, the more /// likely that the input image represents the value of <c>Symbol</c>. /// </summary> public int Score(WrappedBitmap inputData) { if (inputData == null) { throw new ArgumentNullException(nameof(inputData)); } return(_scorer.Score(inputData)); }
/// <summary> /// Returns a list of symbols the classifier recognises, paired /// with the score that the given image matches that symbol /// </summary> public Dictionary <TSymbol, int> Classify(WrappedBitmap input) { return(_recognisers .Select(r => new { Symbol = r.Key, Score = r.Value.Score(input) }) .ToDictionary(kvp => kvp.Symbol, kvp => kvp.Score)); }
/// <summary> /// Calculates a score for the given input data. The higher the score, the more /// likely that the input image represents the value of <c>Symbol</c>. /// </summary> public int Score(WrappedBitmap inputData) { int score = 0; foreach (var point in _pixelsToSample) { if (inputData.IsPixelSet(point.X, point.Y)) { score += _tuningParams.PositiveScoreOffset; } else { score -= _tuningParams.NegativeScoreOffset; } } return(score); }
static void Main(string[] args) { WrappedBitmap a1w = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\a1.png"); WrappedBitmap a2w = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\a2.png"); WrappedBitmap a3w = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\a3.png"); //WrappedBitmap bw = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\b.png"); WrappedBitmap cw = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\c.png"); //WrappedBitmap dw = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\d.png"); //WrappedBitmap ew = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\e.png"); WrappedBitmap fw = WrappedBitmap.FromFile(@"..\..\..\..\sample-data\f.png"); var charClassifier_1 = new Classifier <char>(); charClassifier_1.Train(a1w, 'a', TuningParams.TrainingRounds); TrainSampleCharacters(charClassifier_1); var x = charClassifier_1.Classify(cw).OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key); Console.WriteLine("Input (C) is likely to be these letters (most likely first): {0}", string.Join(", ", x.Take(4))); var y = charClassifier_1.Classify(fw).OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key); Console.WriteLine("Input (F) is likely to be these letters (most likely first): {0}", string.Join(", ", y.Take(4))); var z = charClassifier_1.Classify(a1w).OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key); Console.WriteLine("Input (A) is likely to be these letters (most likely first): {0}", string.Join(", ", z.Take(4))); var z1 = charClassifier_1.Classify(a2w).OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key); Console.WriteLine("Input (A2) is likely to be these letters (most likely first): {0}", string.Join(", ", z1.Take(4))); var z2 = charClassifier_1.Classify(a3w).OrderByDescending(kvp => kvp.Value).Select(kvp => kvp.Key); Console.WriteLine("Input (A3) is likely to be these letters (most likely first): {0}", string.Join(", ", z2.Take(4))); //new Recogniser<char>('A').DrawSamplePoints().Save(@"..\..\..\..\sample-data\hello world.bmp"); Console.WriteLine("Press any key to quit"); Console.ReadKey(); }