Files
OCR_Decode/OCR_Decode/Window.cs
T
2023-04-11 10:44:29 +02:00

251 lines
8.6 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.IO;
using Tesseract;
using System.Text.RegularExpressions;
using System.Drawing.Drawing2D;
namespace OCR_Decode
{
public class Window
{
private Rectangle _bounds;
private Bitmap _image;
private string _name;
//protected static TesseractEngine Engine = null;
public Rectangle Bounds { get => _bounds; private set => _bounds = value; }
public Bitmap Image { get => _image; set => _image = value; }
public string Name { get => _name; protected set => _name = value; }
public static DirectoryInfo TESS_DATA_FOLDER = new DirectoryInfo(@"C:\Users\Moi\Pictures\SeleniumScreens\TessData");
public Bitmap WindowImage
{
get
{
Bitmap sample = new Bitmap(Bounds.Width, Bounds.Height);
Graphics g = Graphics.FromImage(sample);
g.DrawImage(Image, new Rectangle(0, 0, sample.Width, sample.Height), Bounds, GraphicsUnit.Pixel);
return sample;
}
}
public Window(Bitmap image, Rectangle bounds)
{
Image = image;
Bounds = bounds;
/*
if (Engine == null)
{
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
}
*/
}
public virtual async Task<Object> DecodePng()
{
return "NaN";
}
public virtual async Task<Object> DecodePng(List<string> drivers)
{
return "NaN";
}
public static byte[] ImageToByte(Image img)
{
using (var stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
return stream.ToArray();
}
}
public static async Task<int> GetTimeFromPng(Bitmap wImage,OcrImage.WindowType type, TesseractEngine Engine)
{
string rawResult = "";
int result = 0;
switch (type)
{
case OcrImage.WindowType.Sector:
Engine.SetVariable("tessedit_char_whitelist", "0123456789.");
break;
case OcrImage.WindowType.LapTime:
Engine.SetVariable("tessedit_char_whitelist", "0123456789.:");
break;
case OcrImage.WindowType.Gap:
Engine.SetVariable("tessedit_char_whitelist", "0123456789.+");
break;
default:
Engine.SetVariable("tessedit_char_whitelist", "");
break;
}
Bitmap enhancedImage = new OcrImage(wImage).Enhance(type);
var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage));
Page page = Engine.Process(tessImage);
Graphics g = Graphics.FromImage(enhancedImage);
// Get the iterator for the page layout
using (var iter = page.GetIterator())
{
// Loop over the elements of the page layout
iter.Begin();
do
{
// Get the text for the current element
try
{
rawResult += iter.GetText(PageIteratorLevel.Word);
}
catch
{
//nothing we just dont add it if its not a number
}
} while (iter.Next(PageIteratorLevel.Word));
}
//enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + Regex.Replace(rawResult, "[^0-9A-Za-z]", "") + ".png");
List<string> rawNumbers;
//In the gaps we can find '+' but we dont care about it its redondant
if(type == OcrImage.WindowType.Gap)
rawResult = Regex.Replace(rawResult, "[^0-9.:]", "");
//Splits into minuts seconds miliseconds
rawNumbers = rawResult.Split('.', ':').ToList<string>();
//removes any empty cells (tho this usually sign of a really bad OCR implementation tbh will have to be fixed higher in the chian)
rawNumbers.RemoveAll(x => ((string)x) == "");
if (rawNumbers.Count == 3)
{
//mm:ss:ms
result = (Convert.ToInt32(rawNumbers[0]) * 1000 * 60) + (Convert.ToInt32(rawNumbers[1]) * 1000) + Convert.ToInt32(rawNumbers[2]);
}
else
{
if (rawNumbers.Count == 2)
{
//ss:ms
result = (Convert.ToInt32(rawNumbers[0]) * 1000) + Convert.ToInt32(rawNumbers[1]);
}
else
{
if (rawNumbers.Count == 1)
{
try
{
result = Convert.ToInt32(rawNumbers[0]);
}
catch
{
//It can be because the input is empty or because its the LEADER bracket
result = 0;
}
}
else
{
//Auuuugh
result = 0;
}
}
}
page.Dispose();
return result;
}
public static async Task<string> GetStringFromPng(Bitmap image, TesseractEngine Engine, string allowedChars = "",OcrImage.WindowType windowType = OcrImage.WindowType.Text)
{
string result = "";
Engine.SetVariable("tessedit_char_whitelist", allowedChars);
Bitmap rawData = image;
Bitmap enhancedImage = new OcrImage(rawData).Enhance(windowType);
Page page = Engine.Process(enhancedImage);
using (var iter = page.GetIterator())
{
iter.Begin();
do
{
result += iter.GetText(PageIteratorLevel.Word);
} while (iter.Next(PageIteratorLevel.Word));
}
/*
if (allowedChars.Contains("S"))
{
enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + result +".png");
}
else
{
enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + result +".png");
}
*/
page.Dispose();
return result;
}
protected Bitmap GetSmallBitmapFromBigOne(Bitmap bmp, Rectangle rectangle)
{
Bitmap sample = new Bitmap(rectangle.Width, rectangle.Height);
Graphics g = Graphics.FromImage(sample);
g.DrawImage(bmp, new Rectangle(0, 0, sample.Width, sample.Height), rectangle, GraphicsUnit.Pixel);
return sample;
}
protected static string FindClosestMatch(List<string> 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;
}
//This method has been generated with the help of ChatGPT
protected 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];
}
}
}