224 lines
7.4 KiB
C#
224 lines
7.4 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;
|
|
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;
|
|
|
|
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
|
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
|
|
}
|
|
public virtual Object DecodePng()
|
|
{
|
|
return "NaN";
|
|
}
|
|
public virtual 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 int GetTimeFromPng(Bitmap wImage)
|
|
{
|
|
string rawResult = "";
|
|
int result = 0;
|
|
|
|
Engine.SetVariable("tessedit_char_whitelist", "0123456789:.");
|
|
|
|
Bitmap enhancedImage = new OcrImage(wImage).Enhance();
|
|
|
|
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;
|
|
|
|
//Removes all non digit chars except for the important ones
|
|
//We will need to change this when trying to see the Leader and Lap texts
|
|
//string cleanedResult = 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;
|
|
}
|
|
protected string GetStringFromPng(bool onlyDigit = false)
|
|
{
|
|
string result = "";
|
|
|
|
if (onlyDigit)
|
|
{
|
|
Engine.SetVariable("tessedit_char_whitelist", "0123456789");
|
|
}
|
|
else
|
|
{
|
|
Engine.SetVariable("tessedit_char_whitelist", "");
|
|
}
|
|
|
|
|
|
Bitmap rawData = WindowImage;
|
|
Bitmap enhancedImage = new OcrImage(rawData).Enhance();
|
|
|
|
Page page = Engine.Process(enhancedImage);
|
|
using (var iter = page.GetIterator())
|
|
{
|
|
iter.Begin();
|
|
do
|
|
{
|
|
result += iter.GetText(PageIteratorLevel.Word);
|
|
} while (iter.Next(PageIteratorLevel.Word));
|
|
}
|
|
page.Dispose();
|
|
return result;
|
|
}
|
|
//This method has been gnerated using ChatGPT
|
|
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 is a tool to be able to compare strings
|
|
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];
|
|
}
|
|
}
|
|
}
|