From bdb04bdf9667287c7e9c7f631d8dcdbb2e376f3a Mon Sep 17 00:00:00 2001 From: maxluli Date: Tue, 4 Apr 2023 15:45:07 +0200 Subject: [PATCH] Added a good Name recognition algorythm --- OCR_Decode/DriverNameWindow.cs | 109 ++++++++++++++++++++++++++++++++- OCR_Decode/Reader.cs | 2 +- OCR_Decode/Window.cs | 15 +++++ OCR_Decode/Zone.cs | 11 +++- 4 files changed, 133 insertions(+), 4 deletions(-) diff --git a/OCR_Decode/DriverNameWindow.cs b/OCR_Decode/DriverNameWindow.cs index 1f6b3ef..2bc6ea1 100644 --- a/OCR_Decode/DriverNameWindow.cs +++ b/OCR_Decode/DriverNameWindow.cs @@ -15,12 +15,13 @@ namespace OCR_Decode { Name = "Name"; } + /* public override object DecodePng() { string result = ""; Bitmap rawData = WindowImage; - rawData = Window.ConvertToBlackAndWhite(rawData,100); + rawData = Window.ConvertToBlackAndWhite(rawData,150); TesseractEngine engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default); var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage)); @@ -46,7 +47,113 @@ namespace OCR_Decode } rawData.Save(Reader.DEBUG_DUMP_FOLDER + result + "_Before" + ".png"); return result; + } + */ + public override object DecodePng(List DriverList) + { + string result = ""; + int[] recommendedTresholds = new int[] { 100, 125, 150, 175, 200 }; + int index = 0; + while (!IsADriver(DriverList, result)) + { + if(index >= recommendedTresholds.Length -1) + { + //150 is usually the safest bet + result = GetStringFromPng(150); + //I put everything in uppercase to try to lower the chances of bad answers + result = FindClosestMatch(DriverList.ConvertAll(d => d.ToUpper()), result.ToUpper()); + break; + } + result = GetStringFromPng(recommendedTresholds[index]); + index++; + } + //rawData.Save(Reader.DEBUG_DUMP_FOLDER + result + "_Before" + ".png"); + return result; + } + private string GetStringFromPng(int BlackAndWhiteTresholh) + { + string result = ""; + + Bitmap rawData = WindowImage; + rawData = Window.ConvertToBlackAndWhite(rawData, 150); + + TesseractEngine engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default); + var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage)); + + Page page = engine.Process(tessImage); + Graphics g = Graphics.FromImage(rawData); + // Get the iterator for the page layout + using (var iter = page.GetIterator()) + { + // Loop over the elements of the page layout + iter.Begin(); + do + { + Rect boundingBox; + // Get the bounding box for the current element + if (iter.TryGetBoundingBox(PageIteratorLevel.Word, out boundingBox)) + { + g.DrawRectangle(Pens.Red, new Rectangle(boundingBox.X1, boundingBox.Y1, boundingBox.Width, boundingBox.Height)); + } + // Get the text for the current element + result += iter.GetText(PageIteratorLevel.Word); + } while (iter.Next(PageIteratorLevel.Word)); + } + return result; + } + //This method has been gnerated using ChatGPT + public static string FindClosestMatch(List array, string target) + { + var closestMatch = ""; + var closestDistance = int.MaxValue; + + foreach (var item in array) + { + var distance = LevenshteinDistance(item, target); + if (distance < closestDistance) + { + closestMatch = item; + closestDistance = distance; + } + } + + return closestMatch; + } + + public static int LevenshteinDistance(string s1, string s2) + { + if (string.IsNullOrEmpty(s1)) + { + return string.IsNullOrEmpty(s2) ? 0 : s2.Length; + } + + if (string.IsNullOrEmpty(s2)) + { + return string.IsNullOrEmpty(s1) ? 0 : s1.Length; + } + + var d = new int[s1.Length + 1, s2.Length + 1]; + for (var i = 0; i <= s1.Length; i++) + { + d[i, 0] = i; + } + + for (var j = 0; j <= s2.Length; j++) + { + d[0, j] = j; + } + + for (var i = 1; i <= s1.Length; i++) + { + for (var j = 1; j <= s2.Length; j++) + { + var cost = (s1[i - 1] == s2[j - 1]) ? 0 : 1; + d[i, j] = Math.Min(Math.Min(d[i - 1, j] + 1, d[i, j - 1] + 1), d[i - 1, j - 1] + cost); + } + } + + return d[s1.Length, s2.Length]; } } } diff --git a/OCR_Decode/Reader.cs b/OCR_Decode/Reader.cs index adfdac8..63f66ec 100644 --- a/OCR_Decode/Reader.cs +++ b/OCR_Decode/Reader.cs @@ -183,7 +183,7 @@ namespace OCR_Decode //Main Zone foreach (Zone z in MainZones[mainZoneId].Zones) { - mainResults.Add(z.Decode()); + mainResults.Add(z.Decode(Drivers)); } break; //Next there will be the title and laps added diff --git a/OCR_Decode/Window.cs b/OCR_Decode/Window.cs index 5096921..7693aa9 100644 --- a/OCR_Decode/Window.cs +++ b/OCR_Decode/Window.cs @@ -38,6 +38,10 @@ namespace OCR_Decode { return " "; } + public virtual Object DecodePng(List drivers) + { + return " "; + } public static byte[] ImageToByte(Image img) { using (var stream = new MemoryStream()) @@ -46,6 +50,17 @@ namespace OCR_Decode return stream.ToArray(); } } + public static bool IsADriver(List drivers,string potentialDriver) + { + bool result = false; + //I cant use drivers.Contains because it has missmatched cases and all + foreach (string name in drivers) + { + if (name.ToUpper() == potentialDriver.ToUpper()) + result = true; + } + return result; + } public static Bitmap ConvertToBlackAndWhite(Bitmap inputBmp, int Treshold = 165) { Bitmap result = new Bitmap(inputBmp.Width, inputBmp.Height); diff --git a/OCR_Decode/Zone.cs b/OCR_Decode/Zone.cs index 761f0d1..74a8946 100644 --- a/OCR_Decode/Zone.cs +++ b/OCR_Decode/Zone.cs @@ -62,12 +62,19 @@ namespace OCR_Decode { Windows.Add(window); } - public virtual List Decode() + public virtual List Decode(List drivers) { List result = new List(); foreach (Window w in Windows) { - result.Add(w.DecodePng()); + if (w is DriverNameWindow) + { + result.Add((w as DriverNameWindow).DecodePng(drivers)); + } + else + { + result.Add(w.DecodePng()); + } } return result; }