From 341b9eb0a18419a27b3bb2fdb3c194cc83597d7e Mon Sep 17 00:00:00 2001 From: maxluli Date: Wed, 5 Apr 2023 14:18:38 +0200 Subject: [PATCH] Added post processing, now numbers detection is almost perfect --- OCR_Decode/OCR_Decode.csproj | 27 ++++ OCR_Decode/OcrImage.cs | 253 +++++++++++++++++++++++++++++++++++ OCR_Decode/Window.cs | 29 ++-- OCR_Decode/packages.config | 7 + 4 files changed, 303 insertions(+), 13 deletions(-) create mode 100644 OCR_Decode/OcrImage.cs diff --git a/OCR_Decode/OCR_Decode.csproj b/OCR_Decode/OCR_Decode.csproj index ab8c0d7..32805f1 100644 --- a/OCR_Decode/OCR_Decode.csproj +++ b/OCR_Decode/OCR_Decode.csproj @@ -35,6 +35,30 @@ 4 + + ..\packages\Accord.3.8.0\lib\net462\Accord.dll + + + ..\packages\Accord.Imaging.3.8.0\lib\net462\Accord.Imaging.dll + + + ..\packages\Accord.Math.3.8.0\lib\net462\Accord.Math.dll + + + ..\packages\Accord.Math.3.8.0\lib\net462\Accord.Math.Core.dll + + + ..\packages\Accord.Statistics.3.8.0\lib\net462\Accord.Statistics.dll + + + ..\packages\AForge.2.2.5\lib\AForge.dll + + + ..\packages\AForge.Imaging.2.2.5\lib\AForge.Imaging.dll + + + ..\packages\AForge.Math.2.2.5\lib\AForge.Math.dll + ..\packages\Microsoft.Bcl.AsyncInterfaces.7.0.0\lib\net462\Microsoft.Bcl.AsyncInterfaces.dll @@ -97,6 +121,7 @@ Form1.cs + @@ -135,5 +160,7 @@ This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + \ No newline at end of file diff --git a/OCR_Decode/OcrImage.cs b/OCR_Decode/OcrImage.cs new file mode 100644 index 0000000..1a9b047 --- /dev/null +++ b/OCR_Decode/OcrImage.cs @@ -0,0 +1,253 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Drawing; +using System.Drawing.Drawing2D; +using Accord.Imaging.Filters; + +namespace OCR_Decode +{ + //AT LEAST PART OF THIS CLASS HAVE BEEN CREATED USING CHATGPT + //Just so you know + internal class OcrImage + { + Bitmap InputImage; + public OcrImage(Bitmap inputImage) + { + InputImage = inputImage; + } + public Bitmap Enhance() + { + Bitmap result = (Bitmap)InputImage.Clone(); + result = Grayscale(result); + result = Tresholding(result, 200); + result = InvertColors(result); + result = Resize(result); + //result = Resize(result); + //result = Dilatation(result, 5); + //result = Erode(result,3); + return result; + } + public static Bitmap Grayscale(Bitmap input) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + for (int y = 0; y < input.Height; y++) + { + for (int x = 0; x < input.Width; x++) + { + Color pixel = input.GetPixel(x, y); + int gray = (int)(pixel.R * 0.3 + pixel.G * 0.59 + pixel.B * 0.11); + output.SetPixel(x, y, Color.FromArgb(gray, gray, gray)); + } + } + + return output; + } + public static Bitmap Tresholding(Bitmap input, int threshold) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + for (int y = 0; y < input.Height; y++) + { + for (int x = 0; x < input.Width; x++) + { + Color pixel = input.GetPixel(x, y); + int gray = (int)(pixel.R * 0.3 + pixel.G * 0.59 + pixel.B * 0.11); + int value = gray < threshold ? 0 : 255; + output.SetPixel(x, y, Color.FromArgb(value, value, value)); + } + } + + return output; + } + public static Bitmap InvertColors(Bitmap input) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + for (int y = 0; y < input.Height; y++) + { + for (int x = 0; x < input.Width; x++) + { + Color pixel = input.GetPixel(x, y); + int red = 255 - pixel.R; + int green = 255 - pixel.G; + int blue = 255 - pixel.B; + output.SetPixel(x, y, Color.FromArgb(red, green, blue)); + } + } + + return output; + } + public static Bitmap ApplyGaussianBlur(Bitmap input, int radius) + { + GaussianBlur filter = new GaussianBlur(radius); + Bitmap output = filter.Apply(input); + return output; + } + public static Bitmap Resize(Bitmap sourceBitmap) + { + // Create a new Bitmap object to hold the resized image + var resultBitmap = new Bitmap(sourceBitmap.Width * 2, sourceBitmap.Height * 2); + + // Create a Graphics object to draw the resized image + using (var graphics = Graphics.FromImage(resultBitmap)) + { + // Set the interpolation mode to high-quality bicubic + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + + // Draw the resized image using the Graphics object + graphics.DrawImage(sourceBitmap, new Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height)); + } + + return resultBitmap; + } + public static Bitmap HighlightContours(Bitmap input) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + Bitmap grayscale = Grayscale(input); + Bitmap thresholded = Tresholding(grayscale, 128); + Bitmap dilated = Dilatation(thresholded, 3); + Bitmap eroded = Erode(dilated, 3); + + for (int y = 0; y < input.Height; y++) + { + for (int x = 0; x < input.Width; x++) + { + Color pixel = input.GetPixel(x, y); + Color dilatedPixel = dilated.GetPixel(x, y); + Color erodedPixel = eroded.GetPixel(x, y); + + int gray = (int)(pixel.R * 0.3 + pixel.G * 0.59 + pixel.B * 0.11); + int threshold = dilatedPixel.R; + + if (gray > threshold) + { + output.SetPixel(x, y, Color.FromArgb(255, 255, 255)); + } + else if (gray <= threshold && erodedPixel.R == 0) + { + output.SetPixel(x, y, Color.FromArgb(255, 0, 0)); + } + else + { + output.SetPixel(x, y, Color.FromArgb(0, 0, 0)); + } + } + } + + return output; + } + public static Bitmap Erode(Bitmap input, int kernelSize) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + int[,] kernel = new int[kernelSize, kernelSize]; + + for (int i = 0; i < kernelSize; i++) + { + for (int j = 0; j < kernelSize; j++) + { + kernel[i, j] = 1; + } + } + + for (int y = kernelSize / 2; y < input.Height - kernelSize / 2; y++) + { + for (int x = kernelSize / 2; x < input.Width - kernelSize / 2; x++) + { + bool flag = true; + + for (int i = -kernelSize / 2; i <= kernelSize / 2; i++) + { + for (int j = -kernelSize / 2; j <= kernelSize / 2; j++) + { + Color pixel = input.GetPixel(x + i, y + j); + int gray = (int)(pixel.R * 0.3 + pixel.G * 0.59 + pixel.B * 0.11); + + if (gray >= 128 && kernel[i + kernelSize / 2, j + kernelSize / 2] == 1) + { + flag = false; + break; + } + } + + if (!flag) + { + break; + } + } + + if (flag) + { + output.SetPixel(x, y, Color.FromArgb(255, 255, 255)); + } + else + { + output.SetPixel(x, y, Color.FromArgb(0, 0, 0)); + } + } + } + + return output; + } + + public static Bitmap Dilatation(Bitmap input, int kernelSize) + { + Bitmap output = new Bitmap(input.Width, input.Height); + + int[,] kernel = new int[kernelSize, kernelSize]; + + for (int i = 0; i < kernelSize; i++) + { + for (int j = 0; j < kernelSize; j++) + { + kernel[i, j] = 1; + } + } + + for (int y = kernelSize / 2; y < input.Height - kernelSize / 2; y++) + { + for (int x = kernelSize / 2; x < input.Width - kernelSize / 2; x++) + { + bool flag = false; + + for (int i = -kernelSize / 2; i <= kernelSize / 2; i++) + { + for (int j = -kernelSize / 2; j <= kernelSize / 2; j++) + { + Color pixel = input.GetPixel(x + i, y + j); + int gray = (int)(pixel.R * 0.3 + pixel.G * 0.59 + pixel.B * 0.11); + + if (gray < 128 && kernel[i + kernelSize / 2, j + kernelSize / 2] == 1) + { + flag = true; + break; + } + } + + if (flag) + { + break; + } + } + + if (flag) + { + output.SetPixel(x, y, Color.FromArgb(0, 0, 0)); + } + else + { + output.SetPixel(x, y, Color.FromArgb(255, 255, 255)); + } + } + } + + return output; + } + + } +} diff --git a/OCR_Decode/Window.cs b/OCR_Decode/Window.cs index 2e113cd..5f898b7 100644 --- a/OCR_Decode/Window.cs +++ b/OCR_Decode/Window.cs @@ -7,6 +7,7 @@ using System.Drawing; using System.IO; using Tesseract; using System.Text.RegularExpressions; +using System.Drawing.Drawing2D; namespace OCR_Decode { @@ -89,17 +90,22 @@ namespace OCR_Decode { //returns milliseconds string rawResult = ""; - int treshold = 165; + int treshold = 100; int result = 0; - Bitmap rawData = wImage; - rawData = Window.ConvertToBlackAndWhite(rawData, treshold); + //Bitmap rawData = wImage; + + OcrImage rawData = new OcrImage(wImage); + Bitmap enhancedImage = rawData.Enhance(); TesseractEngine engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default); - var tessImage = Pix.LoadFromMemory(ImageToByte(wImage)); + engine.DefaultPageSegMode = PageSegMode.SingleLine; + engine.SetVariable("tessedit_char_whitelist", "0123456789.:+-LEADRPleadrp"); + + var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage)); Page page = engine.Process(tessImage); - Graphics g = Graphics.FromImage(rawData); + Graphics g = Graphics.FromImage(enhancedImage); // Get the iterator for the page layout using (var iter = page.GetIterator()) { @@ -111,7 +117,7 @@ namespace OCR_Decode // 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)); + //g.DrawRectangle(Pens.Red, new Rectangle(boundingBox.X1, boundingBox.Y1, boundingBox.Width, boundingBox.Height)); } // Get the text for the current element try @@ -125,18 +131,17 @@ namespace OCR_Decode } while (iter.Next(PageIteratorLevel.Word)); } + enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + Regex.Replace(rawResult, "[^0-9A-Za-z]", "") + ".png"); + List rawNumbers; //Removes all non digit chars except for the important ones string cleanedResult = Regex.Replace(rawResult, "[^0-9.:]", ""); + //Splits into minuts seconds miliseconds rawNumbers = cleanedResult.Split('.', ':').ToList(); //removes any empty cells (tho this usually sign of a really bad OCR implementation tbh will have to be fixed higher in the chian) - for (int i = 0; i < rawNumbers.Count;i++) - { - if (rawNumbers[i] == "") - rawNumbers.RemoveAt(i); - } + rawNumbers.RemoveAll(x => ((string)x) == ""); if (rawNumbers.Count == 3) { @@ -154,8 +159,6 @@ namespace OCR_Decode { if (rawNumbers.Count == 1) { - //ss - //if (rawNumbers[0] == "LEADER") try { result = Convert.ToInt32(rawNumbers[0]); diff --git a/OCR_Decode/packages.config b/OCR_Decode/packages.config index cd49cd2..3a24cbb 100644 --- a/OCR_Decode/packages.config +++ b/OCR_Decode/packages.config @@ -1,5 +1,12 @@  + + + + + + +