Updated doc
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
+10
-5
@@ -28,17 +28,22 @@ Le but du projet est donc de fournir un outil qui hiérarchise et affiche diffé
|
||||
|
||||
### Abstract
|
||||
|
||||
Track Trends is a Formula 1 data and analysis tool.
|
||||
Track Trends is a Formula 1 data is a tool that displays and interpret data.
|
||||
|
||||
To understand everything, a little bit of context. In my free time I have multiple activities and one is to be the Live Ticker F1 for the local journal "20 minutes". to help me in this work I'm currently using the F1TV to which I'm currently subscribed because it provides me with a better video feed with better commentary than the ones from the RTS (in my opinion) but also because it gives me access to a very important video feed : the data channel
|
||||
To understand everything,first ,a little bit of context. In my free time I have multiple activities and one is to be the Live Ticker F1 for the local journal "20 minutes" (Owned by Tamedia). to help me in this work I'm currently using the F1TV to which I'm currently subscribed because it provides me with a better video feed with better commentary than the ones from the RTS (in my opinion) but also because it gives me access to a very important video feed : the data channel
|
||||
|
||||
See the screenshot above to see what it looks like.
|
||||
You can see in the chapter above an example of the F1TV DATA CHANNEL.
|
||||
|
||||
[note: It's a pretty HTML table but a full on video feed that contains a table (probably, so you can't access data directly)]
|
||||
[Note : Even tough it looks like a pretty HTML table on wich you could easely get infos... Its not. Its a video feed]
|
||||
|
||||
You can see a lot of data all well and good BUT! All the data is displayed the same in a big table which make it really hard to read totally in a hurry, which means that I miss a lot of useful information.
|
||||
|
||||
The point of the project then is to provide with a tool that can display those data by taking into account their relevance. That would help me not miss any and provide a better commentary by never missing out battles, and be able to better write with the time I saved by using it.
|
||||
The point of the project then is to provide a tool that can display those data by taking into account their relevance.
|
||||
So for example a driver that is 10s away from everyone and that is doing some normal lapTimes will be less displayed or even not displayed at all so I can focus on the drivers that are battling each others.
|
||||
|
||||
This tool would help me not miss the battles and details that are happening in the back and therefore not being broadcasted on TV.And it could be a usefull tool for anyone who wants a better insight of how the race is going by looking at the data.
|
||||
|
||||
This kind of project already exists in the form of the AWS tool "F1 Insight" but it is not avaible to the public. We can only see some of its predictions (that are trash) and data dumps in the live feed when the TV directors feel like it.
|
||||
|
||||
### Description du besoin
|
||||
|
||||
|
||||
+431
-1
@@ -2187,4 +2187,434 @@ Bon au final j'ai quand même changé mon poster
|
||||
|
||||
Mais je suis trop attaché à l'ancien concept alors je vais plutôt utiliser ca :
|
||||
|
||||

|
||||

|
||||
|
||||
Je pense que cette version est meilleure même si elle est encore plus en bordel par ce que le texte permet de se faire une meilleure idée de l'utilisé de chaque partie.
|
||||
|
||||
## Mercredi 10 Mai 2023
|
||||
|
||||
Bon hier je n'ai pas eu le temps de finir la documentation de la recupèration d'images et de la calibration. Il faudra donc que je repasse un coup dessus en fin de semaine je pense.
|
||||
|
||||
Mais la j'aimerais avancer sur la mise en commun du projet, comme la configuration fonctionne plutôt pas mal je pense que je vais juste vite fait aller commenter les methodes qui ne le sont pas encore et ensuite je vais passer à l'implémentation de l'OCR.
|
||||
|
||||
Je suis presque certain que l'OCR va avoir besoin de plus de règlages mais bon on verra bien.
|
||||
|
||||
Je me rend compte en commentant que la methode de load serait plus efficace avec un tout petit peu plus d'infos de la part du JSON. J'aurais pu ajouter l'offset entre chaque Driver Zone pour eviter un lèger drift lors de la reconstruction. Mais bon rien de grave donc je pense que je vais le laisser comme ca pour le moment à moins que ca me pose soucis plus tard.
|
||||
|
||||
J'ai eu quelques soucis avec les images en 4K. Du coup j'ai descendu les variables d'environnement à 1920x1080
|
||||
|
||||
En fait il y a parfois un soucis un peu pénible avec l'OCR.
|
||||
|
||||
Parfois pour un temps comme ci dessous:
|
||||
|
||||

