Increased OCR performances

This commit is contained in:
2023-04-11 10:44:29 +02:00
parent 8796fed916
commit fde3bcaae6
14 changed files with 270 additions and 194 deletions
+90
View File
@@ -0,0 +1,90 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace OCR_Decode
{
public class DriverData
{
public bool DRS; //True = Drs is opened
public int GapToLeader; //In ms
public int LapTime; //In ms
public string Name; //Ex: LECLERC
public int Position; //Ex: 1
public int Sector1; //in ms
public int Sector2; //in ms
public int Sector3; //in ms
public Tyre CurrentTyre;//Ex Soft 11 laps
public DriverData(bool dRS, int gapToLeader, int lapTime, string name, int position, int sector1, int sector2, int sector3, Tyre tyre)
{
DRS = dRS;
GapToLeader = gapToLeader;
LapTime = lapTime;
Name = name;
Position = position;
Sector1 = sector1;
Sector2 = sector2;
Sector3 = sector3;
CurrentTyre = tyre;
}
public DriverData()
{
DRS = false;
GapToLeader = -1;
LapTime = -1;
Name = "Unknown";
Position = -1;
Sector1 = -1;
Sector2 = -1;
Sector3 = -1;
CurrentTyre = new Tyre(Tyre.Type.Undefined,-1);
}
public override string ToString()
{
string result = "";
//Position
result += "Position : " + Position +Environment.NewLine;
//Gap
result += "Gap to leader : " + Reader.ConvertMsToTime(GapToLeader) + Environment.NewLine;
//LapTime
result += "Lap time : " + Reader.ConvertMsToTime(LapTime) + Environment.NewLine;
//DRS
result += "DRS : " + DRS + Environment.NewLine;
//Tyres
result += "Uses " + CurrentTyre.Coumpound + " tyre " + CurrentTyre.NumberOfLaps + " laps old" + Environment.NewLine;
//Name
result += "Driver name : " + Name +Environment.NewLine;
//Sector 1
result += "Sector 1 : " + Reader.ConvertMsToTime(Sector1) + Environment.NewLine;
//Sector 1
result += "Sector 2 : " + Reader.ConvertMsToTime(Sector2) + Environment.NewLine;
//Sector 1
result += "Sector 3 : " + Reader.ConvertMsToTime(Sector3) + Environment.NewLine;
return result;
}
}
public struct Tyre
{
public enum Type
{
Soft,
Medium,
Hard,
Inter,
Wet,
Undefined
}
public Type Coumpound;
public int NumberOfLaps;
public Tyre(Type type, int laps)
{
Coumpound = type;
NumberOfLaps = laps;
}
}
}
+5 -2
View File
@@ -28,7 +28,7 @@ namespace OCR_Decode
if (greenValue > EmptyDrsGreenValue + EmptyDrsGreenValue / 100 * 30) if (greenValue > EmptyDrsGreenValue + EmptyDrsGreenValue / 100 * 30)
result = true; result = true;
WindowImage.Save(Reader.DEBUG_DUMP_FOLDER + "DRS" + result + ".png"); //WindowImage.Save(Reader.DEBUG_DUMP_FOLDER + "DRS" + result + ".png");
return result; return result;
} }
@@ -68,7 +68,9 @@ namespace OCR_Decode
} }
public Rectangle GetBox() public Rectangle GetBox()
{ {
using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage)); var tessImage = Pix.LoadFromMemory(ImageToByte(WindowImage));
Engine.SetVariable("tessedit_char_whitelist", ""); Engine.SetVariable("tessedit_char_whitelist", "");
Page page = Engine.Process(tessImage); Page page = Engine.Process(tessImage);
@@ -94,3 +96,4 @@ namespace OCR_Decode
} }
} }
} }
}
+6 -1
View File
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tesseract;
namespace OCR_Decode namespace OCR_Decode
{ {
@@ -15,8 +16,12 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Gap); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Gap,Engine);
return result; return result;
} }
} }
} }
}
+5 -1
View File
@@ -16,8 +16,12 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
int result = await GetTimeFromPng(WindowImage,OcrImage.WindowType.LapTime); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.LapTime,Engine);
return result; return result;
} }
} }
} }
}
+5 -1
View File
@@ -17,8 +17,11 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng(List<string> DriverList) public override async Task<object> DecodePng(List<string> DriverList)
{ {
using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
string result = ""; string result = "";
result = await GetStringFromPng(WindowImage); result = await GetStringFromPng(WindowImage,Engine);
if (!IsADriver(DriverList, result)) if (!IsADriver(DriverList, result))
{ {
@@ -27,6 +30,7 @@ namespace OCR_Decode
} }
return result; return result;
} }
}
private static bool IsADriver(List<string> drivers, string potentialDriver) private static bool IsADriver(List<string> drivers, string potentialDriver)
{ {
bool result = false; bool result = false;
+7 -2
View File
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tesseract;
namespace OCR_Decode namespace OCR_Decode
{ {
@@ -15,7 +16,10 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
string result = await GetStringFromPng(WindowImage,"0123456789"); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
string result = await GetStringFromPng(WindowImage,Engine, "0123456789");
int position; int position;
try try
@@ -25,9 +29,10 @@ namespace OCR_Decode
catch catch
{ {
position = -1; position = -1;
WindowImage.Save(Reader.DEBUG_DUMP_FOLDER + "FailedPosition"+".png"); //WindowImage.Save(Reader.DEBUG_DUMP_FOLDER + "FailedPosition" + ".png");
} }
return position; return position;
} }
} }
} }
}
+6 -1
View File
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tesseract;
namespace OCR_Decode namespace OCR_Decode
{ {
@@ -15,8 +16,12 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
int result = await GetTimeFromPng(WindowImage,OcrImage.WindowType.Sector,Engine);
return result; return result;
} }
} }
} }
}
+6 -1
View File
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tesseract;
namespace OCR_Decode namespace OCR_Decode
{ {
@@ -15,8 +16,12 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector,Engine);
return result; return result;
} }
} }
} }
}
+6 -1
View File
@@ -4,6 +4,7 @@ using System.Drawing;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Tesseract;
namespace OCR_Decode namespace OCR_Decode
{ {
@@ -15,8 +16,12 @@ namespace OCR_Decode
} }
public override async Task<object> DecodePng() public override async Task<object> DecodePng()
{ {
int result = await GetTimeFromPng(WindowImage,OcrImage.WindowType.Sector); using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
int result = await GetTimeFromPng(WindowImage, OcrImage.WindowType.Sector,Engine);
return result; return result;
} }
} }
} }
}
+8 -24
View File
@@ -31,12 +31,14 @@ namespace OCR_Decode
{ {
Bitmap tyreZone = GetSmallBitmapFromBigOne(WindowImage, FindTyreZone()); Bitmap tyreZone = GetSmallBitmapFromBigOne(WindowImage, FindTyreZone());
tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "ZONE" + ".png"); //tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "ZONE" + ".png");
Tyre.Type type = Tyre.Type.Undefined; Tyre.Type type = Tyre.Type.Undefined;
int laps = -1; int laps = -1;
using (var Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default))
{
Engine.DefaultPageSegMode = PageSegMode.SingleLine;
//MHIWsmhiw so we can detect Soft Medium Hard Inters and Wet tyres //MHIWsmhiw so we can detect Soft Medium Hard Inters and Wet tyres
string text = await GetStringFromPng(tyreZone, "SMHIW", OcrImage.WindowType.Tyre); string text = await GetStringFromPng(tyreZone, Engine, "SMHIW", OcrImage.WindowType.Tyre);
if (text.Length == 1 && text != "") if (text.Length == 1 && text != "")
{ {
//We found a tire letter //We found a tire letter
@@ -66,7 +68,7 @@ namespace OCR_Decode
} }
else else
{ {
string number = await GetStringFromPng(tyreZone, "0123456789", OcrImage.WindowType.Tyre); string number = await GetStringFromPng(tyreZone, Engine, "0123456789", OcrImage.WindowType.Tyre);
try try
{ {
laps = Convert.ToInt32(number); laps = Convert.ToInt32(number);
@@ -78,9 +80,10 @@ namespace OCR_Decode
type = GetTyreTypeFromColor(OcrImage.GetAvgColorFromBitmap(OcrImage.Resize(tyreZone))); type = GetTyreTypeFromColor(OcrImage.GetAvgColorFromBitmap(OcrImage.Resize(tyreZone)));
} }
tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + type + "Laps" + laps + '#' + rnd.Next(0, 1000) + ".png"); //tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + type + "Laps" + laps + '#' + rnd.Next(0, 1000) + ".png");
return new Tyre(type, laps); return new Tyre(type, laps);
} }
}
private Rectangle FindTyreZone() private Rectangle FindTyreZone()
{ {
Bitmap bmp = WindowImage; Bitmap bmp = WindowImage;
@@ -143,23 +146,4 @@ namespace OCR_Decode
return type; return type;
} }
} }
struct Tyre
{
public enum Type
{
Soft,
Medium,
Hard,
Inter,
Wet,
Undefined
}
public Type Coumpound;
public int NumberOfLaps;
public Tyre(Type type, int laps)
{
Coumpound = type;
NumberOfLaps = laps;
}
}
} }
+1
View File
@@ -107,6 +107,7 @@
</Reference> </Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="DriverData.cs" />
<Compile Include="DriverDrsWindow.cs" /> <Compile Include="DriverDrsWindow.cs" />
<Compile Include="DriverGapToLeaderWindow.cs" /> <Compile Include="DriverGapToLeaderWindow.cs" />
<Compile Include="DriverLapTimeWindow.cs" /> <Compile Include="DriverLapTimeWindow.cs" />
+4 -50
View File
@@ -174,7 +174,7 @@ namespace OCR_Decode
{ {
string result = ""; string result = "";
ChangeImage(idImage); ChangeImage(idImage);
List<List<Object>> mainResults = new List<List<Object>>(); List<DriverData> mainResults = new List<DriverData>();
//Decode //Decode
for (int mainZoneId = 0; mainZoneId < MainZones.Count; mainZoneId++) for (int mainZoneId = 0; mainZoneId < MainZones.Count; mainZoneId++)
@@ -183,11 +183,10 @@ namespace OCR_Decode
{ {
case 0: case 0:
//Main Zone //Main Zone
//Parallel.ForEach(MainZones[mainZoneId].Zones, z =>
foreach (Zone z in MainZones[mainZoneId].Zones) foreach (Zone z in MainZones[mainZoneId].Zones)
{ {
mainResults.Add(await z.Decode(Drivers)); mainResults.Add(await z.Decode(Drivers));
}//); }
break; break;
//Next there will be the title and laps added //Next there will be the title and laps added
} }
@@ -195,56 +194,11 @@ namespace OCR_Decode
} }
//Display //Display
foreach (List<Object> objects in mainResults) foreach (DriverData driver in mainResults)
{ {
for (int objId = 0; objId < objects.Count; objId++) result += driver.ToString();
{
switch (objId)
{
case 0:
//Position
result += "Position : " + (int)objects[objId] + " ";
break;
case 1:
//Gap
result += "Gap to leader : " + ConvertMsToTime((int)objects[objId]) + " ";
break;
case 2:
//LapTime
result += "Lap time : " + ConvertMsToTime((int)objects[objId]) + " ";
break;
case 3:
//DRS
result += "DRS : " + (bool)objects[objId] + "";
break;
case 4:
//Tyres
Tyre tyre = (Tyre)objects[objId];
result += "Uses " + tyre.Coumpound + " tyre for " + tyre.NumberOfLaps + " laps";
break;
case 5:
//Name
result += "Driver name : " + (string)objects[objId] + " ";
break;
case 6:
//Sector 1
result += "Sector 1 : " + ConvertMsToTime((int)objects[objId]) + " ";
break;
case 7:
//Sector 1
result += "Sector 2 : " + ConvertMsToTime((int)objects[objId]) + " ";
break;
case 8:
//Sector 1
result += "Sector 3 : " + ConvertMsToTime((int)objects[objId]) + " ";
break;
default:
result += "Unknown source : " + objects[objId].ToString();
break;
}
result += Environment.NewLine; result += Environment.NewLine;
} }
}
return result; return result;
} }
+8 -7
View File
@@ -16,7 +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 = null; //protected static TesseractEngine Engine = null;
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; }
@@ -37,12 +37,13 @@ namespace OCR_Decode
{ {
Image = image; Image = image;
Bounds = bounds; Bounds = bounds;
/*
if (Engine == null) if (Engine == null)
{ {
Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default); Engine = new TesseractEngine(TESS_DATA_FOLDER.FullName, "eng", EngineMode.Default);
Engine.DefaultPageSegMode = PageSegMode.SingleLine; Engine.DefaultPageSegMode = PageSegMode.SingleLine;
} }
*/
} }
public virtual async Task<Object> DecodePng() public virtual async Task<Object> DecodePng()
{ {
@@ -60,7 +61,7 @@ namespace OCR_Decode
return stream.ToArray(); return stream.ToArray();
} }
} }
public static async Task<int> GetTimeFromPng(Bitmap wImage,OcrImage.WindowType type) public static async Task<int> GetTimeFromPng(Bitmap wImage,OcrImage.WindowType type, TesseractEngine Engine)
{ {
string rawResult = ""; string rawResult = "";
int result = 0; int result = 0;
@@ -107,7 +108,7 @@ namespace OCR_Decode
} while (iter.Next(PageIteratorLevel.Word)); } while (iter.Next(PageIteratorLevel.Word));
} }
enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + Regex.Replace(rawResult, "[^0-9A-Za-z]", "") + ".png"); //enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + Regex.Replace(rawResult, "[^0-9A-Za-z]", "") + ".png");
List<string> rawNumbers; List<string> rawNumbers;
@@ -156,7 +157,7 @@ namespace OCR_Decode
page.Dispose(); page.Dispose();
return result; return result;
} }
public static async Task<string> GetStringFromPng(Bitmap image,string allowedChars = "",OcrImage.WindowType windowType = OcrImage.WindowType.Text) public static async Task<string> GetStringFromPng(Bitmap image, TesseractEngine Engine, string allowedChars = "",OcrImage.WindowType windowType = OcrImage.WindowType.Text)
{ {
string result = ""; string result = "";
@@ -174,6 +175,7 @@ namespace OCR_Decode
result += iter.GetText(PageIteratorLevel.Word); result += iter.GetText(PageIteratorLevel.Word);
} while (iter.Next(PageIteratorLevel.Word)); } while (iter.Next(PageIteratorLevel.Word));
} }
/*
if (allowedChars.Contains("S")) if (allowedChars.Contains("S"))
{ {
enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + result +".png"); enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + result +".png");
@@ -182,8 +184,7 @@ namespace OCR_Decode
{ {
enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + result +".png"); enhancedImage.Save(Reader.DEBUG_DUMP_FOLDER + result +".png");
} }
*/
page.Dispose(); page.Dispose();
return result; return result;
} }
+21 -11
View File
@@ -62,20 +62,30 @@ namespace OCR_Decode
{ {
Windows.Add(window); Windows.Add(window);
} }
public virtual async Task<List<Object>> Decode(List<string> drivers) public virtual async Task<DriverData> Decode(List<string> drivers)
{ {
List<Object> result = new List<Object>(); DriverData result = new DriverData();
foreach (Window w in Windows) Parallel.ForEach(Windows,async w =>
{ {
if (w is DriverNameWindow) if (w is DriverNameWindow)
{ result.Name = (string)await (w as DriverNameWindow).DecodePng(drivers);
result.Add(await (w as DriverNameWindow).DecodePng(drivers)); if (w is DriverDrsWindow)
} result.DRS = (bool)await (w as DriverDrsWindow).DecodePng();
else if (w is DriverGapToLeaderWindow)
{ result.GapToLeader = (int)await (w as DriverGapToLeaderWindow).DecodePng();
result.Add(await w.DecodePng()); if (w is DriverLapTimeWindow)
} result.LapTime = (int)await (w as DriverLapTimeWindow).DecodePng();
} if (w is DriverPositionWindow)
result.Position = (int)await (w as DriverPositionWindow).DecodePng();
if (w is DriverSector1Window)
result.Sector1 = (int)await (w as DriverSector1Window).DecodePng();
if (w is DriverSector2Window)
result.Sector2 = (int)await (w as DriverSector2Window).DecodePng();
if (w is DriverSector3Window)
result.Sector3 = (int)await (w as DriverSector3Window).DecodePng();
if (w is DriverTyresWindow)
result.CurrentTyre = (Tyre)await (w as DriverTyresWindow).DecodePng();
});
return result; return result;
} }
} }