Cleaned the code a little and the character recognition is now even better
This commit is contained in:
@@ -18,108 +18,25 @@ namespace OCR_Decode
|
|||||||
public override object DecodePng(List<string> DriverList)
|
public override object DecodePng(List<string> DriverList)
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
int[] recommendedTresholds = new int[] { 100, 125, 150, 175, 200 };
|
result = GetStringFromPng();
|
||||||
|
|
||||||
int index = 0;
|
if (!IsADriver(DriverList, result))
|
||||||
while (!IsADriver(DriverList, result))
|
|
||||||
{
|
{
|
||||||
if(index >= recommendedTresholds.Length -1)
|
//I put everything in uppercase to try to lower the chances of bad answers
|
||||||
{
|
result = FindClosestMatch(DriverList.ConvertAll(d => d.ToUpper()), result.ToUpper());
|
||||||
//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;
|
return result;
|
||||||
}
|
}
|
||||||
//This method has been gnerated using ChatGPT
|
private static bool IsADriver(List<string> drivers, string potentialDriver)
|
||||||
public static string FindClosestMatch(List<string> array, string target)
|
|
||||||
{
|
{
|
||||||
var closestMatch = "";
|
bool result = false;
|
||||||
var closestDistance = int.MaxValue;
|
//I cant use drivers.Contains because it has missmatched cases and all
|
||||||
|
foreach (string name in drivers)
|
||||||
foreach (var item in array)
|
|
||||||
{
|
{
|
||||||
var distance = LevenshteinDistance(item, target);
|
if (name.ToUpper() == potentialDriver.ToUpper())
|
||||||
if (distance < closestDistance)
|
result = true;
|
||||||
{
|
|
||||||
closestMatch = item;
|
|
||||||
closestDistance = distance;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return result;
|
||||||
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];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,12 +22,10 @@ namespace OCR_Decode
|
|||||||
{
|
{
|
||||||
Bitmap result = (Bitmap)InputImage.Clone();
|
Bitmap result = (Bitmap)InputImage.Clone();
|
||||||
result = Grayscale(result);
|
result = Grayscale(result);
|
||||||
result = Tresholding(result, 200);
|
|
||||||
result = InvertColors(result);
|
result = InvertColors(result);
|
||||||
|
result = Tresholding(result, 100);
|
||||||
result = Resize(result);
|
result = Resize(result);
|
||||||
//result = Resize(result);
|
result = Dilatation(result, 1);
|
||||||
//result = Dilatation(result, 5);
|
|
||||||
//result = Erode(result,3);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
public static Bitmap Grayscale(Bitmap input)
|
public static Bitmap Grayscale(Bitmap input)
|
||||||
|
|||||||
+81
-52
@@ -16,6 +16,7 @@ namespace OCR_Decode
|
|||||||
private Rectangle _bounds;
|
private Rectangle _bounds;
|
||||||
private Bitmap _image;
|
private Bitmap _image;
|
||||||
private string _name;
|
private string _name;
|
||||||
|
protected static TesseractEngine Engine;
|
||||||
public Rectangle Bounds { get => _bounds; private set => _bounds = value; }
|
public Rectangle Bounds { get => _bounds; private set => _bounds = value; }
|
||||||
public Bitmap Image { get => _image; set => _image = value; }
|
public Bitmap Image { get => _image; set => _image = value; }
|
||||||
public string Name { get => _name; protected set => _name = value; }
|
public string Name { get => _name; protected set => _name = value; }
|
||||||
@@ -36,14 +37,17 @@ namespace OCR_Decode
|
|||||||
{
|
{
|
||||||
Image = image;
|
Image = image;
|
||||||
Bounds = bounds;
|
Bounds = bounds;
|
||||||
|
|
||||||
|
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
||||||
|
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
|
||||||
}
|
}
|
||||||
public virtual Object DecodePng()
|
public virtual Object DecodePng()
|
||||||
{
|
{
|
||||||
return " ";
|
return "NaN";
|
||||||
}
|
}
|
||||||
public virtual Object DecodePng(List<string> drivers)
|
public virtual Object DecodePng(List<string> drivers)
|
||||||
{
|
{
|
||||||
return " ";
|
return "NaN";
|
||||||
}
|
}
|
||||||
public static byte[] ImageToByte(Image img)
|
public static byte[] ImageToByte(Image img)
|
||||||
{
|
{
|
||||||
@@ -53,58 +57,17 @@ namespace OCR_Decode
|
|||||||
return stream.ToArray();
|
return stream.ToArray();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public static bool IsADriver(List<string> 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);
|
|
||||||
|
|
||||||
for (int y = 0; y < inputBmp.Height; y++)
|
|
||||||
{
|
|
||||||
for (int x = 0; x < inputBmp.Width; x++)
|
|
||||||
{
|
|
||||||
Color pixelColor = inputBmp.GetPixel(x, y);
|
|
||||||
if (pixelColor.R <= Treshold && pixelColor.G <= Treshold && pixelColor.B <= Treshold)
|
|
||||||
{
|
|
||||||
pixelColor = Color.FromArgb(0, 0, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pixelColor = Color.FromArgb(255, 255, 255);
|
|
||||||
}
|
|
||||||
result.SetPixel(x, y, pixelColor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
public static int GetTimeFromPng(Bitmap wImage)
|
public static int GetTimeFromPng(Bitmap wImage)
|
||||||
{
|
{
|
||||||
//returns milliseconds
|
//returns milliseconds
|
||||||
string rawResult = "";
|
string rawResult = "";
|
||||||
int treshold = 100;
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
//Bitmap rawData = wImage;
|
Bitmap enhancedImage = new OcrImage(wImage).Enhance();
|
||||||
|
|
||||||
OcrImage rawData = new OcrImage(wImage);
|
|
||||||
Bitmap enhancedImage = rawData.Enhance();
|
|
||||||
|
|
||||||
TesseractEngine engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
|
|
||||||
engine.DefaultPageSegMode = PageSegMode.SingleLine;
|
|
||||||
engine.SetVariable("tessedit_char_whitelist", "0123456789.:+-LEADRPleadrp");
|
|
||||||
|
|
||||||
var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage));
|
var tessImage = Pix.LoadFromMemory(ImageToByte(enhancedImage));
|
||||||
|
|
||||||
Page page = engine.Process(tessImage);
|
Page page = Engine.Process(tessImage);
|
||||||
Graphics g = Graphics.FromImage(enhancedImage);
|
Graphics g = Graphics.FromImage(enhancedImage);
|
||||||
// Get the iterator for the page layout
|
// Get the iterator for the page layout
|
||||||
using (var iter = page.GetIterator())
|
using (var iter = page.GetIterator())
|
||||||
@@ -113,12 +76,6 @@ namespace OCR_Decode
|
|||||||
iter.Begin();
|
iter.Begin();
|
||||||
do
|
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
|
// Get the text for the current element
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -136,6 +93,7 @@ namespace OCR_Decode
|
|||||||
List<string> rawNumbers;
|
List<string> rawNumbers;
|
||||||
|
|
||||||
//Removes all non digit chars except for the important ones
|
//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.:]", "");
|
string cleanedResult = Regex.Replace(rawResult, "[^0-9.:]", "");
|
||||||
|
|
||||||
//Splits into minuts seconds miliseconds
|
//Splits into minuts seconds miliseconds
|
||||||
@@ -176,8 +134,79 @@ namespace OCR_Decode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
page.Dispose();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
protected string GetStringFromPng()
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
|
||||||
|
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];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user