|
||||
|
||||
Le programme ne va pas bien comprendre les ponctuations et il va donner : `1115140`
|
||||
|
||||
La il y a deux problèmes... Le 1:xx.xxx est compris comme 11xxxxx et le 4 s'est transformé en 1...
|
||||
|
||||
J'ai créé ce "petit" bout de code pour gèrer les fois ou les '.' et les ':' ont mal été interprêtés
|
||||
|
||||
```Csharp
|
||||
if (rawNumbers.Count == 1)
|
||||
{
|
||||
//If this code is used it means that its bad ...
|
||||
//The methods that comes are really not that great and are juste quick fixes
|
||||
try
|
||||
{
|
||||
result = Convert.ToInt32(rawNumbers[0]);
|
||||
|
||||
switch (windowType)
|
||||
{
|
||||
case OcrImage.WindowType.Sector:
|
||||
//The usual sector is in this form : 33.456
|
||||
if (rawNumbers[0].Length == 6)
|
||||
{
|
||||
//The '.' has been understood like a number
|
||||
result = 0;
|
||||
result += Convert.ToInt32(rawNumbers[0][0] + rawNumbers[0][1]) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[0][3] + rawNumbers[0][4] + rawNumbers[0][5]);
|
||||
}
|
||||
if (rawNumbers[0].Length == 5)
|
||||
{
|
||||
//The '.' has been overlooked
|
||||
result = 0;
|
||||
result += Convert.ToInt32(rawNumbers[0][0] + rawNumbers[0][1]) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[0][2] + rawNumbers[0][3] + rawNumbers[0][4]);
|
||||
}
|
||||
break;
|
||||
case OcrImage.WindowType.LapTime:
|
||||
//The usual Lap time is in this form : 1:45:345
|
||||
if (rawNumbers[0].Length == 6)
|
||||
{
|
||||
//The '.' and ':' have been overlooked
|
||||
//I Know Im skipping the cases where there are more than 9 minuts but it happens so rarely that... we dont care
|
||||
result = 0;
|
||||
result += Convert.ToInt32(rawNumbers[0][0]) * 60000;
|
||||
result += Convert.ToInt32(rawNumbers[0][1] + rawNumbers[0][2]) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[0][3] + rawNumbers[0][4] + rawNumbers[0][5]);
|
||||
}
|
||||
if (rawNumbers[0].Length == 7)
|
||||
{
|
||||
//There is two possibilities
|
||||
//Either 1:45.140 has been interpreted as 1145.10 or 1:451140. We will assume its the first one
|
||||
result = 0;
|
||||
result += Convert.ToInt32(rawNumbers[0][0]) * 60000;
|
||||
result += Convert.ToInt32(rawNumbers[0][2] + rawNumbers[0][3]) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[0][4] + rawNumbers[0][5] + rawNumbers[0][6]);
|
||||
}
|
||||
break;
|
||||
case OcrImage.WindowType.Gap:
|
||||
//The usual Gap is in this form : + 34.567
|
||||
if (rawNumbers[0].Length == 5)
|
||||
{
|
||||
//The '.' has been overlooked
|
||||
result += Convert.ToInt32(rawNumbers[0][0] + rawNumbers[0][1]) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[0][2] + rawNumbers[0][3] + rawNumbers[0][4]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (rawNumbers[0].Length > 6)
|
||||
{
|
||||
//The number definitely has been interpreted wrong
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
//It can be because the input is empty or because its the LEADER bracket
|
||||
result = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//Auuuugh
|
||||
result = 0;
|
||||
}
|
||||
```
|
||||
|
||||
```Csharp
|
||||
ConfigFile = "./Presets/Clean_2023.json";
|
||||
string gpUrl = "https://f1tv.formula1.com/detail/1000006688/2023-azerbaijan-grand-prix?action=play";
|
||||
```
|
||||
|
||||
Bon je n'arrive pas à faire fonctionner l'OCR sans tout faire crash à chaque fois. Je vais abandonner le travail de la journée pour revenir au point initial... C'est très frustrant mais bon je ne vois pas comment faire mieux. Rien ne marche alors qu'avant ca marchant super sur le projet OCR normal.
|
||||
|
||||
Va savoir pourquoi même comme ca, impossible de faire marcher l'OCR. Il y a un soucis au niveau de l'ASYNC qui me fait crash tout le temps en me disant qu'un objet est deja en train d'être utilisé. Ca marchait nikel dans mes premières version je ne vois pas pourquoi ca pête maintenant.
|
||||
|
||||
Je pense que je vois à peu près le soucis.
|
||||
|
||||
```Csharp
|
||||
public virtual async Task<DriverData> Decode(List<string> driverList)
|
||||
{
|
||||
int sectorCount = 0;
|
||||
DriverData result = new DriverData();
|
||||
Parallel.ForEach(Windows, async w =>
|
||||
{
|
||||
// A switch would be prettier but I dont think its supported in this C# version
|
||||
if (w is DriverNameWindow)
|
||||
result.Name = (string)await (w as DriverNameWindow).DecodePng(driverList);
|
||||
if (w is DriverDrsWindow)
|
||||
result.DRS = (bool)await (w as DriverDrsWindow).DecodePng();
|
||||
if (w is DriverGapToLeaderWindow)
|
||||
result.GapToLeader = (int)await (w as DriverGapToLeaderWindow).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 DriverSectorWindow)
|
||||
{
|
||||
sectorCount++;
|
||||
if (sectorCount == 1)
|
||||
result.Sector1 = (int)await (w as DriverSectorWindow).DecodePng();
|
||||
if (sectorCount == 2)
|
||||
result.Sector2 = (int)await (w as DriverSectorWindow).DecodePng();
|
||||
if (sectorCount == 3)
|
||||
result.Sector3 = (int)await (w as DriverSectorWindow).DecodePng();
|
||||
}
|
||||
if (w is DriverTyresWindow)
|
||||
result.CurrentTyre = (Tyre)await (w as DriverTyresWindow).DecodePng();
|
||||
});
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
Ca c'est ma methode de decoding de chaque Driver Zone. Le message d'erreur me parle d'une windowImage quand il dit qu'un objet est déja utilisé. Ma conjecture c'est que en essayant de faire toutes les windows en même temps. Elles veulent parfois accèder à l'image principale en même temps. Ce qui evidemment pose problème. Je pense que le fix le plus simple serait de faire le traitement sans le parallele quitte à exporter ce fonctionnement sur chaque zone en elle même pour ne pas perdre trop de performances.
|
||||
|
||||
Ok je crois que je vois ou est le soucis. En fait dans cette version du programme c'est toujours la première image qui était juste tout le temps prise et dans la première image on a une partie des chiffres qui est bloquée par l'UI de la fenêtre... lol...
|
||||
|
||||
EN FAIT
|
||||
J'avais un soucis dans ma gestion des chiffres mal faits. Visiblement parfois quand je ne prenais pas en compte un :, un LapTime etait compris comme un Gap to leader ou un Secteur
|
||||
|
||||
Bon j'en ai tellement marre... Je n'arrive tout simplement PAS à faire fonctionner l'OCR ca crash tout le temps j'en peux plus.
|
||||
|
||||
J'ai tenté de règler les problèmes de mauvaises detections de secteurs et temps au tour qui font crasher l'app :
|
||||
|
||||
```Csharp
|
||||
if (rawNumbers.Count == 2)
|
||||
{
|
||||
//ss:ms
|
||||
result = (Convert.ToInt32(rawNumbers[0]) * 1000) + Convert.ToInt32(rawNumbers[1]);
|
||||
|
||||
if (result > (60000 + 999))
|
||||
{
|
||||
if (windowType == OcrImage.WindowType.LapTime)
|
||||
{
|
||||
result = 0;
|
||||
result += Convert.ToInt32(rawNumbers[0][0]) * 60000;
|
||||
result += Convert.ToInt32(rawNumbers[0][2].ToString() + rawNumbers[0][3].ToString()) * 1000;
|
||||
result += Convert.ToInt32(rawNumbers[1]);
|
||||
}
|
||||
if (windowType == OcrImage.WindowType.Sector)
|
||||
{
|
||||
int seconds = 0;
|
||||
if (rawNumbers[0].Length == 3)
|
||||
{
|
||||
//We have one char that we need to delete
|
||||
//For no apparent reason im going to delete the first
|
||||
seconds = Convert.ToInt32(rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
seconds = Convert.ToInt32(rawNumbers[0][0].ToString() + rawNumbers[0][1].ToString());
|
||||
}
|
||||
int ms = Convert.ToInt32(rawNumbers[0][0].ToString() + rawNumbers[0][1].ToString() + rawNumbers[0][2].ToString());
|
||||
result = seconds * 1000 + ms;
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Mais toujours impossible de faire fonctionner cette M**** C'est juste infernal. Je pense que je vais encore tout retirer et remplacer par ce que j'ai dans mon projet OCR original. Donc c'est une journée de perdue complêtement... C'est extrêmement frustrant.
|
||||
|
||||
Après des heures de debug j'ai enfin réussi à faire fonctionner le programme de temps en temps. Mais j'ai toujours le soucis que l'image ne veut pas changer alors que je fais tout pour et que l'OCR est nulle à chier du coup...
|
||||
|
||||
## Jeudi 11 Mai 2023
|
||||
|
||||
Bon après une bonne nuit de sommeil je vais reprendre les choses depuis le début.
|
||||
|
||||
J'ai deux soucis :
|
||||
|
||||
- L'OCR pue du derche
|
||||
- L'Image que l'on décode ne change pas
|
||||
|
||||
Pour la première partie j'ai ma petite théorie. Je pense que comme je donne des images 4K alors que le feed est en 1080P, il y a déja un genre d'interpolation qui est faite. Je pense donc qu'il faut que j'adapte mon engine pour qu'il fonctionne avec cette résolution.
|
||||
|
||||
Je me suis demandé si ca n'était pas mieux de prendre en compte les deux résolutions pour les pc un peu moins balèzes et j'ai décidé de n'en avoir rien a faire. On verra dans le futur si c'est une feature que je voudrais ajouter mais c'est en dehors du scope du diplôme je pense.
|
||||
|
||||
Pour la seconde partie, je pense qu'il faut que j'aille voir du côte de OCR_Decode et de OCR Tester pour voir comment je faisais. Je dois forcément oublier un truc.
|
||||
|
||||
Bon ca commence mal, quand je vais voir dans le projet OCR_Decode, le changement d'image est exactement le même et il fonctionne alors que de mon côté ca n'est pas le cas.
|
||||
|
||||
Alors deux choses. Je me rend compte que le changement d'images n'a AUCUN effet sur la detection de texte, et seconde chose, le décalage est trop grand entre les windows. Des que le soucis d'image est règlé il va falloir que je change drastiquement ma facon de stocker la config en JSON. Il faut que je conserve les écarts.
|
||||
|
||||
Sinon regardez ce que ca donne quand on arrive au dernier pilote :
|
||||
|
||||

|
||||
|
||||
Je commence à devenir FOU. Je n'arrive pas à changer cette foutue image wtf... J'ai beau tenter par tous les moyens de la changer par une image noire, l'image semble toujours rester celle du départ.
|
||||
|
||||
Bon j'ai enfin trouvé pourquoi et je n'ai pas envie de dire comment j'ai trouvé... Je pense que l'on a tous droit à son petit jardin secret.
|
||||
|
||||
Maintenant ca veut dire que je peux me focus sur le concept important qui est le changement de la création et de la lecture des JSON.
|
||||
|
||||
Voici un exemple de preset JSON :
|
||||
|
||||
```JSON
|
||||
{
|
||||
"Main": {
|
||||
"x": 40,
|
||||
"y": 355,
|
||||
"width": 3784,
|
||||
"height": 1438,
|
||||
"Zones": [
|
||||
{
|
||||
"DriverZone": {
|
||||
"x": 0,
|
||||
"y": -10,
|
||||
"width": 3784,
|
||||
"height": 71,
|
||||
"Windows": [
|
||||
{
|
||||
"Position": {
|
||||
"x": 47,
|
||||
"y": 11,
|
||||
"width": 72
|
||||
},
|
||||
"GapToLeader": {
|
||||
"x": 445,
|
||||
"y": 13,
|
||||
"width": 201
|
||||
},
|
||||
"LapTime": {
|
||||
"x": 859,
|
||||
"y": 14,
|
||||
"width": 221
|
||||
},
|
||||
"DRS": {
|
||||
"x": 1094,
|
||||
"y": 13,
|
||||
"width": 173
|
||||
},
|
||||
"Tyres": {
|
||||
"x": 1270,
|
||||
"y": 11,
|
||||
"width": 1452
|
||||
},
|
||||
"Name": {
|
||||
"x": 2727,
|
||||
"y": 11,
|
||||
"width": 351
|
||||
},
|
||||
"Sector1": {
|
||||
"x": 3083,
|
||||
"y": 10,
|
||||
"width": 253
|
||||
},
|
||||
"Sector2": {
|
||||
"x": 3339,
|
||||
"y": 14,
|
||||
"width": 195
|
||||
},
|
||||
"Sector3": {
|
||||
"x": 3518,
|
||||
"y": 14,
|
||||
"width": 250
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"Drivers": [
|
||||
"Perez",
|
||||
"Leclerc",
|
||||
"Sainz",
|
||||
"Alonso",
|
||||
"Stroll",
|
||||
"Russel",
|
||||
"Verstappen",
|
||||
"Zhou",
|
||||
"Ocon",
|
||||
"Hulkenberg",
|
||||
"Hamilton",
|
||||
"Norris",
|
||||
"Tsunoda",
|
||||
"Magnussen",
|
||||
"Piastri",
|
||||
"Albon",
|
||||
"Gasly",
|
||||
"Sargeant",
|
||||
"Bottas",
|
||||
"De Vries"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Je pense que ce qui serait bien ce serait de rajouter un "offsets" qui contienne les 19 écarts restants.
|
||||
|
||||
Bon... la structure de ma fabrication de JSON etait trop confuse je trouve alors je l'ai complêtement refaite.
|
||||
|
||||
J'ai aussi abandonné l'idée de faire un fichier le plus petit possible car au final on s'en fiche et le plus important c'est que toutes les windows et les zones soient aux bons endroits.
|
||||
|
||||
Ca nous fait un fichier d'environs 1300 lignes mais au moins le code pour la serialisation est plutôt clean :
|
||||
|
||||
```Csharp
|
||||
public void SaveToJson(List<string> drivers, string configName)
|
||||
{
|
||||
string JSON = "";
|
||||
|
||||
JsonObject jsonFileObject = new JsonObject();
|
||||
|
||||
//Creating 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);
|
||||
mainZoneObject.Add("height",MainZone.Bounds.Height);
|
||||
|
||||
JsonArray driverZonesArray = new JsonArray();
|
||||
|
||||
int DriverID = 0;
|
||||
foreach (Zone driverZone in MainZone.Zones)
|
||||
{
|
||||
DriverID++;
|
||||
JsonObject driverZoneObject = new JsonObject();
|
||||
driverZoneObject.Add("name","Driver"+DriverID);
|
||||
driverZoneObject.Add("x", driverZone.Bounds.X);
|
||||
driverZoneObject.Add("y", driverZone.Bounds.Y);
|
||||
driverZoneObject.Add("width", driverZone.Bounds.Width);
|
||||
driverZoneObject.Add("height", driverZone.Bounds.Height);
|
||||
|
||||
JsonArray windowsArray = new JsonArray();
|
||||
|
||||
JsonObject windowObject = new JsonObject();
|
||||
foreach (Window window in driverZone.Windows)
|
||||
{
|
||||
windowObject.Add(window.Name, new JsonObject {
|
||||
{ "x", window.Bounds.X },
|
||||
{ "y", window.Bounds.Y },
|
||||
{ "width", window.Bounds.Width },
|
||||
{ "height", window.Bounds.Height }
|
||||
});
|
||||
}
|
||||
windowsArray.Add(windowObject);
|
||||
|
||||
driverZoneObject.Add("Windows",windowsArray);
|
||||
|
||||
driverZonesArray.Add(driverZoneObject);
|
||||
}
|
||||
|
||||
mainZoneObject.Add("DriverZones",driverZonesArray);
|
||||
|
||||
JsonArray driversArray = new JsonArray();
|
||||
|
||||
foreach (string driver in drivers)
|
||||
{
|
||||
driversArray.Add(driver);
|
||||
}
|
||||
|
||||
mainZoneObject.Add("Drivers",driversArray);
|
||||
|
||||
jsonFileObject.Add("Main",mainZoneObject);
|
||||
|
||||
JSON = jsonFileObject.ToString();
|
||||
|
||||
//Saving the file
|
||||
string path = CONFIGS_FOLDER_NAME + configName;
|
||||
|
||||
if (File.Exists(path + ".json"))
|
||||
{
|
||||
//We need to create a new name
|
||||
int count = 2;
|
||||
while (File.Exists(path + "_" + count + ".json"))
|
||||
{
|
||||
count++;
|
||||
}
|
||||
path += "_" + count + ".json";
|
||||
}
|
||||
else
|
||||
{
|
||||
path += ".json";
|
||||
}
|
||||
|
||||
File.WriteAllText(path, JSON);
|
||||
}
|
||||
```
|
||||
|
||||
Et normalement la lecture devrait être encore plus simple.
|
||||
|
||||
En fait c'était pas beaucoup plus simple mais au moins maintenant ca marche. Je vais pas mettre le code de lecture ici car c'est un peu trop long donc il va falloir me croire sur parole. (Ou aller sur Git)
|
||||
|
||||
Bon bah on est au même endroit qu'hier...
|
||||
|
||||
Bon pour demain le plan de bataille ca va être :
|
||||
|
||||
Changer complêtement la methode "GetTimeFromPng" pour qu'elle prenne en compte toutes les possibilités de bugs et d'oubli de '.' ou de ':' mais pas selon le nombre de blocs mais selon le type de temps que l'on cherche
|
||||
|
||||
Pour le moment je regarde le nombre de blocs et si il y en a deux alors c'est que c'est un temps de secteur. En fait non cela peut aussi être un temps au tour qui a raté un point.
|
||||
|
||||
Il faut que je bosse juste un peu vite fait la dessus et que j'arrête de putain de crasher dès que un truc est pas au bon format. Ensuite quand ca aura arrêté de crasher je vais reprendre l'OCR et voir pourquoi les resultats sont nuls a chier comme ca.
|
||||
|
||||
Et le but c'est que demain soir j'ai une reconnaissance de caractères plus proche de ce que j'avais dans d'autres projets... J'y croit 0 mais bon l'espoir fait vivre comme on dit.
|
||||
|
||||
Reference in New Issue
Block a user