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; using System.Drawing.Imaging; namespace OCR_Decode { //AT LEAST PART OF THIS CLASS HAVE BEEN CREATED USING CHATGPT //Just so you know public class OcrImage { Bitmap InputImage; public enum WindowType { LapTime, Text, Sector, Gap, Tyre, } public OcrImage(Bitmap inputImage) { InputImage = inputImage; } public Bitmap Enhance(WindowType type = WindowType.Text) { Bitmap result = (Bitmap)InputImage.Clone(); switch (type) { case WindowType.LapTime: result = Grayscale(result); result = InvertColors(result); result = Tresholding(result, 165); result = Resize(result); result = Resize(result); break; case WindowType.Text: result = Grayscale(result); result = InvertColors(result); result = Tresholding(result, 165); result = Resize(result); result = Dilatation(result, 1); break; case WindowType.Tyre: //result = RemoveBG(result); result = RemoveUseless(result); result = Resize(result); result = Resize(result); result = Resize(result); result = Dilatation(result, 1); break; default: result = Tresholding(result, 165); result = Resize(result); result = Resize(result); result = Erode(result, 1); break; } //result = Dilatation(result, 1); return result; } public static Bitmap Grayscale(Bitmap input) { Bitmap bmp = input; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); byte blue = pixel[0]; byte green = pixel[1]; byte red = pixel[2]; int gray = (int)(red * 0.3 + green * 0.59 + blue * 0.11); pixel[0] = pixel[1] = pixel[2] = (byte)gray; } } } bmp.UnlockBits(bmpData); return bmp; } public static Bitmap Tresholding(Bitmap input, int threshold) { Bitmap bmp = input; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); byte blue = pixel[0]; byte green = pixel[1]; byte red = pixel[2]; int gray = (int)(red * 0.3 + green * 0.59 + blue * 0.11); int value = gray < threshold ? 0 : 255; pixel[0] = pixel[1] = pixel[2] = (byte)value; } } } bmp.UnlockBits(bmpData); return bmp; } public static Bitmap RemoveBG(Bitmap input) { Color limitColor = Color.FromArgb(0x50, 0x50, 0x50); Bitmap bmp = input; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); int B = pixel[0]; int G = pixel[1]; int R = pixel[2]; if (R <= limitColor.R && G <= limitColor.G && B <= limitColor.B) pixel[0] = pixel[1] = pixel[2] = 0; } } } bmp.UnlockBits(bmpData); return bmp; } public unsafe static Bitmap RemoveUseless(Bitmap bmp) { bmp = RemoveBG(bmp); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); List pixelsToRemove = new List(); bool fromBorder = true; for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); int B = pixel[0]; int G = pixel[1]; int R = pixel[2]; if (fromBorder && B < 0x10 && G < 0x10 && R < 0x10) { pixelsToRemove.Add(x); } else { fromBorder = false; } } fromBorder = true; for (int x = bmp.Width - 1; x > 0; x--) { byte* pixel = currentLine + (x * bytesPerPixel); int B = pixel[0]; int G = pixel[1]; int R = pixel[2]; if (fromBorder && B < 0x10 && G < 0x10 && R < 0x10) { pixelsToRemove.Add(x); } else { fromBorder = false; } } foreach (int pxPos in pixelsToRemove) { byte* pixel = currentLine + (pxPos * bytesPerPixel); pixel[0] = 0xFF; pixel[1] = 0xFF; pixel[2] = 0xFF; } } //NOW REMOVING THE COLOR Color limitColor = Color.FromArgb(0x50, 0x50, 0x50); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); int B = pixel[0]; int G = pixel[1]; int R = pixel[2]; //We remove the background pixels if (R >= limitColor.R || G >= limitColor.G || B >= limitColor.B) { pixel[0] = 0xFF; pixel[1] = 0xFF; pixel[2] = 0xFF; } } } bmp.UnlockBits(bmpData); return bmp; } public static Color GetAvgColorFromBitmap(Bitmap bmp) { Color limitColor = Color.FromArgb(0x50, 0x50, 0x50); Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; int totR = 0; int totG = 0; int totB = 0; int totPixels = 1; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); int B = pixel[0]; int G = pixel[1]; int R = pixel[2]; //We remove the background pixels if (R >= limitColor.R || G >= limitColor.G || B >= limitColor.B) { totPixels++; totB += pixel[0]; totG += pixel[1]; totR += pixel[2]; } } } } bmp.UnlockBits(bmpData); return Color.FromArgb(255, Convert.ToInt32((float)totR / (float)totPixels), Convert.ToInt32((float)totG / (float)totPixels), Convert.ToInt32((float)totB / (float)totPixels)); } public static Bitmap InvertColors(Bitmap input) { Bitmap bmp = input; Rectangle rect = new Rectangle(0, 0, bmp.Width, bmp.Height); BitmapData bmpData = bmp.LockBits(rect, ImageLockMode.ReadWrite, bmp.PixelFormat); int bytesPerPixel = Bitmap.GetPixelFormatSize(bmp.PixelFormat) / 8; unsafe { byte* ptr = (byte*)bmpData.Scan0.ToPointer(); for (int y = 0; y < bmp.Height; y++) { byte* currentLine = ptr + (y * bmpData.Stride); for (int x = 0; x < bmp.Width; x++) { byte* pixel = currentLine + (x * bytesPerPixel); pixel[0] = (byte)(255 - pixel[0]); pixel[1] = (byte)(255 - pixel[1]); pixel[2] = (byte)(255 - pixel[2]); } } } bmp.UnlockBits(bmpData); return bmp; } 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; } } }