Fixed the slowest drivers windows and cleaned some of the code
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : ConfigurationTool.cs
|
||||
/// Brief : Class that contains all the methods needed to create a config file for the OCR
|
||||
/// Version : 0.1
|
||||
/// Brief : Class that contains all the methods used to create config files for the main programm
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -23,7 +23,11 @@ namespace Test_Merge
|
||||
public const int NUMBER_OF_DRIVERS = 20;
|
||||
public const int NUMBER_OF_ZONES = 9;
|
||||
public const string CONFIGS_FOLDER_NAME = "./Presets/";
|
||||
|
||||
/// <summary>
|
||||
/// Creates the configuration tool. It can only be created if you already have the dimensions of the main zone
|
||||
/// </summary>
|
||||
/// <param name="fullImage">The full image coming from the F1TV Data Channel</param>
|
||||
/// <param name="mainZoneDimensions">The dimensions of the zone where all the drivers data are situated</param>
|
||||
public ConfigurationTool(Bitmap fullImage, Rectangle mainZoneDimensions)
|
||||
{
|
||||
MainZone = new Zone(fullImage, mainZoneDimensions,"Main");
|
||||
@@ -54,9 +58,9 @@ namespace Test_Merge
|
||||
|
||||
JsonObject jsonFileObject = new JsonObject();
|
||||
|
||||
//Creating the mainZone object
|
||||
|
||||
//Creates the mainZone object
|
||||
JsonObject mainZoneObject = new JsonObject();
|
||||
|
||||
mainZoneObject.Add("x",MainZone.Bounds.X);
|
||||
mainZoneObject.Add("y",MainZone.Bounds.Y);
|
||||
mainZoneObject.Add("width",MainZone.Bounds.Width);
|
||||
@@ -64,6 +68,7 @@ namespace Test_Merge
|
||||
|
||||
JsonArray driverZonesArray = new JsonArray();
|
||||
|
||||
//Creates all the subzones that contain driver infos
|
||||
int DriverID = 0;
|
||||
foreach (Zone driverZone in MainZone.Zones)
|
||||
{
|
||||
@@ -76,8 +81,10 @@ namespace Test_Merge
|
||||
driverZoneObject.Add("height", driverZone.Bounds.Height);
|
||||
|
||||
JsonArray windowsArray = new JsonArray();
|
||||
|
||||
JsonObject windowObject = new JsonObject();
|
||||
|
||||
//Creates all the windows of the current driver zone
|
||||
//Note : We store ALL the windows and zones in the JSON because they are not spaced exactly the same on the main zone
|
||||
foreach (Window window in driverZone.Windows)
|
||||
{
|
||||
windowObject.Add(window.Name, new JsonObject {
|
||||
@@ -149,35 +156,35 @@ namespace Test_Merge
|
||||
driverZone.AddWindow(new DriverPositionWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 2:
|
||||
//First zone should be the Gap to leader
|
||||
//Second zone should be the Gap to leader
|
||||
driverZone.AddWindow(new DriverGapToLeaderWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 3:
|
||||
//First zone should be the driver's Lap Time
|
||||
//Third zone should be the driver's Lap Time
|
||||
driverZone.AddWindow(new DriverLapTimeWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 4:
|
||||
//First zone should be the driver's DRS status
|
||||
//Fourth zone should be the driver's DRS status
|
||||
driverZone.AddWindow(new DriverDrsWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 5:
|
||||
//First zone should be the driver's Tyre's informations
|
||||
//Fifth zone should be the driver's Tyre's informations
|
||||
driverZone.AddWindow(new DriverTyresWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 6:
|
||||
//First zone should be the driver's Name
|
||||
//Sixth zone should be the driver's Name
|
||||
driverZone.AddWindow(new DriverNameWindow(driverZone.ZoneImage, rectangles[i - 1], false));
|
||||
break;
|
||||
case 7:
|
||||
//First zone should be the driver's First Sector
|
||||
//Seventh zone should be the driver's First Sector
|
||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 1, false));
|
||||
break;
|
||||
case 8:
|
||||
//First zone should be the driver's Second Sector
|
||||
//Zone number eight should be the driver's Second Sector
|
||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 2, false));
|
||||
break;
|
||||
case 9:
|
||||
//First zone should be the driver's Position Sector
|
||||
//Zone number nine should be the driver's Position Sector
|
||||
driverZone.AddWindow(new DriverSectorWindow(driverZone.ZoneImage, rectangles[i - 1], 3, false));
|
||||
break;
|
||||
}
|
||||
@@ -186,6 +193,7 @@ namespace Test_Merge
|
||||
}
|
||||
/// <summary>
|
||||
/// This will automatically create all the driver zones at the correct places if the main zone has been weel positionned
|
||||
/// You cant just divide the image by the number of pilots or it will be messy and inconsistent at the end (Garbage in Garbage Out)
|
||||
/// </summary>
|
||||
public void AutoCalibrate()
|
||||
{
|
||||
@@ -197,6 +205,8 @@ namespace Test_Merge
|
||||
var tessImage = Pix.LoadFromMemory(Window.ImageToByte(image));
|
||||
|
||||
Page page = engine.Process(tessImage);
|
||||
//Runs a quick OCR detection. Not to detect any content but just to detect where is all the text positionned.
|
||||
//For each row it decides the best Zone location and adds it to the Driver zone list
|
||||
using (var iter = page.GetIterator())
|
||||
{
|
||||
iter.Begin();
|
||||
@@ -205,7 +215,6 @@ namespace Test_Merge
|
||||
Rect boundingBox;
|
||||
if (iter.TryGetBoundingBox(PageIteratorLevel.Word, out boundingBox))
|
||||
{
|
||||
//var text = iter.GetText(PageIteratorLevel.Word).ToUpper();
|
||||
//We remove all the rectangles that are definitely too big
|
||||
if (boundingBox.Height < image.Height / NUMBER_OF_DRIVERS)
|
||||
{
|
||||
@@ -244,7 +253,6 @@ namespace Test_Merge
|
||||
//We add the driver zones
|
||||
Zone driverZone = new Zone(MainZone.ZoneImage, windowRectangle, "DriverZone");
|
||||
MainZone.AddZone(driverZone);
|
||||
|
||||
//driverZone.ZoneImage.Save("Driver" + i+".png");
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using System;
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 30/05/2023
|
||||
/// File : DataWrapper.cs
|
||||
/// Brief : Class that is used to interface between the main Form (vue) and the Storage (wich is a class that wraps the sqlite database, so the model) its almost MVC :D
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -13,11 +19,22 @@ namespace Test_Merge
|
||||
private Reader Reader;
|
||||
private SqliteStorage Storage;
|
||||
List<List<DriverData>> LiveDriverDataLogs = new List<List<DriverData>>();
|
||||
//Note : It could be usefull to get the mainForm at the start of the programm and not have to take it in half of the methods.
|
||||
/// <summary>
|
||||
/// Constructs a new DataWrapper. It needs the config file so it can create a Reader, It also needs a first screenshot for the same reason
|
||||
/// </summary>
|
||||
/// <param name="configFile">The JSON config file that is created by the configuration tool</param>
|
||||
/// <param name="screenshot">A screenshot of the </param>
|
||||
public DataWrapper(string configFile, Bitmap screenshot)
|
||||
{
|
||||
Reader = new Reader(configFile, screenshot, true);
|
||||
//The Storage is here and on the Reader. It seems bad but it is ok as we dont use it at all to insert data and are only using it here to read some. The reader takes care of the inserts (Note: We could technically do both here but I did not find it usefull to transfer everything here)
|
||||
Storage = Reader.Storage;
|
||||
}
|
||||
/// <summary>
|
||||
/// Refreshes the controller so it has the latest driver datas (Be sure to call it everytime you need to use any other method and expects the data to be up to date)
|
||||
/// </summary>
|
||||
/// <returns>Error code, 0 is success, 1 is not (Note: Maybe it could be interesting in the future to add some more error handling here)</returns>
|
||||
public int Refresh()
|
||||
{
|
||||
LiveDriverDataLogs.Add(Reader.Decode(Reader.MainZones, Reader.Drivers));
|
||||
@@ -25,15 +42,28 @@ namespace Test_Merge
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
/// <summary>
|
||||
/// Changes the image to the newest screenshot in all of the zones and windows
|
||||
/// </summary>
|
||||
/// <param name="image">The new screenshot to put everywhere (Do not mix resolutions)</param>
|
||||
public void ChangeImage(Bitmap image)
|
||||
{
|
||||
Reader.ChangeImage(image);
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets all the data from one driver and also displays into the given panel the last five laps (or less if its the sart of the race) Note: Its responsive :D
|
||||
/// </summary>
|
||||
/// <param name="driverName">The name of the driver (should not be case sensitive but it MUST already exist in the first list that has been inserted into the DB)</param>
|
||||
/// <param name="lastFiveLapsPanel">The pannel where you want the five last laps to be displayed</param>
|
||||
/// <param name="form1">The Main form.</param>
|
||||
/// <returns></returns>
|
||||
public DriverData GetFullDriverData(string driverName, Panel lastFiveLapsPanel, Main form1)
|
||||
{
|
||||
//Note : I know that its a bad idea to ask the Form in this method and some others because it means that it wont work with any main form. And to that Ill say that... your right !
|
||||
DriverData result = new DriverData();
|
||||
if (LiveDriverDataLogs.Count > 0)
|
||||
{
|
||||
//Searches the most recent live data from the given driverName
|
||||
foreach (DriverData data in LiveDriverDataLogs[LiveDriverDataLogs.Count - 1])
|
||||
{
|
||||
if (data.Name == driverName)
|
||||
@@ -42,6 +72,7 @@ namespace Test_Merge
|
||||
|
||||
if (result.Name != "")
|
||||
{
|
||||
//Recovers and displays the last five laps from the driver
|
||||
lastFiveLapsPanel.Controls.Clear();
|
||||
Size labelDimensions = new Size(lastFiveLapsPanel.Width, lastFiveLapsPanel.Height / 5);
|
||||
|
||||
@@ -50,6 +81,8 @@ namespace Test_Merge
|
||||
int id = 0;
|
||||
foreach ((int LapTime, int Lap) lapData in lapsInfos)
|
||||
{
|
||||
//Hardcodes the new button.
|
||||
//Note : It could be smart to have like a default button for all the methods to use without needing to rewrite everything.
|
||||
Button newButton = new Button();
|
||||
lastFiveLapsPanel.Controls.Add(newButton);
|
||||
newButton.Name = driverName + "_" + lapData.Lap;
|
||||
@@ -65,10 +98,16 @@ namespace Test_Merge
|
||||
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Runs trough every drivers live data to recover the drivers that are close to each others
|
||||
/// </summary>
|
||||
/// <param name="pnlBattles">The control that will host the displayed battles</param>
|
||||
/// <param name="form1">The main form. It needs to have a method called 'btnDriver_Click' so it can reads the buttons clicks</param>
|
||||
public void DisplayBattles(Panel pnlBattles,Main form1)
|
||||
{
|
||||
DriverData oldDriver = null;
|
||||
List<(DriverData d1, DriverData d2, int gap)> battles = new List<(DriverData d1, DriverData d2, int gap)>();
|
||||
//Search trough all the drivers and finds the one battling
|
||||
foreach (DriverData driver in LiveDriverDataLogs[LiveDriverDataLogs.Count - 1])
|
||||
{
|
||||
if (oldDriver != null && driver.Position != -1 && oldDriver.Position != -1)
|
||||
@@ -104,6 +143,8 @@ namespace Test_Merge
|
||||
{
|
||||
if(id < maxBattles)
|
||||
{
|
||||
//*hardcoding* the different controls that needs to be added to the panel.
|
||||
//Note : this stuff could totally be handled by the Form with method returning a list of the drivers. It was just easier for me at the time to code it this way but its not the prettiest
|
||||
Button btnFirstDriver = new Button();
|
||||
Button btnSecondDriver = new Button();
|
||||
Label lblGap = new Label();
|
||||
@@ -154,6 +195,12 @@ namespace Test_Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches the fastest and slowests drivers and displays them in the given panels
|
||||
/// </summary>
|
||||
/// <param name="pnlFastest">Panel that will contain the constructed controls</param>
|
||||
/// <param name="pnlSlowest">Panel that will contain the constructed controls</param>
|
||||
/// <param name="form1">The main form that needs to implement the method btnDriver_Click to allow it to recover custom buttons click</param>
|
||||
public void DisplayTimesDeltas(Panel pnlFastest,Panel pnlSlowest, Main form1)
|
||||
{
|
||||
List<(int avg, string driverName)> averages = new List<(int avg, string driverName)>();
|
||||
@@ -180,6 +227,7 @@ namespace Test_Merge
|
||||
pnlSlowest.Controls.Clear();
|
||||
int maxUiSize = pnlFastest.Height / numberOfDriversToShow;
|
||||
|
||||
//Displays the fastest drivers
|
||||
for (int i = 0; i < numberOfDriversToShow; i++)
|
||||
{
|
||||
Button newButton = new Button();
|
||||
@@ -195,7 +243,7 @@ namespace Test_Merge
|
||||
if (i != 0)
|
||||
newButton.Text += " + " + Reader.ConvertMsToTime(Convert.ToInt32(((float)data.avg - (float)averages[0].avg) / 5.0f));
|
||||
}
|
||||
|
||||
//Displays the slowests drivers
|
||||
int badId = 0;
|
||||
for (int i = averages.Count -1; i >= averages.Count - numberOfDriversToShow; i--)
|
||||
{
|
||||
@@ -209,13 +257,18 @@ namespace Test_Merge
|
||||
newButton.Name = data.driver + "_slowest_" + i;
|
||||
newButton.Click += form1.btnDriver_Click;
|
||||
//We take the average time lost per lap
|
||||
newButton.Text += " + " + Reader.ConvertMsToTime(Convert.ToInt32(((float)data.avg) - (float)averages[0].avg / 5.0f));
|
||||
newButton.Text += " + " + Reader.ConvertMsToTime(Convert.ToInt32(((float)data.avg - (float)averages[0].avg) / 5.0f));
|
||||
badId++;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Will add to the list of overtakes the different changes of position
|
||||
/// </summary>
|
||||
/// <param name="lsbResult">The listbox containing all the infos</param>
|
||||
public void DisplayOvertakes(ListBox lsbResult)
|
||||
{
|
||||
//Note : This method SHOULD REALLY not do this but just return a string or a list of string with the new overtakes so the form can handle it as it wishes
|
||||
if (LiveDriverDataLogs.Count > 1)
|
||||
{
|
||||
List<DriverData> oldList = LiveDriverDataLogs[LiveDriverDataLogs.Count - 2];
|
||||
@@ -246,6 +299,12 @@ namespace Test_Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Displays a messageBox containing the infos about a lap time
|
||||
/// </summary>
|
||||
/// <param name="driverName">The name of the driver that has done the lapTime</param>
|
||||
/// <param name="Lap">The number of the lap on wich the lapTime has been set (CAUTION ITS NOT THE RACING LAP ITS FROM THE DB)</param>
|
||||
/// <param name="LapTime">The time (in ms) of the lap</param>
|
||||
public void DisplayLapTimeInfos(string driverName, int Lap, string LapTime)
|
||||
{
|
||||
List<int> sectors = Storage.GetSectorsFromLapTime(driverName, Lap);
|
||||
@@ -259,6 +318,11 @@ namespace Test_Merge
|
||||
message += "Sector 3 : " + Reader.ConvertMsToTime(sectors[2]) + Environment.NewLine;
|
||||
MessageBox.Show(message);
|
||||
}
|
||||
/// <summary>
|
||||
/// Displays the live ranking with the names of the drivers and their gap to the leader in the right order
|
||||
/// </summary>
|
||||
/// <param name="pnl">The control that will host all the new controls</param>
|
||||
/// <param name="form1">The main form</param>
|
||||
public void DisplayLiveRanking(Panel pnl, Main form1)
|
||||
{
|
||||
if (LiveDriverDataLogs.Count > 0)
|
||||
@@ -304,7 +368,7 @@ namespace Test_Merge
|
||||
|
||||
buttons[driverCount] = newButton;
|
||||
}
|
||||
|
||||
//Note : It could be better to have this directly in the same loop
|
||||
foreach (Button button in buttons)
|
||||
{
|
||||
pnl.Controls.Add(button);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverData.cs
|
||||
/// Brief : Class used to store Driver informations
|
||||
/// Version : 0.1
|
||||
/// Brief : File containing classes that behave just like structures to store data about drivers
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -36,6 +36,9 @@ namespace Test_Merge
|
||||
Sector3 = sector3;
|
||||
CurrentTyre = tyre;
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a default driver data with empty values
|
||||
/// </summary>
|
||||
public DriverData()
|
||||
{
|
||||
DRS = false;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverDrsWindow.cs
|
||||
/// Brief : Window containing DRS related method and infos
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -26,7 +26,7 @@ namespace Test_Merge
|
||||
/// <summary>
|
||||
/// Method that will decode the content of the window
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns>returns a boolean (true = DRS OPEN, false = DRS CLOSED)</returns>
|
||||
public override object DecodePng()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverGapToLeaderWindow.cs
|
||||
/// Brief : Window containing infos about the gap to the leader of a driver
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -22,7 +22,7 @@ namespace Test_Merge
|
||||
/// <summary>
|
||||
/// Decodes the gap to leader using Tesseract OCR
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <returns>Returns the gap to the leader in miliseconds (int)</returns>
|
||||
public override object DecodePng()
|
||||
{
|
||||
int result = GetTimeFromPng(WindowImage, OcrImage.WindowType.Gap, Engine);
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverLapTimeWindow
|
||||
/// Brief : Window containing infos about the lap time of a driver
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverNameWindow
|
||||
/// Brief : Window containing infos about the name of the driver
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -15,7 +15,6 @@ namespace Test_Merge
|
||||
{
|
||||
public class DriverNameWindow : Window
|
||||
{
|
||||
public static Random rnd = new Random();
|
||||
public DriverNameWindow(Bitmap image, Rectangle bounds, bool generateEngine = true) : base(image, bounds,generateEngine)
|
||||
{
|
||||
Name = "Name";
|
||||
@@ -23,8 +22,8 @@ namespace Test_Merge
|
||||
/// <summary>
|
||||
/// Decodes using OCR wich driver name is in the image
|
||||
/// </summary>
|
||||
/// <param name="DriverList"></param>
|
||||
/// <returns>The driver name in string</returns>
|
||||
/// <param name="DriverList">A list of all the names that can be on the image</param>
|
||||
/// <returns>a string representing the found driver name. It will be one of the ones given in the list</returns>
|
||||
public override object DecodePng(List<string> DriverList)
|
||||
{
|
||||
string result = "";
|
||||
@@ -40,8 +39,8 @@ namespace Test_Merge
|
||||
/// <summary>
|
||||
/// Verifies that the name found in the OCR is a valid name
|
||||
/// </summary>
|
||||
/// <param name="driverList"></param>
|
||||
/// <param name="potentialDriver"></param>
|
||||
/// <param name="driverList">The list of all the drivers name that can be found in the image</param>
|
||||
/// <param name="potentialDriver">The driver you want to be sure if it exists or not</param>
|
||||
/// <returns>If ye or no the driver exists</returns>
|
||||
private static bool IsADriver(List<string> driverList, string potentialDriver)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// File : DriverPosition.cs
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverPositionWindow.cs
|
||||
/// Brief : Window containing infos about the position of a driver.
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -22,7 +22,7 @@ namespace Test_Merge
|
||||
/// <summary>
|
||||
/// Decodes the position number using Tesseract OCR
|
||||
/// </summary>
|
||||
/// <returns>The position of the pilot in int</returns>
|
||||
/// <returns>An int representing the position of the driver (should be between 1 and 20 included)</returns>
|
||||
public override object DecodePng()
|
||||
{
|
||||
string ocrResult = GetStringFromPng(WindowImage, Engine, "0123456789");
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverSectorWindow.cs
|
||||
/// Brief : Window containing infos about a driver sector time. Can be the first second or third, does not matter.
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : DriverTyresWindow.cs
|
||||
/// Brief : Window containing infos about a driver's tyre
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -15,9 +15,6 @@ namespace Test_Merge
|
||||
{
|
||||
public class DriverTyresWindow:Window
|
||||
{
|
||||
private static Random rnd = new Random();
|
||||
int seed = rnd.Next(0, 10000);
|
||||
|
||||
//Those are the colors I found but you can change them if they change in the future like in 2019
|
||||
public static Color SOFT_TYRE_COLOR = Color.FromArgb(0xff, 0x00, 0x00);
|
||||
public static Color MEDIUM_TYRE_COLOR = Color.FromArgb(0xf5, 0xbf, 0x00);
|
||||
@@ -59,9 +56,8 @@ namespace Test_Merge
|
||||
//We could not convert the number so its a letter so its 0 laps old
|
||||
laps = 0;
|
||||
}
|
||||
//tyreZone.Save(Reader.DEBUG_DUMP_FOLDER + "Tyre" + type + "Laps" + laps + '#' + rnd.Next(0, 1000) + ".png");
|
||||
|
||||
//71 is the most laps an f1 race is ever going to have (mexico)
|
||||
//71 is the most laps an f1 race is ever going to have (mexico) so any more would be considered as bad (and remember you cant go trough a full race without making at least one pitstop)
|
||||
if (laps > 75)
|
||||
laps = 0;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : F1TVEmulator.cs
|
||||
/// Brief : Class that contains methods to emulate a browser and navigate the F1TV website
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using OpenQA.Selenium;
|
||||
using OpenQA.Selenium.Firefox;
|
||||
|
||||
+25
-3
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : OcrImage.cs
|
||||
/// Brief : Class containing all the methods used to enhance images for OCR
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -44,6 +44,7 @@ namespace Test_Merge
|
||||
public Bitmap Enhance(int id,WindowType type = WindowType.Text)
|
||||
{
|
||||
Bitmap outputBitmap = (Bitmap)InputBitmap.Clone();
|
||||
//Note : If you plan to activate all the comments that I used to debug the OCR I would advise to make sure that the debug folder exists
|
||||
switch (type)
|
||||
{
|
||||
case WindowType.Gap:
|
||||
@@ -143,16 +144,23 @@ namespace Test_Merge
|
||||
|
||||
return inputBitmap;
|
||||
}
|
||||
/// <summary>
|
||||
/// Method that uses the Sobel Edge detection to outline the edges of the characters to help with the OCR
|
||||
/// </summary>
|
||||
/// <param name="grayscaleImage">The image with the sobel edge detection used</param>
|
||||
/// <returns></returns>
|
||||
private Bitmap SobelEdgeDetection(Bitmap grayscaleImage)
|
||||
{
|
||||
// Create a new bitmap for the edges
|
||||
Bitmap edgesImage = new Bitmap(grayscaleImage.Width, grayscaleImage.Height);
|
||||
|
||||
// Define the Sobel operators
|
||||
// Its just a matrix that we will use on the all image
|
||||
int[,] sobelX = { { -1, 0, 1 }, { -2, 0, 2 }, { -1, 0, 1 } };
|
||||
int[,] sobelY = { { -1, -2, -1 }, { 0, 0, 0 }, { 1, 2, 1 } };
|
||||
|
||||
// Apply the Sobel operators and normalize the gradients
|
||||
// NOTE: I dont know how easy or hard it would be to make this paralel but it could be a good idea to do so if possible.
|
||||
for (int y = 1; y < grayscaleImage.Height - 1; y++)
|
||||
{
|
||||
for (int x = 1; x < grayscaleImage.Width - 1; x++)
|
||||
@@ -162,6 +170,7 @@ namespace Test_Merge
|
||||
int gradient = (int)Math.Sqrt(gradientX * gradientX + gradientY * gradientY);
|
||||
|
||||
// Normalize the gradient value
|
||||
// In some rare cases the value can exceed 255 so we limit it with the Math.Min method
|
||||
gradient = Math.Min(255, Math.Max(0, gradient));
|
||||
|
||||
edgesImage.SetPixel(x, y, Color.FromArgb(gradient, gradient, gradient));
|
||||
@@ -170,7 +179,14 @@ namespace Test_Merge
|
||||
|
||||
return edgesImage;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Method that's here to be used by the sobel edge detection method (Chat GPT has been used for parts of this method)
|
||||
/// </summary>
|
||||
/// <param name="grayscaleImage">The input image with the grayscale processing already done</param>
|
||||
/// <param name="sobelOperator">The matrix to apply</param>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <returns>Returns the processed gradient</returns>
|
||||
private int CalculateGradient(Bitmap grayscaleImage, int[,] sobelOperator, int x, int y)
|
||||
{
|
||||
int gradient = 0;
|
||||
@@ -186,6 +202,11 @@ namespace Test_Merge
|
||||
|
||||
return gradient;
|
||||
}
|
||||
/// <summary>
|
||||
/// Method that is used to whiten an image. Ignore the funny name. Its used to prevent colored text to trouble the OCR when it uses grayscaling
|
||||
/// </summary>
|
||||
/// <param name="inputBitmap">The bitmap to vanish</param>
|
||||
/// <returns></returns>
|
||||
public static Bitmap VanishOxyAction(Bitmap inputBitmap)
|
||||
{
|
||||
Rectangle rect = new Rectangle(0, 0, inputBitmap.Width, inputBitmap.Height);
|
||||
@@ -194,6 +215,7 @@ namespace Test_Merge
|
||||
|
||||
unsafe
|
||||
{
|
||||
//Note : MAKE THIS PARALELL OMG WY DID I LEFT IT LIKE THAT
|
||||
byte* ptr = (byte*)bmpData.Scan0.ToPointer();
|
||||
for (int y = 0; y < inputBitmap.Height; y++)
|
||||
{
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : Reader.cs
|
||||
/// Brief : Class used to Read the config file for the OCR
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -39,6 +39,8 @@ namespace Test_Merge
|
||||
/// <param name="imageNumber">The image #id on wich you want to create the zones on</param>
|
||||
public List<Zone> Load(Bitmap image, string configFilePath, ref List<string> driverListToFill, bool LoadOCR)
|
||||
{
|
||||
// Note : You may wonder why in the H... I have all the zones and windows stored in a JSON file and not just for example the first and the last
|
||||
// Its because they are not perfectly aligned to each others and every zone has his own alignement to the main image
|
||||
List<Zone> mainZones = new List<Zone>();
|
||||
Bitmap fullImage = image;
|
||||
Zone mainZone;
|
||||
@@ -226,9 +228,7 @@ namespace Test_Merge
|
||||
/// <returns>a string representation of all the returns</returns>
|
||||
public List<DriverData> Decode(List<Zone> mainZones, List<string> drivers)
|
||||
{
|
||||
string result = "";
|
||||
List<DriverData> mainResults = new List<DriverData>();
|
||||
|
||||
//Decode
|
||||
for (int mainZoneId = 0; mainZoneId < mainZones.Count; mainZoneId++)
|
||||
{
|
||||
@@ -282,7 +282,10 @@ namespace Test_Merge
|
||||
mainResults = mainResults.OrderBy(driver => driver.Position).ToList();
|
||||
return mainResults;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Changes the image in all of the zones wich then will do the same for theyre own subzones and windows
|
||||
/// </summary>
|
||||
/// <param name="Image">The new Image from the F1TV data channel</param>
|
||||
public void ChangeImage(Bitmap Image)
|
||||
{
|
||||
foreach (Zone z in MainZones)
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
using System;
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 30/05/2023
|
||||
/// File : SqliteStorage.cs
|
||||
/// Brief : Class that controls the sqlite database
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
@@ -16,10 +22,16 @@ namespace Test_Merge
|
||||
private const string CONNECTION_STRING = "Data Source=" + DATABASE_FOLDER + DATABASE_FILE + ";Version=3;";
|
||||
|
||||
private SQLiteConnection Connection;
|
||||
/// <summary>
|
||||
/// Creates a new Sqlite Storage and initialize the database
|
||||
/// </summary>
|
||||
public SqliteStorage()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
/// <summary>
|
||||
/// Loads a fresh new Database or create a new one if it does not exist.
|
||||
/// </summary>
|
||||
private void Load()
|
||||
{
|
||||
if (!Directory.Exists(DATABASE_FOLDER))
|
||||
@@ -75,6 +87,10 @@ namespace Test_Merge
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds a driver into the drivers table. Meant to be used at the start of the programm
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the driver. (non case sensitive)</param>
|
||||
public void AddDriver(string name)
|
||||
{
|
||||
string insertQuery = "INSERT INTO Drivers (Name) VALUES (@name);";
|
||||
@@ -93,6 +109,11 @@ namespace Test_Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Searches for a driver and returns its id if it has been found
|
||||
/// </summary>
|
||||
/// <param name="name">Name of the driver (non case sensitive)</param>
|
||||
/// <returns></returns>
|
||||
private int GetDriverID(string name)
|
||||
{
|
||||
string selectQuery = "SELECT ID FROM Drivers where Name LIKE @driverName";
|
||||
@@ -117,6 +138,12 @@ namespace Test_Merge
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the sectors from a lapTime. Sectors are subdivisions of a laptime (could be usefull to validate one or the other)
|
||||
/// </summary>
|
||||
/// <param name="driverName">The name of the driver who has done the lap</param>
|
||||
/// <param name="lap">The lap at wich the driver has done the time</param>
|
||||
/// <returns>A list of the different sectors time in int (ms)</returns>
|
||||
public List<int> GetSectorsFromLapTime(string driverName,int lap)
|
||||
{
|
||||
int driverId = GetDriverID(driverName);
|
||||
@@ -143,6 +170,12 @@ namespace Test_Merge
|
||||
}
|
||||
return result;
|
||||
}
|
||||
/// <summary>
|
||||
/// Get the laptime history of a driver
|
||||
/// </summary>
|
||||
/// <param name="driverName">The name of the driver</param>
|
||||
/// <param name="numberOfLaptimes">The number of lapTimes you want</param>
|
||||
/// <returns>A list of tuples with the lap and the laptime. It will only return the amount it found so even if you ask 5 expect getting less or even 0</returns>
|
||||
public List<(int LapTime, int Lap)> GetDriverLaptimes(string driverName,int numberOfLaptimes)
|
||||
{
|
||||
int driverId = GetDriverID(driverName);
|
||||
@@ -169,6 +202,12 @@ namespace Test_Merge
|
||||
}
|
||||
return lapData;
|
||||
}
|
||||
/// <summary>
|
||||
/// Add a pitstop into the db
|
||||
/// </summary>
|
||||
/// <param name="driverName">The name of the driver who made his pitstop</param>
|
||||
/// <param name="lap">The lap where he stopped</param>
|
||||
/// <param name="tyre">The tyre he took out</param>
|
||||
public void AddPitstop(string driverName,int lap,string tyre)
|
||||
{
|
||||
string insertQuery = "INSERT INTO Pitstops (Lap,DriverID,Tyre) VALUES (@Lap,@DriverID,@Tyre)";
|
||||
@@ -188,6 +227,11 @@ namespace Test_Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Adds drivers info into the DB (it should only be once per lap)
|
||||
/// </summary>
|
||||
/// <param name="data">The Driver data</param>
|
||||
/// <param name="lap">The lap from wich the datas are from</param>
|
||||
public void AddDriverStat(DriverData data,int lap)
|
||||
{
|
||||
string insertQuery = "INSERT INTO Stats (Lap,DriverID,Tyre,LapTime,Sector1,Sector2,Sector3,GapToLeader,Position) VALUES (@Lap,@DriverID,@Tyre,@LapTime,@Sector1,@Sector2,@Sector3,@GapToLeader,@Position);";
|
||||
|
||||
+10
-2
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : Window.cs
|
||||
/// Brief : Default Window object that is mainly expected to be inherited.
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -51,6 +51,12 @@ namespace Test_Merge
|
||||
return sample;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Creates a new Window
|
||||
/// </summary>
|
||||
/// <param name="image">The image of the parent zone</param>
|
||||
/// <param name="bounds">The position and size of the window</param>
|
||||
/// <param name="generateEngine">Does the window need to generate a tesseract engine (takes time and ressources)</param>
|
||||
public Window(Bitmap image, Rectangle bounds, bool generateEngine = true)
|
||||
{
|
||||
Image = image;
|
||||
@@ -62,6 +68,7 @@ namespace Test_Merge
|
||||
}
|
||||
|
||||
//DEBUG
|
||||
/*
|
||||
if (!Directory.Exists(STRING_DEBUG_FOLDER))
|
||||
Directory.CreateDirectory(STRING_DEBUG_FOLDER);
|
||||
if (!Directory.Exists(LAPTIME_DEBUG_FOLDER))
|
||||
@@ -78,6 +85,7 @@ namespace Test_Merge
|
||||
Directory.CreateDirectory(DRS_DEBUG_FOLDER);
|
||||
if (!Directory.Exists(TYRE_DEBUG_FOLDER))
|
||||
Directory.CreateDirectory(TYRE_DEBUG_FOLDER);
|
||||
*/
|
||||
}
|
||||
/// <summary>
|
||||
/// Method that will have to be used by the childrens to let the model make them decode the images they have
|
||||
|
||||
+8
-4
@@ -1,8 +1,8 @@
|
||||
/// Author : Maxime Rohmer
|
||||
/// Date : 08/05/2023
|
||||
/// Date : 30/05/2023
|
||||
/// File : Zone.cs
|
||||
/// Brief : Class that contains all the methods and infos for a zone. This is designed to be potentially be inherited.
|
||||
/// Version : 0.1
|
||||
/// Version : Alpha 1.0
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
@@ -49,12 +49,16 @@ namespace Test_Merge
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Rectangle Bounds { get => _bounds; protected set => _bounds = value; }
|
||||
public List<Zone> Zones { get => _zones; protected set => _zones = value; }
|
||||
public List<Window> Windows { get => _windows; protected set => _windows = value; }
|
||||
public string Name { get => _name; protected set => _name = value; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new Zone
|
||||
/// </summary>
|
||||
/// <param name="image">Image of the parent zone</param>
|
||||
/// <param name="bounds">The position and size of the zone</param>
|
||||
/// <param name="name">THe name of the zone (usefull for the JSON formatting)</param>
|
||||
public Zone(Bitmap image, Rectangle bounds, string name)
|
||||
{
|
||||
Windows = new List<Window>();
|
||||
|
||||
Reference in New Issue
Block a user