Added a new table of figures script

This commit is contained in:
2023-06-09 11:51:55 +02:00
parent 1a8a73a143
commit 40c7e3df81
83 changed files with 16509 additions and 22749 deletions
+34
View File
@@ -0,0 +1,34 @@
import os
import re
def generate_figure_table(directory):
table = []
figure_pattern = r'!\[([^\]]*)\]\(([^\)]*)\)'
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".md"):
file_path = os.path.join(root, file)
with open(file_path, "r") as md_file:
content = md_file.readlines()
for line in content:
matches = re.findall(figure_pattern, line)
for match in matches:
alt_text = match[0]
image_path = match[1]
table.append([alt_text, image_path, file_path])
if table:
headers = ["Texte alternatif", "Chemin de l'image", "Fichier Markdown"]
with open("TableDesFigures.md", "w") as file:
file.write("| " + " | ".join(headers) + " |\n")
file.write("|" + "|".join(["---"] * len(headers)) + "|\n")
for row in table:
file.write("| " + " | ".join(row) + " |\n")
print("Le fichier figure_table.md a été généré avec succès.")
else:
print("Aucune figure trouvée dans les fichiers Markdown.")
# Exemple d'utilisation
generate_figure_table("./docs")
+247
View File
@@ -0,0 +1,247 @@
| Texte alternatif | Chemin de l'image | Fichier Markdown |
|---|---|---|
| "Page de lancement" | ./Images/Manual/StartPage.png | ./docs/ManuelUtilisateur.md |
| "Contrôles" | ./Images/Manual/Controls.png | ./docs/ManuelUtilisateur.md |
| "Page principale de la F1TV" | ./Images/Manual/F1TvMainPage.png | ./docs/ManuelUtilisateur.md |
| "Page d'un Grand Prix sur la F1TV" | ./Images/Manual/F1TvGpPage.png | ./docs/ManuelUtilisateur.md |
| "Page suspecte (Pas de panique, elle ne l'est pas)" | ./Images/Manual/SuspectCmd.png | ./docs/ManuelUtilisateur.md |
| "Début du programme" | ./Images/Manual/StartOfSimulation.png | ./docs/ManuelUtilisateur.md |
| "Arrêt du programme" | ./Images/Manual/Stopeed.png | ./docs/ManuelUtilisateur.md |
| "Page de config vide" | ./Images/Manual/EmptySettingsPage.png | ./docs/ManuelUtilisateur.md |
| "Invite de commande suspecte, mais normale" | ./Images/Manual/SettingsPageWithCmdOpen.png | ./docs/ManuelUtilisateur.md |
| "Page de config amorcée" | ./Images/Manual/SettingsPageWithStartedF1TV.png | ./docs/ManuelUtilisateur.md |
| "Texte indiquant le nombre de points qu'il reste à ajouter" | ./Images/Manual/2PointsRemaining.png | ./docs/ManuelUtilisateur.md |
| "Infographie expliquant où placer les points de la zone principale" | ./Images/Manual/WhereToDrawMainZone.png | ./docs/ManuelUtilisateur.md |
| "Texte qui ne doit pas être dans la zone sélectionnée" | ./Images/Manual/ForbiddenZone.png | ./docs/ManuelUtilisateur.md |
| "Zone principale avec les zones de pilotes automatiquement calculées" | ./Images/Manual/DriverZones.png | ./docs/ManuelUtilisateur.md |
| "Image d'une zone de pilote" | ./Images/Manual/DriverZone.png | ./docs/ManuelUtilisateur.md |
| "Texte indiquant le nombre de windows à ajouter" | ./Images/Manual/9WindowsRemaining.png | ./docs/ManuelUtilisateur.md |
| "Exemple de fenêtres découpées" | ./Images/Manual/Windows.png | ./docs/ManuelUtilisateur.md |
| "Menu d'interaction avec la liste de pilotes" | ./Images/Manual/DriverListControls.png | ./docs/ManuelUtilisateur.md |
| "Image de la page de config après avoir ajouté toutes les infos" | ./Images/Manual/SettingsReady.png | ./docs/ManuelUtilisateur.md |
| "Exemple de ce à quoi peut ressembler un loading et l'affichage bizarre que ça implique" | ./Images/Manual/LoadedPreset.png | ./docs/ManuelUtilisateur.md |
| "Image de l'application en cours de fonctionnement depuis quelques minutes" | ./Images/Manual/Simulation.png | ./docs/ManuelUtilisateur.md |
| "Image de la fenêtre des cinq derniers tours" | ./Images/Manual/LastFiveLAps.png | ./docs/ManuelUtilisateur.md |
| "Fenêtre des batailles" | ./Images/Manual/Battles.png | ./docs/ManuelUtilisateur.md |
| "Fenêtre des infos pilote" | ./Images/Manual/DriverInfos.png | ./docs/ManuelUtilisateur.md |
| "Exemple d'affichage des secteurs d'un temps au tour" | ./Images/Manual/LapInfos.png | ./docs/ManuelUtilisateur.md |
| "Fenêtre du classement en direct" | ./Images/Manual/LiveRanking.png | ./docs/ManuelUtilisateur.md |
| "Exemple commentaires" | ./Images/Screens/ExampleLiveTicker.png | ./docs/CahierDesCharges.md |
| "Data channel exemple" | ./Images/Screens/Formula1DataChannel.png | ./docs/CahierDesCharges.md |
| "Proto" | ./Images/Figma/Prototype.png | ./docs/CahierDesCharges.md |
| "Exemple mkdocs" | ./Images/Screens/MkdocsExample.png | ./docs/jdb.md |
| "Croquis Poster 1" | ./Images/Photos/photosCroquisPoster1jpg | ./docs/jdb.md |
| "Croquis Poster 2" | ./Images/Photos/photosCroquisPoster2jpg | ./docs/jdb.md |
| "Image non traitée" | ./Images/Screens/BlackToWhite0.png | ./docs/jdb.md |
| "Image traitée laxiste" | ./Images/Screens/BlackToWhite1.png | ./docs/jdb.md |
| "Image traitée stricte" | ./Images/Screens/BlackToWhite2.png | ./docs/jdb.md |
| "Screenshot de reconnaisance d'image complete" | ./Images/Screens/TextRecognition1.png | ./docs/jdb.md |
| "Screenshot de reconnaissance d'image cropée" | ./Images/Screens/TextRecognition0.png | ./docs/jdb.md |
| "Screenshot de reconnaissance de Tsunoda" | ./Images/Screens/TextRecognition2.png | ./docs/jdb.md |
| "Tsunoda en 720P" | ./Images/Screens/720PTsunoda.png | ./docs/jdb.md |
| "Tsunoda en 1080P" | ./Images/Screens/1080PTsunoda.png | ./docs/jdb.md |
| "Reconnaissance Tsunoda en 1080P" | ./Images/Screens/TextRecognition3.png | ./docs/jdb.md |
| "Tsunoda 1080P avec filtre" | ./Images/Screens/TextRecognition4.png | ./docs/jdb.md |
| "Leclerc 1080P avec filtre" | ./Images/Screens/TextRecognition5.png | ./docs/jdb.md |
| "Leclerc 1080P avec filtre 2" | ./Images/Screens/TextRecognition6.png | ./docs/jdb.md |
| "Tentative de reconnaisance du timing" | ./Images/Screens/TimingRecognition0.png | ./docs/jdb.md |
| "Tentative 2 de reconnaissance du timing" | ./Images/Screens/TimingRecognition1.png | ./docs/jdb.md |
| "Reconnaissance du timing au tour" | ./Images/Screens/TimingRecognition2.png | ./docs/jdb.md |
| "Main zone" | ./Images/Figma/WindowZoneExplanation1.png | ./docs/jdb.md |
| "Driver zone #1" | ./Images/Figma/WindowZoneExplanation2.png | ./docs/jdb.md |
| "Driver windows" | ./Images/Figma/WindowZoneExplanation3.png | ./docs/jdb.md |
| "Diagramme d'explications" | ./Images/Figma/WindowZoneExplanationDiagram.png | ./docs/jdb.md |
| "MainZone avec carrés de texte" | ./Images/Screens/AutoCalibration1.png | ./docs/jdb.md |
| "MainZone avec de meilleurs carrés" | ./Images/Screens/AutoCalibration2.png | ./docs/jdb.md |
| "MainZone avec de meilleurs carrés" | ./Images/Screens/AutoCalibration3.png | ./docs/jdb.md |
| "MainZone avec un seul carré par ligne" | ./Images/Screens/AutoCalibration4.png | ./docs/jdb.md |
| "Mainzone auto calibrée" | ./Images/Screens/AutoCalibration5.png | ./docs/jdb.md |
| "Images pilotes" | ./Images/Screens/WindowsPilotes.png | ./docs/jdb.md |
| "Zone d'un pilote" | ./Images/Screens/driver2.png | ./docs/jdb.md |
| "Sainz coupé" | ./Images/Screens/data0Sainz.png | ./docs/jdb.md |
| "Perez coupé" | ./Images/Screens/data0Perez.png | ./docs/jdb.md |
| "Ocr tester screenshot" | ./Images/Screens/OCRTestingScreen.png | ./docs/jdb.md |
| "Dossier Perez" | ./Images/Screens/PerezFolder.png | ./docs/jdb.md |
| "Tentative d'auto calibration" | ./Images/Screens/AutoCalibration6.png | ./docs/jdb.md |
| "Tentative 2" | ./Images/Screens/AutoCalibration7.png | ./docs/jdb.md |
| "Resultat final" | ./Images/Screens/AutoCalibration8.png | ./docs/jdb.md |
| "Verstappen folder" | ./Images/Screens/VerstappenFolder.png | ./docs/jdb.md |
| "JSON decode result" | ./Images/Screens/JsonDecodeResult.png | ./docs/jdb.md |
| "Centered driver" | ./Images/Screens/CenteredDriver.png | ./docs/jdb.md |
| "Uncentered Driver" | ./Images/Screens/UncenteredDriver.png | ./docs/jdb.md |
| "Verstappen folder 2 | ./Images/Screens/VerstappenFolder2.png | ./docs/jdb.md |
| "Image reconnaissance propre" | ./Images/Screens/ImageDecoding1.png | ./docs/jdb.md |
| "11ZSD" | ./Images/Screens/11ZSD.png | ./docs/jdb.md |
| 42340 | ./Images/Screens/42340.png | ./docs/jdb.md |
| "ZZAEB" | ./Images/Screens/ZZAEB.png | ./docs/jdb.md |
| "Clear1" | ./Images/Screens/Clear44301.png | ./docs/jdb.md |
| "Clear2" | ./Images/Screens/ClearA5157.png | ./docs/jdb.md |
| "Original" | ./Images/Screens/BeforeProcessing1.png | ./docs/jdb.md |
| "Grayscale" | ./Images/Screens/GrayScale.png | ./docs/jdb.md |
| "InvertColors" | ./Images/Screens/InvertColor.png | ./docs/jdb.md |
| "Resize" | ./Images/Screens/Scaling.png | ./docs/jdb.md |
| "Dilatation" | ./Images/Screens/Dilatation.png | ./docs/jdb.md |
| "Clean" | ./Images/Screen/../Screens/Clean.png | ./docs/jdb.md |
| "Closed DRS" | ./Images/Screens/DRSFalse.png | ./docs/jdb.md |
| "Open DRS" | ./Images/Screens/DRSTrue.png | ./docs/jdb.md |
| "Color fun" | ./Images/Screens/TestsCouleurs.png | ./docs/jdb.md |
| "Tyres" | ./Images/Screens/TyresImages.png | ./docs/jdb.md |
| "Tyre colors" | ./Images/Screens/TyreColors.png | ./docs/jdb.md |
| "5i t'inquiètes" | ./Images/Screens/Perfect11But5.jpg | ./docs/jdb.md |
| "Avec background" | ./Images/Screens/TyreWithBackground.png | ./docs/jdb.md |
| "Sans background" | ./Images/Screens/TyreWithoutBackground.png | ./docs/jdb.md |
| "Super 11" | ./Images/Screens/Recognised11.png | ./docs/jdb.md |
| "Super H" | ./Images/Screens/RecognisedH.png | ./docs/jdb.md |
| "Super M" | ./Images/Screens/RecognisedM.png | ./docs/jdb.md |
| "Poster V1" | ./Images/Figma/PosterV1.png | ./docs/jdb.md |
| "Poster V2" | ./Images/Figma/PosterV2.png | ./docs/jdb.md |
| "Empty F1TV" | ./Images/Screens/EmptyF1TV.png | ./docs/jdb.md |
| "diformed 11" | ./Images/Screens/Diformed11_1.png | ./docs/jdb.md |
| "diformed 11" | ./Images/Screens/Diformed11_2.png | ./docs/jdb.md |
| "less diformed" | ./Images/Screens/Diformed11ButLess1.png | ./docs/jdb.md |
| "less diformed" | ./Images/Screens/Diformed11ButLess2.png | ./docs/jdb.md |
| "Screen" | ./Images/Screens/SettingsWindowV1.png | ./docs/jdb.md |
| "High Res" | ./Images/Screens/F1TVHIGHRES.png | ./docs/jdb.md |
| "Low Res" | ./Images/Screens/F1TVLOWRES.png | ./docs/jdb.md |
| "ERROR 105" | ./Images/Screens/error105Loading.png | ./docs/jdb.md |
| "ERROR 105" | ./Images/Screens/error105Loading2.png | ./docs/jdb.md |
| "Before fullscreen" | ./Images/Screens/BEFOREFULLSCREEN.png | ./docs/jdb.md |
| "After fullscreen" | ./Images/Screens/AFTERFULLSCREEN.png | ./docs/jdb.md |
| "Exemple settings UI" | ./Images/Screens/SettingsUI1.png | ./docs/jdb.md |
| "Poster V3" | ./Images/Figma/PosterV3.png | ./docs/jdb.md |
| "Poster V4" | ./Images/Figma/PosterV4.png | ./docs/jdb.md |
| "Poster V5" | ./Images/Figma/PosterV5.png | ./docs/jdb.md |
| "Poster V6" | ./Images/Figma/PosterV6.png | ./docs/jdb.md |
| "Poster V7" | ./Images/Figma/PosterV7.png | ./docs/jdb.md |
| "Bordel Figma" | ./Images/Screens/BordelFigma.png | ./docs/jdb.md |
| "Poster V8" | ./Images/Figma/PosterV8.png | ./docs/jdb.md |
| "Poster V9" | ./Images/Figma/PosterV9.png | ./docs/jdb.md |
| "1:45.140" | ./Images/Screens/BadOcr.png | ./docs/jdb.md |
| "Zone de pilote décalée" | ./Images/Screens/BadDriverZone.png | ./docs/jdb.md |
| Pneus cachés | ./Images/Screens/CroppedTyres.png | ./docs/jdb.md |
| "Filtre vanish oxy action sur un secteur violet" | ./Images/Screens/VanishOxyAction.png | ./docs/jdb.md |
| "wtf...?" | ./Images/Screens/wtfF1TV.png | ./docs/jdb.md |
| "Wtf...??" | ./Images/Screens/wtfF1TV1.png | ./docs/jdb.md |
| "Artefacts de detection de sobel" | ./Images/Screens/SobelArtefacts.png | ./docs/jdb.md |
| "Artefacts allègés" | ./Images/Screens/A | ./docs/jdb.md |
| "Ancienne page de settings" | ./Images/Screens/OldSettingsPage.png | ./docs/jdb.md |
| "Nouvelle page de configuration" | ./Images/Screens/newRawSettingsPage.png | ./docs/jdb.md |
| "Nouvelle page de config" | ./Images/Screens/newSettingsPageEmpty.png | ./docs/jdb.md |
| "Nouvelle page de config en plein écran" | ./Images/Screens/newSettingsPageEmptyFullscreen.png | ./docs/jdb.md |
| "Nouvelle page de config en action" | ./Images/Screens/newRawSettingsPageFull.png | ./docs/jdb.md |
| "Première version de la page principale" | ./Images/Screens/MainPageSketch.png | ./docs/jdb.md |
| "Screenshot de la page principale" | ./Images/Screens/MainPage1.png | ./docs/jdb.md |
| "Screenshot de la page principale" | ./Images/Screens/MainPage2.png | ./docs/jdb.md |
| "Dataset Ecarts" | ./Images/Screens/DataSetGaps.png | ./docs/jdb.md |
| "Dataset Tours" | ./Images/Screens/DataSetLaps.png | ./docs/jdb.md |
| "Dataset Noms" | ./Images/Screens/DataSetNames.png | ./docs/jdb.md |
| "Dataset Positions" | ./Images/Screens/DataSetPositions.png | ./docs/jdb.md |
| "Dataset Sectors" | ./Images/Screens/DataSetSectors.png | ./docs/jdb.md |
| "Dataset Tyres" | ./Images/Screens/DataSetTyres.png | ./docs/jdb.md |
| "Diagramme fonctionnement général" | ./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png | ./docs/jdb.md |
| "Diagramme recupération d'images" | ./Images/Figma/DiagrammeRecupImages.png | ./docs/jdb.md |
| "Diagramme OCR" | ./Images/Figma/DiagrammeOCR.png | ./docs/jdb.md |
| "Diagramme Traitement" | ./Images/Figma/DiagrammeTraitement.png | ./docs/jdb.md |
| "Ce que voyait le programme pendant les erreurs 105 ce dimanche" | ./Images/Screens/BadWifi105.png | ./docs/jdb.md |
| "Ce que voyait le programme avant que j'essaie d'implémenter le click auto" | ./Images/Screens/BadLiveHandling.png | ./docs/jdb.md |
| | ./Images/Figma/PosterV7.png | ./docs/index.md |
| "Screenshot du feed data de la f1TV" | ./Images/Screens/ScreenF1TvData.png | ./docs/index.md |
| "Exemple de la Data Channel" | ./Images/Screens/Formula1DataChannel.png | ./docs/index.md |
| "Prototype de l'app fait sur Figma" | ./Images/Figma/Prototype.png | ./docs/index.md |
| "Maquette originale du projet faite sur Figma" | ./Images/Figma/Prototype.png | ./docs/index.md |
| "Maquette originale du projet faite sur Figma" | ./Images/Screens/MainPage2.png | ./docs/index.md |
| "Graphique représentant la quantité de travail requise" | ./Images/Figma/TimeRepartition.png | ./docs/index.md |
| "Logo de Visual Studio 2022" | ./Images/Screens/Vs2022logo.png | ./docs/index.md |
| "Logo de Visual Studio Code" | ./Images/Screens/vsCodelogo.png | ./docs/index.md |
| "Logo de Mkdocs Materials" | ./Images/Screens/MaterialsLogo.png | ./docs/index.md |
| "Logo de Figma" | ./Images/Screens/FigmaLogo.png | ./docs/index.md |
| "Logo de sélénium" | ./Images/Photos/Selenium_Logo.png | ./docs/index.md |
| "Logo de Pupeteer" | ./Images/Photos/Pupetteer_Logo.png | ./docs/index.md |
| "Logo C#" | ./Images/Photos/Csharp_Logo.png | ./docs/index.md |
| "Logo Python" | ./Images/Photos/Python_Logo.png | ./docs/index.md |
| "Logo Firefox Headless" | ./Images/Photos/Firefox_logo_dev.png | ./docs/index.md |
| "Diagramme simplifié représentant le processus de récupération des images" | ./Images/Figma/DiagrammeRecupImages.png | ./docs/index.md |
| "Diagramme simplifié représentant le processus d'OCR" | ./Images/Figma/DiagrammeOCR.png | ./docs/index.md |
| "Diagramme simplifié représentant le processus de traitement et d'affichage" | ./Images/Figma/DiagrammeTraitement.png | ./docs/index.md |
| "Diagramme simplifié représentant le processus global du projet" | ./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png | ./docs/index.md |
| "Exemple insertion AWS en GP" | ./Images/Screens/AWSExample1.jpg | ./docs/index.md |
| "Exemple data d'AWS" | ./Images/Screens/AWSExample2.jpg | ./docs/index.md |
| "Exemple de Data Channel" | ./Images/Screens/ScreenF1TvData.png | ./docs/index.md |
| "Navigateur Headless (sans tête)" | ./Images/Screens/headless-firefox.jpg | ./docs/index.md |
| "Chromium logo" | ./Images/Screens/ChromiumLogo.png | ./docs/index.md |
| "Firefox dev logo" | ./Images/Screens/FirefoxLogo.png | ./docs/index.md |
| "Exemple de zone principale" | ./Images/Screens/MainZoneExample.png | ./docs/index.md |
| "Exemple zone pilote" | ./Images/Screens/DriverZoneExample.png | ./docs/index.md |
| "Exemple Window de pneus" | ./Images/Screens/TyreZoneExemple1.png | ./docs/index.md |
| "Exemple Window temps au tour" | ./Images/Screens/DriverLapTimeExample.png | ./docs/index.md |
| "Exemple window Drs" | ./Images/Screens/DRSFalse.png | ./docs/index.md |
| "Screen F1TV" | ./Images/Screens/ScreenF1TvData.png | ./docs/index.md |
| "Zones principales" | ./Images/Figma/WindowZoneExplanation1.png | ./docs/index.md |
| "Diagramme explicatif de l'architecture des zones" | ./Images/Figma/WindowZoneExplanationDiagram.png | ./docs/index.md |
| "Exemple zone principale" | ./Images/Screens/MainZoneExample.png | ./docs/index.md |
| "Exemple zone de pilote" | ./Images/Screens/DriverZoneExample.png | ./docs/index.md |
| "Exemple de fenêtre de position" | ./Images/Screens/DriverPositionExample.png | ./docs/index.md |
| "Exemple de fenêtre de nom" | ./Images/Screens/DriverNameExample.png | ./docs/index.md |
| "Exemple de fenêtre de temps au tour" | ./Images/Screens/DriverLapTimeExample.png | ./docs/index.md |
| "Exemple de fenêtre pneus" | ./Images/Screens/DriverTyreWindowExample.png | ./docs/index.md |
| "Exemple de chiffre avant post traitement" | ./Images/Figma/Bad9Example.png | ./docs/index.md |
| "9 avec antialiasing" | ./Images/Figma/Aliased9.png | ./docs/index.md |
| "Premier exemple de contours" | ./Images/Figma/Horrible9.png | ./docs/index.md |
| "Second exemple de contours" | ./Images/Figma/Clean9Example.png | ./docs/index.md |
| "Exemple de contour généreux" | ./Images/Figma/Filled9.png | ./docs/index.md |
| "Exemple texte cru" | ./Images/Screens/ExempleTextRaw.png | ./docs/index.md |
| "Texte inversé" | ./Images/Screens/ExempleTextINvertColor.png | ./docs/index.md |
| "Texte après Treshold" | ./Images/Screens/ExempleTextTresholding.png | ./docs/index.md |
| "Texte après Resize" | ./Images/Screens/ExempleTextResize.png | ./docs/index.md |
| "Texte après Dilatation" | ./Images/Screens/ExempleTextDilatation.png | ./docs/index.md |
| "Temps au tour avant traitement" | ./Images/Screens/ExempleLapTimeBefore.png | ./docs/index.md |
| "Temps au tour zoomé" | ./Images/Screens/ExempleLapTimeBeforeUpscaled.png | ./docs/index.md |
| "Temps au tour après Treshold" | ./Images/Screens/ExempleLapTimeTreshold.png | ./docs/index.md |
| "Temps au tour après Resize" | ./Images/Screens/ExempleLapTimeResize.png | ./docs/index.md |
| "Temps au tour après Dilatation" | ./Images/Screens/ExempleLapTimeDilatation.png | ./docs/index.md |
| "Temps au tour après Érosion" | ./Images/Screens/ExempleLapTimeErode.png | ./docs/index.md |
| "Gamme de pneus Pirelli" | ./Images/Photos/Tyres.png | ./docs/index.md |
| "Exemple zone pneus 1" | ./Images/Screens/TyreZoneExemple3.png | ./docs/index.md |
| "Exemple zone pneus 2" | ./Images/Screens/TyreZoneExemple2.png | ./docs/index.md |
| "Exemple zone pneus 3" | ./Images/Screens/TyreZoneExemple1.png | ./docs/index.md |
| "Exemple zone pneus 4" | ./Images/Screens/TyreZoneExemple4.png | ./docs/index.md |
| "Zone complète" | ./Images/Screens/TyreZoneFull.png | ./docs/index.md |
| "Zone coupée automatiquement" | ./Images/Screens/TyreZoneCropped.png | ./docs/index.md |
| "Couleur d'un pneu tendre" | ./Images/Photos/SoftTyreColor.png | ./docs/index.md |
| "Couleur d'un pneu medium" | ./Images/Photos/MediumTyreColor.png | ./docs/index.md |
| "Couleur d'un pneu dur" | ./Images/Photos/HardTyreColor.png | ./docs/index.md |
| "Couleur d'un pneu intermédiaire" | ./Images/Photos/IntermediateTyreColor.png | ./docs/index.md |
| "Couleur d'un pneu pluie" | ./Images/Photos/WetTyreColor.png | ./docs/index.md |
| "Pneu dur avec 0 tours" | ./Images/Screens/TyreZoneHard.png | ./docs/index.md |
| "Couleur moyenne de l'image ci-dessus après soustraction du background" | ./Images/Screens/TyreZoneHardAVG.png | ./docs/index.md |
| "Zone pneu avec le background en moins" | ./Images/Screens/TyreZoneCropedWithoutBackGround.png | ./docs/index.md |
| "Zone avec le reste des couleurs supprimées" | ./Images/Screens/TyreZoneFilter1.png | ./docs/index.md |
| "Filtre 1" | ./Images/Screens/TyreZoneFilter2.png | ./docs/index.md |
| "Resultat" | ./Images/Screens/TyreZoneAfter.png | ./docs/index.md |
| "Exemple treshold" | ./Images/Photos/TresholdExemple1.webp | ./docs/index.md |
| "Exemple d'interpolation linéaire" | ./Images/Photos/InterpolationExemple.png | ./docs/index.md |
| "Exemple des différents types d'interpolation" | ./Images/Photos/BicubicExample.png | ./docs/index.md |
| "Exemple interpolation bicubique (avant)" | ./Images/Photos/BicubicExample1.webp | ./docs/index.md |
| "Exemple interpolation bicubique (après)" | ./Images/Photos/BicubicExample2.webp | ./docs/index.md |
| "Echantillon 720P" | ./Images/Screens/F1TVLOWRES.png | ./docs/index.md |
| "Echantillon 1080P" | ./Images/Screens/F1TVHIGHRES.png | ./docs/index.md |
| "Echantillon 4K" | ./Images/Screens/F1TVHIGHERRES.png | ./docs/index.md |
| "Exemple de secteur en couleur" | ./Images/Screens/VanishRaw.png | ./docs/index.md |
| "Exemple de secteur en grayscale" | ./Images/Screens/VanishGrayScale.png | ./docs/index.md |
| "Exemple de secteur blanchi avec vanishoxyAction" | ./Images/Screens/VanishVanish.png | ./docs/index.md |
| Artefacts de la détection de bords de Sobel | ./Images/Screens/SobelArtefacts.png | ./docs/index.md |
| "Exemple temps au tour" | ./Images/Screens/ExempleLapTimeBefore.png | ./docs/index.md |
| "Exemple temps secteur" | ./Images/Screens/VanishRaw.png | ./docs/index.md |
| "Logo SQLite" | ./Images/Photos/SQLite_Logo.png | ./docs/index.md |
| "Infographie de pneu qui se chevauche" | ./Images/Screens/CroppedTyres.png | ./docs/index.md |
| "Exemple d'affichage live" | ./Images/Screens/SmallDriverInfoExemple.png | ./docs/index.md |
| "Fenêtre d'informations à propos d'un pilote" | ./Images/Screens/SmallDriverInfoFullExemple.png | ./docs/index.md |
| "Exemple fenêtre des batailles" | ./Images/Screens/BattlesWindowExemple.png | ./docs/index.md |
| "Exemple fenêtre des dépassements" | ./Images/Screens/OvertakesWindowExemple.png | ./docs/index.md |
| "Exemple de fenêtre d'informations totalement calculées" | ./Images/Screens/SlowestAndFastestExemple.png | ./docs/index.md |
| "Exemple d'échantillons pour les tests" | ./Images/Screens/DataSetGaps.png | ./docs/index.md |
| "Consommation de mémoire peu après avoir commencé la détection" | ./Images/Screens/MemoryUtilisation.png | ./docs/index.md |
| Diagramme qui montre comment les zones et fenêtres interagissent | ./Images/Figma/ZonesStuctureDiagram.png | ./docs/index.md |
| "Utilisation du processeur pendant le fonctionnement de l'application" | ./Images/Screens/CPUUsage.png | ./docs/index.md |
| "Températures du laptop pendant le fonctionnement de l'application" | ./Images/Photos/PCThermals.jpg | ./docs/index.md |
| "Logo chat Gpt" | ./Images/Screens/GPTLogo.png | ./docs/index.md |
+44 -1
View File
@@ -3200,4 +3200,47 @@ Les performances n'ont pas beaucoup augmenté mais au moins comme ca c'est fait
Aujourd'hui, le but est de finir la documentation et de mettre les derniers commentaires dans le code et faire une première release en BETA.
Pour ce genre de travail un peu pénible je conseille une bonne playlist de phonk. Ca permet d'écrire en rythme.
Pour ce genre de travail un peu pénible je conseille une bonne playlist de phonk. Ca permet d'écrire en rythme.
## Vendredi 09 Juin 2023
La c'est la finalisation de la documentation.
J'ai créé ce petit script avec l'aide de ChatGPT pour créer une table des figures :
```Python3
import os
import re
def generate_figure_table(directory):
table = []
figure_pattern = r'!\[([^\]]*)\]\(([^\)]*)\)'
for root, dirs, files in os.walk(directory):
for file in files:
if file.endswith(".md"):
file_path = os.path.join(root, file)
with open(file_path, "r") as md_file:
content = md_file.readlines()
for line in content:
matches = re.findall(figure_pattern, line)
for match in matches:
alt_text = match[0]
image_path = match[1]
table.append([alt_text, image_path, file_path])
if table:
headers = ["Texte alternatif", "Chemin de l'image", "Fichier Markdown"]
with open("TableDesFigures.md", "w") as file:
file.write("| " + " | ".join(headers) + " |\n")
file.write("|" + "|".join(["---"] * len(headers)) + "|\n")
for row in table:
file.write("| " + " | ".join(row) + " |\n")
print("Le fichier figure_table.md a été généré avec succès.")
else:
print("Aucune figure trouvée dans les fichiers Markdown.")
# Exemple d'utilisation
generate_figure_table("./docs")
```
+1 -1
View File
@@ -31,7 +31,7 @@ markdown_extensions:
plugins:
- glightbox
- search
- img2fig
- table-of-figures
- with-pdf:
cover_subtitle: "Vroum Vroum"
enabled_if_env: ENABLE_PDF_EXPORT
+18 -3
View File
@@ -255,22 +255,37 @@
<li class="md-nav__item">
<a href="/tof.html" class="md-nav__link">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" >
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_5">
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" aria-label="Code" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+14 -9
View File
@@ -160,14 +160,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
@@ -327,9 +332,9 @@ Par exemple : "Tour 28/54, Hamilton a fini par s'arrêter et chausser des gommes
<li><a href="https://www.20min.ch/fr/story/les-leaders-du-championnat-en-fond-de-grille-937035758708">"Commentaire Grand Prix de Belgique 2022"</a></li>
<li><a href="https://www.20min.ch/fr/story/singapour-sous-la-pluie-depart-repousse-432150037887">"Commentaire du Grand Prix de Singapour 2022"</a></li>
</ul>
<figure class="figure-image">
<figure class="figure-image" id="figure-102">
<a class="glightbox" href="./Images/Screens/ExampleLiveTicker.png"><img alt="" commentaires""="" exemple="" src="./Images/Screens/ExampleLiveTicker.png"/></a>
<figcaption>"Exemple commentaires"</figcaption>
<figcaption>Figure 102 - "Exemple commentaires"</figcaption>
</figure>
<p>Pendant un Grand Prix, je dois constamment :</p>
<ul>
@@ -363,9 +368,9 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Il existe des API "Pirates" faites par la communauté, le problème est qu'elles ne sont pas forcément des plus pratiques à utiliser.</p>
<p>Mais comme je possède un abonnement premium ++ à la F1TV, j'ai accès pour chaque grand prix à un flux vidéo nommé : DATA F1 CHANNEL</p>
<p>Qui ressemble à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-103">
<a class="glightbox" href="./Images/Screens/Formula1DataChannel.png"><img alt="" channel="" data="" exemple""="" src="./Images/Screens/Formula1DataChannel.png"/></a>
<figcaption>"Data channel exemple"</figcaption>
<figcaption>Figure 103 - "Data channel exemple"</figcaption>
</figure>
<p>Donc la seule façon que je vois de récupérer ces données est de les prendre directement sur ce feed.</p>
<p>Même si le but final de l'application est de faire pleins de choses super avec les datas, le gros du projet va surtout être la récupération des données et leur stockage.</p>
@@ -394,9 +399,9 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<li>Prédire les temps au tour de chaque pilote selon l'usure des pneus</li>
</ul>
<p>Voici un exemple d'interface possible pour une page :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-104">
<a class="glightbox" href="./Images/Figma/Prototype.png"><img alt="" proto""="" src="./Images/Figma/Prototype.png"/></a>
<figcaption>"Proto"</figcaption>
<figcaption>Figure 104 - "Proto"</figcaption>
</figure>
<h2 id="cas-dutilisation">Cas d'utilisation</h2>
<hr/>
+10 -5
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
@@ -517,7 +522,7 @@
</main>
<footer class="md-footer">
<nav aria-label="Footer" class="md-footer__inner md-grid">
<a aria-label="Previous: Journal de bord" class="md-footer__link md-footer__link--prev" href="../jdb.html" rel="prev">
<a aria-label="Previous: Table of Figures" class="md-footer__link md-footer__link--prev" href="../tof.html" rel="prev">
<div class="md-footer__button md-icon">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"></path></svg>
</div>
@@ -526,7 +531,7 @@
<span class="md-footer__direction">
Previous
</span>
Journal de bord
Table of Figures
</div>
</div>
</a>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
+8 -3
View File
@@ -122,14 +122,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="../tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--nested">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input checked="" class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 894 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.0 KiB

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.1 KiB

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 81 KiB

@@ -1,3 +0,0 @@
[ZoneTransfer]
LastWriterPackageFamilyName=Microsoft.Windows.Photos_8wekyb3d8bbwe
ZoneId=3
@@ -1,4 +0,0 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://hacks.mozilla.org/files/2017/12/headless-firefox.jpg
HostUrl=https://hacks.mozilla.org/files/2017/12/headless-firefox.jpg
@@ -1,4 +0,0 @@
[ZoneTransfer]
ZoneId=3
ReferrerUrl=https://cloudconvert.com/
HostUrl=https://storage.cloudconvert.com/tasks/86d47ecf-9b36-49d7-920d-afdc5a0d7d24/logo.png?AWSAccessKeyId=cloudconvert-production&Expires=1686128919&Signature=lCf1WuDkeA1HMNtNKrFgORZJtJ4%3D&response-content-disposition=attachment%3B%20filename%3D%22logo.png%22&response-content-type=image%2Fpng
Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 17 KiB

+60 -55
View File
@@ -246,14 +246,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
@@ -499,14 +504,14 @@
<h2 id="utilisation-simple">Utilisation "Simple"</h2>
<p>Le but de cette section est de vous permettre d'apprendre à lancer, stopper et modifier les variables de fonctionnement de l'application. Vous serez donc en mesure d'utiliser le programme correctement.</p>
<p>Vous devez commencer par lancer le programme.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-105">
<a class="glightbox" href="./Images/Manual/StartPage.png"><img alt="" de="" lancement""="" page="" src="./Images/Manual/StartPage.png"/></a>
<figcaption>"Page de lancement"</figcaption>
<figcaption>Figure 105 - "Page de lancement"</figcaption>
</figure>
<p>Au lancement de l'app, vous devriez avoir une page comme ci-dessus. Il y a beaucoup d'infos, mais pour le moment ce qui nous intéresse, c'est le menu en haut à gauche.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-106">
<a class="glightbox" href="./Images/Manual/Controls.png"><img alt="" contrôles""="" src="./Images/Manual/Controls.png"/></a>
<figcaption>"Contrôles"</figcaption>
<figcaption>Figure 106 - "Contrôles"</figcaption>
</figure>
<p>Si c'est la première fois que vous utilisez l'application, il est possible qu'il n'y ait qu'un seul preset au lieu des quatre ci-dessous voire 0 si vous n'avez pas mis le preset inclus dans l'installation. Si vous n'avez aucun preset, passez directement à l'étape calibration avant de revenir ici.</p>
<p>Comme vous pouvez le voir, en plus des presets sélectionnables, il y a quatre boutons (dont deux grisés) et une boite de texte avec un lien.</p>
@@ -514,16 +519,16 @@
<h3 id="recuperer-le-lien-vers-le-flux">Récupérer le lien vers le flux</h3>
<p>Pour remplir la boite de texte précitée, il nous faut un lien et ce lien, on le trouve sur la <a href="https://f1tv.formula1.com/">F1TV</a>.</p>
<p>Quand vous vous rendez sur la F1TV la page principale devrait ressembler à quelque chose comme ça (évidemment le contenu ne sera pas le même) :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-107">
<a class="glightbox" href="./Images/Manual/F1TvMainPage.png"><img alt="" de="" f1tv""="" la="" page="" principale="" src="./Images/Manual/F1TvMainPage.png"/></a>
<figcaption>"Page principale de la F1TV"</figcaption>
<figcaption>Figure 107 - "Page principale de la F1TV"</figcaption>
</figure>
<p>Si vous ne vous êtes pas déjà connecté, connectez-vous et ensuite, allez sur la page du Grand Prix qui vous intéresse.</p>
<p>Pour un Grand Prix en direct, normalement, il y a un endroit où vous pouvez cliquer pour accéder au flux directement, et si vous voulez utiliser un Grand Prix en différé, vous pouvez aller dans "202x Season" ou x est l'année en cours, en l'occurrence 2023. Et là, vous pourrez sélectionner un Grand Prix.</p>
<p>Dans tous les cas, quand vous avez sélectionné votre Grand Prix, vous devriez vous retrouver sur une page de ce style :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-108">
<a class="glightbox" href="./Images/Manual/F1TvGpPage.png"><img alt="" d'un="" f1tv""="" grand="" la="" page="" prix="" src="./Images/Manual/F1TvGpPage.png" sur=""/></a>
<figcaption>"Page d'un Grand Prix sur la F1TV"</figcaption>
<figcaption>Figure 108 - "Page d'un Grand Prix sur la F1TV"</figcaption>
</figure>
<p>Et ici si vous êtes sur un Grand Prix en direct, vous pouvez directement copier l'URL de la page et si c'est un Grand Prix en différé, vous pouvez directement naviguer avec la barre de progression vidéo du lecteur de la F1TV, Je conseille de la placer juste après le départ. Vous pouvez prendre le lien avant ou après avoir changé le timecode de la vidéo, cela ne change rien, le lien ne contient pas votre progression dans la vidéo.</p>
<p>Ensuite, vous pourrez juste mettre le lien que vous avez récupéré dans la boite de texte que l'on a vu précédemment. Il faut simplement s'assurer que le lien contient bien le terme <code>?action=play</code> à la fin.</p>
@@ -533,9 +538,9 @@
<p>Le bouton Launch permet de lancer le programme. Le texte peut changer (Par exemple en 'Retry' si le lancement a raté) mais son utilité reste la même : Lancer le navigateur virtuel qui sera requis pour traiter les données.</p>
<p>Si vous cliquez sur Launch tous les boutons devraient être grisés, c'est normal. Pendant le lancement du navigateur, l'application ne peut pas être utilisée pour éviter des conflits. Il faut juste attendre. Vous aurez également des fenêtres d'invite de commande qui vont s'ouvrir et se fermer, c'est tout à fait normal et il ne faut pas interagir avec tant que tout ne s'est pas stabilisé.</p>
<p>Vous devriez voir enfin une fenêtre comme celle ci :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-109">
<a class="glightbox" href="./Images/Manual/SuspectCmd.png"><img (pas="" alt="" de="" elle="" l'est="" ne="" page="" panique,="" pas)""="" src="./Images/Manual/SuspectCmd.png" suspecte=""/></a>
<figcaption>"Page suspecte (Pas de panique, elle ne l'est pas)"</figcaption>
<figcaption>Figure 109 - "Page suspecte (Pas de panique, elle ne l'est pas)"</figcaption>
</figure>
<p>Il ne faut pas fermer cette fenêtre. C'est la seule chose qui nous relie au navigateur virtuel qu'utilise l'application. Il ne faut pas la fermer, par contre, vous pouvez la réduire et la laisser en background, c'est d'ailleurs ce que je vous recommande de faire.</p>
<p>Peu après l'ouverture de cette fenêtre, vous devriez avoir accès à trois boutons.</p>
@@ -545,16 +550,16 @@
<li>Bouton 'Start' lance le processus de récupération de données.</li>
</ul>
<p>Si vous cliquez sur ce dernier, vous lancerez le programme. Cela peut prendre quelque secondes à s'actualiser, mais très vite vous devriez vous trouver devant une page comme celle-ci :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-110">
<a class="glightbox" href="./Images/Manual/StartOfSimulation.png"><img alt="" du="" début="" programme""="" src="./Images/Manual/StartOfSimulation.png"/></a>
<figcaption>"Début du programme"</figcaption>
<figcaption>Figure 110 - "Début du programme"</figcaption>
</figure>
<p>Vous n'aurez alors qu'un seul bouton disponible : le bouton 'Stop'.</p>
<p>Vous pouvez arrêter le programme quand vous le voulez. ATTENTION : Avant de fermer le programme, merci de stopper d'abord le processus.</p>
<p>Si vous stoppez le processus, vous devriez vous retrouver dans la même situation que juste après avoir lancé le navigateur virtuel :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-111">
<a class="glightbox" href="./Images/Manual/Stopeed.png"><img alt="" arrêt="" du="" programme""="" src="./Images/Manual/Stopeed.png"/></a>
<figcaption>"Arrêt du programme"</figcaption>
<figcaption>Figure 111 - "Arrêt du programme"</figcaption>
</figure>
<p>Vous pouvez voir en dessous la dernière image que le programme a décodée et vous avez de nouveau accès aux trois boutons expliqués précédemment.</p>
<p>Quand l'application a été lancée, vous pouvez aussi cliquer sur les données affichées, mais ces comportements sont expliqués dans la section "Comprendre les données"</p>
@@ -575,9 +580,9 @@
<h3 id="comment-creer-son-preset">Comment créer son Preset</h3>
<p>Pour créer son Preset, il faut utiliser la page Settings ou Config de l'application.</p>
<p>Pour y accéder, il faut simplement cliquer sur le bouton "Config" de la page principale et vous serez accueilli par une page qui devrait ressembler à celle ci dessous :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-112">
<a class="glightbox" href="./Images/Manual/EmptySettingsPage.png"><img alt="" config="" de="" page="" src="./Images/Manual/EmptySettingsPage.png" vide""=""/></a>
<figcaption>"Page de config vide"</figcaption>
<figcaption>Figure 112 - "Page de config vide"</figcaption>
</figure>
<p>La seule différence est que vous aurez sûrement moins de Presets dans la liste des Presets voir, vous pouvez n'en avoir aucuns.</p>
<p>Comme vous pouvez le voir, vous n'avez pas énormément d'options disponibles quand vous lancez simplement l'application.</p>
@@ -587,14 +592,14 @@
<p>Le but, c'est de mettre le lien vers un Grand Prix pour pouvoir avoir une image de test. Pour voir comment récupérer cet URL, voir la section (Utilisation "simple" → "Récupérer le lien vers le flux")</p>
<p>Quand l'URL a été placée au bon endroit, on peut cliquer sur le bouton "Start" et attendre. Si vous n'avez pas encore lu la partie "Utilisation "simple"", vous allez voir des invites de commandes s'ouvrir et se fermer et c'est tout à fait normal.</p>
<p>Il faut attendre d'avoir une invite de commande qui reste ouverte et qui ressemble à celle ci dessous avant de faire quoi que ce soit. Ensuite, vous pourrez simplement réduire cette fenêtre et retourner sur la page de configuration.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-113">
<a class="glightbox" href="./Images/Manual/SettingsPageWithCmdOpen.png"><img alt="" commande="" de="" invite="" mais="" normale""="" src="./Images/Manual/SettingsPageWithCmdOpen.png" suspecte,=""/></a>
<figcaption>"Invite de commande suspecte, mais normale"</figcaption>
<figcaption>Figure 113 - "Invite de commande suspecte, mais normale"</figcaption>
</figure>
<p>Ensuite, si vous attendez un peu (le processus peut prendre jusqu'à plusieurs dizaines de secondes), vous aurez soit une erreur, soit vous vous retrouverez avec une page qui ressemble à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-114">
<a class="glightbox" href="./Images/Manual/SettingsPageWithStartedF1TV.png"><img alt="" amorcée""="" config="" de="" page="" src="./Images/Manual/SettingsPageWithStartedF1TV.png"/></a>
<figcaption>"Page de config amorcée"</figcaption>
<figcaption>Figure 114 - "Page de config amorcée"</figcaption>
</figure>
<p>Et là on voit que toutes les options ont été débloquées.</p>
<p>Avant de se pencher sur les nouvelles options, on va rester sur le fonctionnement général. Le bouton "Get a newer image" permet d'avoir une image plus récente de la F1TV. C'est utile par exemple, car comme on le voit sur l'exemple, l'interface de la F1TV n'a pas encore eu le temps de disparaitre. Mais cela peut aussi être utile plus tard dans le cas où vous voudriez que certaines infos s'affichent.</p>
@@ -611,47 +616,47 @@
<p>Le programme de calibration est fait pour que vous n'ayez besoin de donner que les informations qu'il ne peut pas deviner.</p>
<p>Il y a deux étapes :</p>
<p>La première étape est de donner les dimensions de la zone principale d'informations. Pour ce faire, il faut dans un premier temps cliquer sur le bouton "Create the main zone" qui devrait afficher le texte suivant en dessous après avoir cliqué :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-115">
<a class="glightbox" href="./Images/Manual/2PointsRemaining.png"><img ajouter""="" alt="" de="" indiquant="" le="" nombre="" points="" qu'il="" reste="" src="./Images/Manual/2PointsRemaining.png" texte="" à=""/></a>
<figcaption>"Texte indiquant le nombre de points qu'il reste à ajouter"</figcaption>
<figcaption>Figure 115 - "Texte indiquant le nombre de points qu'il reste à ajouter"</figcaption>
</figure>
<p>Ensuite, il va falloir cliquer directement sur l'image pour indiquer le coin en haut à gauche et le point en bas à droite de la zone rectangulaire qui contient les informations.</p>
<p>Vous pouvez voir en bleu ci-dessous les coins du rectangle et en rouge l'endroit où il faut cliquer.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-116">
<a class="glightbox" href="./Images/Manual/WhereToDrawMainZone.png"><img alt="" de="" expliquant="" infographie="" la="" les="" ="" placer="" points="" principale""="" src="./Images/Manual/WhereToDrawMainZone.png" zone=""/></a>
<figcaption>"Infographie expliquant où placer les points de la zone principale"</figcaption>
<figcaption>Figure 116 - "Infographie expliquant où placer les points de la zone principale"</figcaption>
</figure>
<p>Il faut faire attention à bien prendre tous les pilotes MAIS il faut également faire attention à ne pas prendre le texte alentours.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-117">
<a class="glightbox" href="./Images/Manual/ForbiddenZone.png"><img alt="" dans="" doit="" la="" ne="" pas="" qui="" src="./Images/Manual/ForbiddenZone.png" sélectionnée""="" texte="" zone="" être=""/></a>
<figcaption>"Texte qui ne doit pas être dans la zone sélectionnée"</figcaption>
<figcaption>Figure 117 - "Texte qui ne doit pas être dans la zone sélectionnée"</figcaption>
</figure>
<p>Ci dessus, on peut voir du texte barré en violet. Il ne faut surtout pas que la zone vienne inclure ces bouts de texte ou toute la calibration pourrait rater.</p>
<p>Ensuite, si vous avez bien fait votre travail, au deuxième clic sur la page, vous aurez quelques secondes de flottement et ensuite, vous devriez avoir les contours que vous avez dessinés affichés en jaune avec pleins de plus petites zones à l'intérieur comme ci-dessous :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-118">
<a class="glightbox" href="./Images/Manual/DriverZones.png"><img alt="" automatiquement="" avec="" calculées""="" de="" les="" pilotes="" principale="" src="./Images/Manual/DriverZones.png" zone="" zones=""/></a>
<figcaption>"Zone principale avec les zones de pilotes automatiquement calculées"</figcaption>
<figcaption>Figure 118 - "Zone principale avec les zones de pilotes automatiquement calculées"</figcaption>
</figure>
<p>Le programme a non seulement pris en compte la zone, mais il a aussi détecté automatiquement où se trouvaient les zones de chaque pilote. Si vous n'avez pas un résultat comme celui-là et/ou que les zones ne sont pas bien alignées sur les pilotes sur l'image, je vous conseille de réessayer de créer la zone principale.</p>
<p>La seconde étape est de montrer où sont les fenêtres d'infos au programme.</p>
<p>Vous aurez peut-être remarqué qu'en dessous de l'image principale, quand l'affichage jaune a été appliqué, une image est apparue.</p>
<p>Elle devrait ressembler à quelque chose dans ce style :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-119">
<a class="glightbox" href="./Images/Manual/DriverZone.png"><img alt="" d'une="" de="" image="" pilote""="" src="./Images/Manual/DriverZone.png" zone=""/></a>
<figcaption>"Image d'une zone de pilote"</figcaption>
<figcaption>Figure 119 - "Image d'une zone de pilote"</figcaption>
</figure>
<p>C'est une zone de pilote de l'image que l'on voit au-dessus et c'est ici que l'on va indiquer les zones intéressantes.</p>
<p>Pour ce faire, il faut cliquer sur le bouton "Create Windows" et ce message devrait s'afficher un peu en dessous :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-120">
<a class="glightbox" href="./Images/Manual/9WindowsRemaining.png"><img ajouter""="" alt="" de="" indiquant="" le="" nombre="" src="./Images/Manual/9WindowsRemaining.png" texte="" windows="" à=""/></a>
<figcaption>"Texte indiquant le nombre de windows à ajouter"</figcaption>
<figcaption>Figure 120 - "Texte indiquant le nombre de windows à ajouter"</figcaption>
</figure>
<p>Cela nous indique le nombre de fenêtres qu'il nous reste à sélectionner.</p>
<p>La technique est la même que pour la grande zone sauf que là, il faut le faire neuf fois. Et il faut absolument le faire dans l'ordre de gauche à droite.</p>
<p>Le but est de tout sélectionner et d'arriver à ce résultat :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-121">
<a class="glightbox" href="./Images/Manual/Windows.png"><img alt="" de="" découpées""="" exemple="" fenêtres="" src="./Images/Manual/Windows.png"/></a>
<figcaption>"Exemple de fenêtres découpées"</figcaption>
<figcaption>Figure 121 - "Exemple de fenêtres découpées"</figcaption>
</figure>
<p>Dans l'ordre, de gauche à droite, on veut récupérer :</p>
<ul>
@@ -668,18 +673,18 @@
<h4 id="ajout-du-nom-des-pilotes">Ajout du nom des pilotes</h4>
<p>La dernière info qui manque à notre programme est la liste des pilotes présents.</p>
<p>On peut interagir avec cette liste ici :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-122">
<a class="glightbox" href="./Images/Manual/DriverListControls.png"><img alt="" avec="" d'interaction="" de="" la="" liste="" menu="" pilotes""="" src="./Images/Manual/DriverListControls.png"/></a>
<figcaption>"Menu d'interaction avec la liste de pilotes"</figcaption>
<figcaption>Figure 122 - "Menu d'interaction avec la liste de pilotes"</figcaption>
</figure>
<p>Dans la boite de texte, on peut écrire le nom d'un pilote qui peut être trouvé sur l'image, on peut l'ajouter à la liste et si on a fait une erreur, on peut le retirer.</p>
<p>Et c'est à peu près tout. Il ne reste maintenant plus qu'à mettre tous les noms.</p>
<p>TIP : Il peut être intéressant d'ajouter le nom des pilotes de réserve pour éviter de venir changer son preset si un pilote n'est pas présent pour cause de maladie ou de blessure. Il faut simplement faire attention de ne pas non plus mettre trop de noms pour éviter que le programme puisse confondre.</p>
<p>Et voilà ! On a toutes les infos nécessaires.</p>
<p>La page de configuration devrait ressembler à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-123">
<a class="glightbox" href="./Images/Manual/SettingsReady.png"><img ajouté="" alt="" après="" avoir="" config="" de="" image="" infos""="" la="" les="" page="" src="./Images/Manual/SettingsReady.png" toutes=""/></a>
<figcaption>"Image de la page de config après avoir ajouté toutes les infos"</figcaption>
<figcaption>Figure 123 - "Image de la page de config après avoir ajouté toutes les infos"</figcaption>
</figure>
<p>Il ne reste plus qu'à le sauvegarder.</p>
<h4 id="sauvegarder-le-nouveau-preset">Sauvegarder le nouveau Preset</h4>
@@ -688,25 +693,25 @@
<p>Vous pouvez ainsi utiliser l'application normalement en sélectionnant votre nouveau preset à chaque fois.</p>
<h3 id="load-un-preset-existant">Load un Preset existant</h3>
<p>Le loading est un peu spécial. Il faut déjà avoir lancé le navigateur virtuel pour activer les boutons. Ensuite, il suffit de sélectionner un preset et de cliquer sur "Load the Preset" et attendre un petit peu. L'affichage sera un peu bizarre, mais c'est normal, il ne faut pas s'inquiéter si la zone de pilote affichée en dessous est correcte.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-124">
<a class="glightbox" href="./Images/Manual/LoadedPreset.png"><img alt="" bizarre="" ce="" de="" et="" exemple="" implique""="" l'affichage="" loading="" peut="" que="" quoi="" ressembler="" src="./Images/Manual/LoadedPreset.png" un="" à="" ça=""/></a>
<figcaption>"Exemple de ce à quoi peut ressembler un loading et l'affichage bizarre que ça implique"</figcaption>
<figcaption>Figure 124 - "Exemple de ce à quoi peut ressembler un loading et l'affichage bizarre que ça implique"</figcaption>
</figure>
<p>À partir de là, il est facile de faire son propre preset en changeant juste les noms des pilotes par exemple.</p>
<h2 id="comprendre-les-donnees">Comprendre les données</h2>
<p>Ici, vous allez apprendre à utiliser l'application et ses données en comprenant à quoi elles servent et comment elles sont affichées.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-125">
<a class="glightbox" href="./Images/Manual/Simulation.png"><img alt="" cours="" de="" depuis="" en="" fonctionnement="" image="" l'application="" minutes""="" quelques="" src="./Images/Manual/Simulation.png"/></a>
<figcaption>"Image de l'application en cours de fonctionnement depuis quelques minutes"</figcaption>
<figcaption>Figure 125 - "Image de l'application en cours de fonctionnement depuis quelques minutes"</figcaption>
</figure>
<p>Il y a 5 types de données :</p>
<h3 id="overtakes">Overtakes</h3>
<p>Cette fenêtre est loin d'être complètement opérationnelle, mais elle permet de voir l'historique des dépassements et des changements de position. Il faut scroller pour voir les plus récents.</p>
<p>Je dirais que pour le moment, c'est la moins intéressante et elle ne fonctionne pas toujours super.</p>
<h3 id="last-five-laps">Last Five Laps</h3>
<figure class="figure-image">
<figure class="figure-image" id="figure-126">
<a class="glightbox" href="./Images/Manual/LastFiveLAps.png"><img alt="" cinq="" de="" derniers="" des="" fenêtre="" image="" la="" src="./Images/Manual/LastFiveLAps.png" tours""=""/></a>
<figcaption>"Image de la fenêtre des cinq derniers tours"</figcaption>
<figcaption>Figure 126 - "Image de la fenêtre des cinq derniers tours"</figcaption>
</figure>
<p>En total contraste avec la fenêtre Overtakes, ici, on a peut-être la fenêtre la plus intéressante de toutes.</p>
<p>On peut voir les pilotes actuellement les plus rapides et plus lents sur le circuit. Le calcul est fait sur la moyenne des cinq derniers tours de chaque pilote. Cela permet de se faire une idée de la situation des pilotes.</p>
@@ -714,9 +719,9 @@
<p>Il est par exemple intéressant de voir la différence de vitesse entre les pneus secs et pluie sur un circuit qui commence à sécher. On peut progressivement voir les pilotes en pneus secs devenir de plus en plus rapides alors que ce sont des pilotes beaucoup moins rapide en temps normal.</p>
<p>On peut cliquer sur n'importe lequel de ces pilotes pour voir ses infos apparaître dans la fenêtre Driver Infos pour voir les cinq derniers tours par exemple ou les pneus qu'il est en train de chausser.</p>
<h3 id="battles">Battles</h3>
<figure class="figure-image">
<figure class="figure-image" id="figure-127">
<a class="glightbox" href="./Images/Manual/Battles.png"><img alt="" batailles""="" des="" fenêtre="" src="./Images/Manual/Battles.png"/></a>
<figcaption>"Fenêtre des batailles"</figcaption>
<figcaption>Figure 127 - "Fenêtre des batailles"</figcaption>
</figure>
<p>Cette fenêtre est également assez intéressante, car elle permet de voir les pilotes qui sont en train de se battre. Il est estimé qu'un pilote qui se bat est un pilote qui est à trois secondes ou moins du pilote devant lui.</p>
<p>Ne sont affichées que les batailles de quatre pilotes maximums dans l'ordre du classement.</p>
@@ -726,22 +731,22 @@ Dans la zone du DRS (Une seconde ou moins) il est écrit en vert.</p>
<p>On peut aussi cliquer sur le nom d'un pilote pour afficher ses infos dans la fenêtre des infos pilote.</p>
<p>Cette fenêtre permet de mieux comprendre qui sont les pilotes qu'il faut garder à l'œil à la TV ou simplement qui sont les pilotes qui sont très proches et qui pourraient se mettre la pression pour les arrêts aux stands, car jamais un pilote ne reste à moins de trois secondes d'un autre si ça n'est pas pour tenter quelque chose au niveau stratégique.</p>
<h3 id="driver-infos">Driver infos</h3>
<figure class="figure-image">
<figure class="figure-image" id="figure-128">
<a class="glightbox" href="./Images/Manual/DriverInfos.png"><img alt="" des="" fenêtre="" infos="" pilote""="" src="./Images/Manual/DriverInfos.png"/></a>
<figcaption>"Fenêtre des infos pilote"</figcaption>
<figcaption>Figure 128 - "Fenêtre des infos pilote"</figcaption>
</figure>
<p>Ici, on peut voir toutes les infos lives d'un pilote.</p>
<p>Rien de fou à dire sur la partie de gauche, par contre la partie de droite est un peu plus intéressante, car elle contient un historique de ses cinq derniers tours (dans la photo, il n'y en a qu'un seul, mais au fur et à mesure de la course cela se remplit).</p>
<p>On peut non seulement voir les cinq derniers temps au tour, mais on peut aussi cliquer sur chacun d'eux pour voir les secteurs associés.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-129">
<a class="glightbox" href="./Images/Manual/LapInfos.png"><img alt="" au="" d'affichage="" d'un="" des="" exemple="" secteurs="" src="./Images/Manual/LapInfos.png" temps="" tour""=""/></a>
<figcaption>"Exemple d'affichage des secteurs d'un temps au tour"</figcaption>
<figcaption>Figure 129 - "Exemple d'affichage des secteurs d'un temps au tour"</figcaption>
</figure>
<p>;</p>
<h3 id="live-ranking">Live Ranking</h3>
<figure class="figure-image">
<figure class="figure-image" id="figure-130">
<a class="glightbox" href="./Images/Manual/LiveRanking.png"><img alt="" classement="" direct""="" du="" en="" fenêtre="" src="./Images/Manual/LiveRanking.png"/></a>
<figcaption>"Fenêtre du classement en direct"</figcaption>
<figcaption>Figure 130 - "Fenêtre du classement en direct"</figcaption>
</figure>
<p>Ceci est la fenêtre la plus simple. C'est tout bêtement le classement actuel avec les écarts avec le leader.</p>
<p>Note : On peut également cliquer sur les différents pilotes pour en afficher les infos dans la fenêtre infos pilote.</p>
+210 -205
View File
@@ -893,14 +893,19 @@
Journal de bord
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="tof.html">
Table of Figures
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" id="__nav_5" type="checkbox"/>
<label class="md-nav__link" for="__nav_5">
<input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" id="__nav_6" type="checkbox"/>
<label class="md-nav__link" for="__nav_6">
Code
<span class="md-nav__icon md-icon"></span>
</label>
<nav aria-label="Code" class="md-nav" data-md-level="1">
<label class="md-nav__title" for="__nav_5">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
Code
</label>
@@ -1785,9 +1790,9 @@
<h1 id="rapport-track-trends-v10">Rapport Track Trends V1.0</h1>
<hr/>
<p>Rohmer Maxime Travail de diplôme Technicien ES 2023</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-1">
<a class="glightbox" href="./Images/Figma/PosterV7.png"><img alt="" src="./Images/Figma/PosterV7.png"/></a>
<figcaption></figcaption>
<figcaption>Figure 1 - </figcaption>
</figure>
<h2 id="introduction">Introduction</h2>
<hr/>
@@ -1795,9 +1800,9 @@
<p>Track Trends est un outil de récupération et d'analyse de données de courses de Formule 1.</p>
<p>Pour le contexte, en dehors des cours, j'exerce différentes activités dont celle de Live Ticker F1 pour le 20 minutes. Pour m'aider dans ce travail, j'utilise actuellement la F1TV à laquelle je suis abonné qui me propose non seulement un feed vidéo de meilleure qualité avec des commentaires plus pertinents que ceux de la RTS mais qui aussi me permet d'accéder à un feed vidéo très important : la chaine data.</p>
<p>Ce dernier ressemble à cela :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-2">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" data="" de="" du="" f1tv""="" feed="" la="" screenshot="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Screenshot du feed data de la f1TV"</figcaption>
<figcaption>Figure 2 - "Screenshot du feed data de la f1TV"</figcaption>
</figure>
<p>(Attention, ce n'est pas un joli tableau HTML, mais bien une vidéo qui contient un tableau.)</p>
<p>Sauf que toutes les informations sont étalées pêle-mêle sans hiérarchie, ce qui fait que cela me prendrait trop de temps de tout déchiffrer à chaque fois, ce qui me fait rater des choses intéressantes.</p>
@@ -1860,9 +1865,9 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Il existe des API "Pirates" faites par la communauté, le problème est qu'elles ne sont pas forcément des plus pratiques à utiliser.</p>
<p>Mais comme je possède un abonnement premium ++ à la F1TV, j'ai accès pour chaque grand prix à un flux vidéo nommé : DATA F1 CHANNEL</p>
<p>Qui ressemble à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-3">
<a class="glightbox" href="./Images/Screens/Formula1DataChannel.png"><img alt="" channel""="" data="" de="" exemple="" la="" src="./Images/Screens/Formula1DataChannel.png"/></a>
<figcaption>"Exemple de la Data Channel"</figcaption>
<figcaption>Figure 3 - "Exemple de la Data Channel"</figcaption>
</figure>
<p>Donc la seule façon que je vois de récupérer ces données est de les prendre directement sur ce feed.</p>
<p>Même si le but final de l'application est de faire pleins de choses super avec les datas, le gros du projet va surtout être la récupération des données et leur stockage.</p>
@@ -1891,9 +1896,9 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<li>Prédire les temps au tour de chaque pilote selon l'usure des pneus</li>
</ul>
<p>Voici un exemple d'interface possible pour une page :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-4">
<a class="glightbox" href="./Images/Figma/Prototype.png"><img alt="" de="" fait="" figma""="" l'app="" prototype="" src="./Images/Figma/Prototype.png" sur=""/></a>
<figcaption>"Prototype de l'app fait sur Figma"</figcaption>
<figcaption>Figure 4 - "Prototype de l'app fait sur Figma"</figcaption>
</figure>
<h3 id="cas-dutilisation">Cas d'utilisation</h3>
<hr/>
@@ -1951,13 +1956,13 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Ensuite pour ce qui est des prédictions, il n'y en a aucunes comme ça, c'est simple.</p>
<p>Si on ne regarde que de très loin le CDC et le projet final, on pourrait dire que c'est plutôt décevant puisqu'il manque beaucoup de choses comme les prédictions et certains affichages.</p>
<p>On peut aussi se dire ça en comparant la maquette du CDC et le résultat final.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-5">
<a class="glightbox" href="./Images/Figma/Prototype.png"><img alt="" du="" faite="" figma""="" maquette="" originale="" projet="" src="./Images/Figma/Prototype.png" sur=""/></a>
<figcaption>"Maquette originale du projet faite sur Figma"</figcaption>
<figcaption>Figure 5 - "Maquette originale du projet faite sur Figma"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-6">
<a class="glightbox" href="./Images/Screens/MainPage2.png"><img alt="" du="" faite="" figma""="" maquette="" originale="" projet="" src="./Images/Screens/MainPage2.png" sur=""/></a>
<figcaption>"Maquette originale du projet faite sur Figma"</figcaption>
<figcaption>Figure 6 - "Maquette originale du projet faite sur Figma"</figcaption>
</figure>
<p>Clairement, un œil non avisé pourrait être très déçu et pourrait dire que c'est un échec.</p>
<p>Et moi je vais vous expliquer pourquoi, au contraire c'est un total succès.</p>
@@ -1965,9 +1970,9 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Ensuite, si on regarde bien, on a quand même une application qui nous permet de suivre les informations de la course et qui calcule des choses à notre place. C'est déjà une grosse plus-value par rapport à la page Data de la F1TV.</p>
<p>Et finalement, les prédictions, les affichages et le style, ce sont les choses les moins compliquées du projet. On ne se rend pas compte que pour simplement afficher les 20 pilotes dans le bon ordre, il faut énormément de travail.</p>
<p>Voici une petite représentation graphique de la quantité de travail nécessaire pour en arriver à l'état actuel du projet :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-7">
<a class="glightbox" href="./Images/Figma/TimeRepartition.png"><img alt="" de="" graphique="" la="" quantité="" représentant="" requise""="" src="./Images/Figma/TimeRepartition.png" travail=""/></a>
<figcaption>"Graphique représentant la quantité de travail requise"</figcaption>
<figcaption>Figure 7 - "Graphique représentant la quantité de travail requise"</figcaption>
</figure>
<p>Pour en arriver à un affichage, il a fallu récupérer automatiquement les images en utilisant un browser headless ce qui a pris un temps fou à mettre en place et il a fallu surtout lire les informations que l'on recevait des images.</p>
<p>J'ai passé presque 90% du temps de mon projet à développer des choses qui permettront ensuite de faire de l'affichage.</p>
@@ -2066,26 +2071,26 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
<hr/>
<h3 id="outils-utilises">Outils utilisés</h3>
<h4 id="visual-studio-2022">Visual Studio 2022</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-8">
<a class="glightbox" href="./Images/Screens/Vs2022logo.png"><img 2022""="" alt="" de="" logo="" src="./Images/Screens/Vs2022logo.png" studio="" visual=""/></a>
<figcaption>"Logo de Visual Studio 2022"</figcaption>
<figcaption>Figure 8 - "Logo de Visual Studio 2022"</figcaption>
</figure>
<p>C'est l'application que j'ai le plus utilisé, je pense. Visual Studio 2022 est l'IDE officiel de Microsoft pour coder en C#.</p>
<p>C'est l'outil que j'utilise depuis maintenant six ans au CFPT et franchement, il fait tout ce que je pourrais vouloir. C'est aussi un outil pratique pour utiliser Windows Forms et faire des applications natives Windows.</p>
<p>Pas grand-chose à dire à ce sujet à part que c'est un outil qui marche bien et qui est gratuit si on prend la community édition.</p>
<h4 id="visual-studio-code">Visual Studio Code</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-9">
<a class="glightbox" href="./Images/Screens/vsCodelogo.png"><img alt="" code""="" de="" logo="" src="./Images/Screens/vsCodelogo.png" studio="" visual=""/></a>
<figcaption>"Logo de Visual Studio Code"</figcaption>
<figcaption>Figure 9 - "Logo de Visual Studio Code"</figcaption>
</figure>
<p>Cet outil est déjà un peu plus intéressant. C'est le second outil que j'ai le plus utilisé. J'en ai surtout eu besoin pour écrire de la doc, mais aussi pour coder en python et pour contrôler mkdocs.</p>
<p>Visual Studio est un IDE absolument génial qui est très puissant avec les bonnes extensions. Je l'utilise au quotidien pour tout ce qui est développement WEB, Mobile ou pour éditer des fichiers de configs pour mes drones ou imprimantes 3D. Je peux même compiler le firmware pour ces dernières en utilisant une extension faite pour.</p>
<p>Les possibilités de customisation sont presque infinies et c'est un plaisir d'utiliser ce logiciel gratuit fourni par Microsoft, mais qui est amélioré constamment par des développeurs indépendants.</p>
<p>Je conseille à n'importe quel développeur de l'essayer à moins qu'il soit uniquement sur C# ou il serait plus intéressant d'utiliser visual studio 2022.</p>
<h4 id="materialmkdocsmarkdown">Material/Mkdocs/Markdown</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-10">
<a class="glightbox" href="./Images/Screens/MaterialsLogo.png"><img alt="" de="" logo="" materials""="" mkdocs="" src="./Images/Screens/MaterialsLogo.png"/></a>
<figcaption>"Logo de Mkdocs Materials"</figcaption>
<figcaption>Figure 10 - "Logo de Mkdocs Materials"</figcaption>
</figure>
<p>Pendant ce projet, j'ai utilisé exclusivement du Markdown avec l'aide de Mkdocs et Materials.</p>
<p>Le choix de Markdown a été plutôt simple, c'est une façon facile et efficace de créer de la documentation et on n'avait pas le choix de l'utiliser.</p>
@@ -2093,9 +2098,9 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
<p>Mkdocs et Materials sont deux outils vraiment fantastiques, mais je dois avouer que je n'ai pas assez mis de temps pour apprendre tout leur potentiel. Pour moi ce sont simplement des outils et je veux qu'ils marchent. Je ne suis pas forcément du genre à aller changer toutes les couleurs et polices pour avoir la doc parfaite, j'ai préféré passer du temps sur mon app. Mais même si ces outils offrent une customisation très avancée, il est très facile de créer un projet simple et j'aime beaucoup cette simplicité.</p>
<p>J'ai eu pas mal d'aide de la part de M. Briard pour implémenter certaines features et je l'en remercie très chaudement, car sans son aide ce document serait sûrement un peu moins commode à lire (Oui oui ça aurait pu être pire, je sais, c'est dur à imaginer).</p>
<h4 id="figma">Figma</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-11">
<a class="glightbox" href="./Images/Screens/FigmaLogo.png"><img alt="" de="" figma""="" logo="" src="./Images/Screens/FigmaLogo.png"/></a>
<figcaption>"Logo de Figma"</figcaption>
<figcaption>Figure 11 - "Logo de Figma"</figcaption>
</figure>
<p>Figma est l'outil que j'ai utilisé pour créer mon poster et un certain nombre des diagrammes de cette documentation.</p>
<p>J'utilise aussi cet outil dès que je vais faire des maquettes de sites ou d'applications. D'ailleurs les maquettes dans le cahier des charges ont été faites avec.</p>
@@ -2104,9 +2109,9 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
<p>Dans ce projet, différents choix ont été faits pour ce qui est des technologies.</p>
<p>Certaines ont été choisies, car elles étaient les plus simples, les plus pratiques, les plus efficaces ou encore les plus connues et donc ayant le meilleur support. Je vais tenter de résumer ici ces choix, mais je reviendrai sur la plupart d'entre eux plus tard quand j'explique ce que je fais avec.</p>
<h4 id="selenium">Selenium</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-12">
<a class="glightbox" href="./Images/Photos/Selenium_Logo.png"><img alt="" de="" logo="" src="./Images/Photos/Selenium_Logo.png" sélénium""=""/></a>
<figcaption>"Logo de sélénium"</figcaption>
<figcaption>Figure 12 - "Logo de sélénium"</figcaption>
</figure>
<p>Selenium est une librairie à la base Node JS qui permet d'automatiser des actions sur un navigateur internet. Le but premier et je pense son utilisation première et l'automatisation de tests pour des applications WEB. En effet, c'est un super outil pour simuler un user faisant un certain nombre d'actions sans apporter de variabilité, ce qui fait de super test unitaires.</p>
<p>Cependant, je pense que l'autre grande partie des utilisateurs de Selenium l'utilisent pour faire du "Scrapping". Et nous sommes un peu dans cette seconde catégorie. Le "Scrapping" c'est l'acte d'aller récupérer des informations sur des pages web automatiquement pour alimenter sa propre base de données. En effet, si on arrive à passer les protections anti-bot, on peut facilement utiliser Selenium pour scraper tous les sites qui nous passent par la tête.</p>
@@ -2123,9 +2128,9 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
<p>Simple, car je ne voulais pas avoir à passer trop de temps dessus (ça n'a pas bien vieilli lol...). Je voulais que l'on puisse utiliser Firefox parce qu'il n'implémente pas les mêmes sécurités que Chrome pour faire simple. J'avais besoin que la lib puisse contrôler un Firefox HEADLESS comme je ne voulais pas avoir une page web ouverte sur mon ordi quand je commente, car c'est de l'espace utilisé pour rien. J'avais besoin d'un wrapper C# puisque c'est le langage que j'utilise. Pour finir, j'avais besoin d'interagir avec les éléments de la page pour naviguer dessus et d'insérer des cookies pour me connecter sans avoir à passer par le login de la F1TV qui est très bon pour détecter les bots.</p>
<p>Avec un cahier des charges pareil beaucoup de librairies ont été abandonnées. J'ai pu tester pleins de librairies C# qui arrivaient à contrôler un Chrome et même pas mal qui arrivaient à contrôler un Chrome Headless. Mais le choix est très vite restreint quand on veut pouvoir contrôler Chrome OU Firefox.</p>
<p>À la base, mon choix, c'était porté sur Puppeteer Sharp qui est une librairie qui se veut être exactement ce que je veux.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-13">
<a class="glightbox" href="./Images/Photos/Pupetteer_Logo.png"><img alt="" de="" logo="" pupeteer""="" src="./Images/Photos/Pupetteer_Logo.png"/></a>
<figcaption>"Logo de Pupeteer"</figcaption>
<figcaption>Figure 13 - "Logo de Pupeteer"</figcaption>
</figure>
<p>Je voulais utiliser cette librairie, car il y a des plugins qui sont très orientés scrapping, en effet, ils implémentent de nombreuses techniques pour permettre de mieux passer inaperçu par les systèmes de détection de bots.</p>
<p>Sur le papier, c'est la librairie parfaite qui correspond parfaitement au cahier des charges que je m'étais fixé et je pense que si j'utilisais un projet JS, elle le serait. Sauf qu'avec le wrapper C# j'ai eu un certain nombre de problèmes :</p>
@@ -2140,9 +2145,9 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
<p>Pour résumer, j'ai choisi Puppeteer car c'était la seule option viable pour mon besoin.</p>
<p>(Note : Par contre si je trouve la personne chez Mozilla ou puppeteer qui a décidé d'hard coder la résolution maximale du browser Headless que l'on peut override UNIQUEMENT en changeant les variables d'environnement de la machine ET DE NE LE DOCUMENTER QUASI NULLE PART JE JURE QUE CA VA TRÈS MAL SE PASSER)</p>
<h4 id="csharp">CSharp</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-14">
<a class="glightbox" href="./Images/Photos/Csharp_Logo.png"><img alt="" c#""="" logo="" src="./Images/Photos/Csharp_Logo.png"/></a>
<figcaption>"Logo C#"</figcaption>
<figcaption>Figure 14 - "Logo C#"</figcaption>
</figure>
<p>Je pense que c'est le choix le plus simple à expliquer. C# est un langage de programmation orienté objet relativement haut niveau qui a été créé par Microsoft et qui a comme cible le développement d'applications pour Windows. (On peut évidemment trouver des adaptations pour le faire tourner sur Linux, mais ce n'est pas vraiment le but du langage)</p>
<p>En plus d'être un superbe langage de programmation, c'est le langage que l'on apprend au CFPT informatique. C'est donc un langage avec lequel je suis beaucoup plus à l'aise que pour d'autres langages comme le Python ou le JS.</p>
@@ -2151,9 +2156,9 @@ La documentation a été faite dès le début du projet. J'ai mis en place le sq
Mes seuls regrets après coup sont que je trouve les Windows Forms très moches et qu'il est particulièrement difficile de les rendre plus jolies et que les librairies disponibles en C# pour des scénarios très précis ne sont pas au niveau de celles pour JS et pour Python.
Cependant, si j'avais à refaire le projet, je reprendrais C# je pense.</p>
<h4 id="python">Python?</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-15">
<a class="glightbox" href="./Images/Photos/Python_Logo.png"><img alt="" logo="" python""="" src="./Images/Photos/Python_Logo.png"/></a>
<figcaption>"Logo Python"</figcaption>
<figcaption>Figure 15 - "Logo Python"</figcaption>
</figure>
<p>Alors ce choix-là est plus compliqué à comprendre.</p>
<p>Pour tout le projet, j'ai tenté de garder le C# comme langage et de ne pas utiliser autre chose. Cependant, j'ai dû utiliser une seule fois le Python dans un cas très précis.</p>
@@ -2165,9 +2170,9 @@ Cependant, si j'avais à refaire le projet, je reprendrais C# je pense.</p>
<p>Un des avantages du Python est quand même qu'il y a beaucoup plus de gens qui codent dessus, et pour ce genre d'utilisation très spécifique, c'est plutôt pratique.</p>
<p>Le seul problème, c'est que cela oblige l'utilisateur à avoir python installé sur sa machine et que sa version doit être compatible... (les joies de python).</p>
<h4 id="firefox">Firefox</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-16">
<a class="glightbox" href="./Images/Photos/Firefox_logo_dev.png"><img alt="" firefox="" headless""="" logo="" src="./Images/Photos/Firefox_logo_dev.png"/></a>
<figcaption>"Logo Firefox Headless"</figcaption>
<figcaption>Figure 16 - "Logo Firefox Headless"</figcaption>
</figure>
<p>J'en parle déjà plus bas, mais le choix de navigateur est super important.</p>
<p>Déjà tous les navigateurs n'ont pas un mode Headless (sans tête, mieux expliqué dans la rubrique "Simuler un navigateur ?"). Par exemple, même si Edge est maintenant basé sur Chromium, il n'existe pas de moyen de le faire tourner en Headless pour le moment.</p>
@@ -2185,32 +2190,32 @@ Donc, il me fallait un navigateur qui puisse opérer en Headless et qui soit sup
<h4 id="les-briques-principales">Les briques principales</h4>
<p>Voici trois grosses étapes du projet. Pour rappel, ce sont des vulgarisations plutôt larges qui n'ont qu'un seul but, aider à la compréhension de ce qui vient par la suite.</p>
<h5 id="recuperation-dimages">Récupération d'images</h5>
<figure class="figure-image">
<figure class="figure-image" id="figure-17">
<a class="glightbox" href="./Images/Figma/DiagrammeRecupImages.png"><img alt="" de="" des="" diagramme="" images""="" le="" processus="" représentant="" récupération="" simplifié="" src="./Images/Figma/DiagrammeRecupImages.png"/></a>
<figcaption>"Diagramme simplifié représentant le processus de récupération des images"</figcaption>
<figcaption>Figure 17 - "Diagramme simplifié représentant le processus de récupération des images"</figcaption>
</figure>
<p>Pour faire simple, on peut voir qu'il y a deux parties à cette étape. La première en partant du haut représente un script python qui va chercher des informations dans la base de données de Chrome qui est en SQLite. Ces informations dans notre cas sont les cookies de connexion.</p>
<p>Dans la seconde étape, on peut voir que le programme utilise Selenium avec un navigateur Firefox Headless qui va aller communiquer avec la F1TV qui est le site web qui nous intéresse et qu'une des infos que l'on récupère est une image de la page en format PNG que l'on envoie au programme C#.</p>
<p>Ces deux parties sont liées, car pour se connecter à la F1TV Selenium a besoin des cookies de connexion récupérés par le programme Python.</p>
<p>La première partie est un processus qui n'est utilisé qu'une seule fois au démarrage tandis que la récupération d'images et en continu pendant toute la durée de l'utilisation de l'application.</p>
<h5 id="ocr">OCR</h5>
<figure class="figure-image">
<figure class="figure-image" id="figure-18">
<a class="glightbox" href="./Images/Figma/DiagrammeOCR.png"><img alt="" d'ocr""="" diagramme="" le="" processus="" représentant="" simplifié="" src="./Images/Figma/DiagrammeOCR.png"/></a>
<figcaption>"Diagramme simplifié représentant le processus d'OCR"</figcaption>
<figcaption>Figure 18 - "Diagramme simplifié représentant le processus d'OCR"</figcaption>
</figure>
<p>;</p>
<p>On peut voir dans ce diagramme simplifié qu'avec l'aide de ce que contient le fichier "Config.JSON" on découpe l'image que l'on a récupéré au préalable en petits morceaux qui contiennent des informations. Ensuite, on prend cette image et on lui applique un filtre pour retirer le flou, la couleur, etc. Puis en utilisant de l'OCR (Optical Character Recognition) on en récupère les informations sous forme de texte et on le renvoie dans le programme C#</p>
<p>Dans cette partie explicative générale, on ne reviendra pas sur la création de ce fichier config. Pour plus d'infos à son sujet, voir la rubrique (OCR/Fonctionnement général)</p>
<h5 id="traitement-et-affichage">Traitement et affichage</h5>
<figure class="figure-image">
<figure class="figure-image" id="figure-19">
<a class="glightbox" href="./Images/Figma/DiagrammeTraitement.png"><img alt="" d'affichage""="" de="" diagramme="" et="" le="" processus="" représentant="" simplifié="" src="./Images/Figma/DiagrammeTraitement.png" traitement=""/></a>
<figcaption>"Diagramme simplifié représentant le processus de traitement et d'affichage"</figcaption>
<figcaption>Figure 19 - "Diagramme simplifié représentant le processus de traitement et d'affichage"</figcaption>
</figure>
<p>On peut voir dans ce dernier mini diagramme simplifié qu'on prend les données que l'on récupérait de l'étape précédente qui ne sont pas forcément toutes cohérentes et qu'on les traite pour leur redonner du sens avant de les stocker dans une base de données SQLITE. Ensuite cette même base de donnée fournis les infos nécessaires pour des affichages (Ces affichages sont directement récupérés depuis le projet en cours de fonctionnement).</p>
<h4 id="resume-du-fonctionnement-general">Résumé du fonctionnement général</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-20">
<a class="glightbox" href="./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png"><img alt="" diagramme="" du="" global="" le="" processus="" projet""="" représentant="" simplifié="" src="./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png"/></a>
<figcaption>"Diagramme simplifié représentant le processus global du projet"</figcaption>
<figcaption>Figure 20 - "Diagramme simplifié représentant le processus global du projet"</figcaption>
</figure>
<p>Ce dernier diagramme est un schéma fait pour représenter de la manière la plus simple possible toutes les briques du projet et comment elles s'imbriquent ensemble.
La représentation est un peu différente des trois autres diagrammes, car le but ici est surtout de montrer le chemin que fait la donnée à travers les couches.</p>
@@ -2228,22 +2233,22 @@ La représentation est un peu différente des trois autres diagrammes, car le bu
<p>Voici la première grande étape du projet.</p>
<p>Pour rappel, Amazon héberge directement le site de la F1TV et possède les droits sur les données de la F1. C'est sous le nom de AWS (le service d'hébergement d'Amazon) que la firme apparait en tant que sponsor.</p>
<p>On peut voir ce nom apparaître assez souvent quand on regarde un Grand Prix, car comme ils ont la mainmise sur les données, ils peuvent insérer des bandeaux d'informations sur le flux public sur ce qu'il se passe, voir même faire des prédictions (Bien qu'un peu bancales)</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-21">
<a class="glightbox" href="./Images/Screens/AWSExample1.jpg"><img alt="" aws="" en="" exemple="" gp""="" insertion="" src="./Images/Screens/AWSExample1.jpg"/></a>
<figcaption>"Exemple insertion AWS en GP"</figcaption>
<figcaption>Figure 21 - "Exemple insertion AWS en GP"</figcaption>
</figure>
<p>Ce service s'appelle F1 Insights (Oui, c'est un meilleur nom de projet que F1 Compagnon, mais bon) et c'est, je pense, la raison pour laquelle on ne voit aucune API publique qui permette de correctement se renseigner en données en direct pendant un Grand Prix. Ils ont dû dégotter un juteux contrat pour s'occuper de toute l'infrastructure digitale de la F1 (du moins publique) en échange d'une exclusivité totale sur certaines choses comme les Data.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-22">
<a class="glightbox" href="./Images/Screens/AWSExample2.jpg"><img alt="" d'aws""="" data="" exemple="" src="./Images/Screens/AWSExample2.jpg"/></a>
<figcaption>"Exemple data d'AWS"</figcaption>
<figcaption>Figure 22 - "Exemple data d'AWS"</figcaption>
</figure>
<p>Évidemment, je ne fais que conjecturer et ce que j'ai dit n'est pas à prendre au pied de la lettre, mais c'est une explication possible, je pense, de pourquoi il est si difficile de trouver des données sur la F1 facilement en temps réel.</p>
<p>Il existe bien quelques API un peu bancales publiques, mais le problème, c'est qu'elles ne sont vraiment pas suffisantes et je ne peux pas leur faire confiance quand je commente. Ce qu'il m'aurait fallu, c'est une API publique et officielle qui me permette d'être sûr que les données sont les bonnes et qu'elles arrivent le plus vite possible.</p>
<p>On pourrait croire que c'est impossible, car cela n'existe pas comme je l'ai dit MAIS ! Ce n'est pas complètement vrai. En effet, depuis que je possède un abonnement à la F1TV, il existe une source d'informations très précieuse qui m'aide énormément dans mon quotidien de commentateur de Formule 1. La "DATA CHANNEL".</p>
<p>La Data Channel est une page de la F1TV qui permet, pour chaque Grand Prix, de visualiser, sous la forme d'un flux vidéo, différentes informations capitales sur la course.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-23">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" channel""="" data="" de="" exemple="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Exemple de Data Channel"</figcaption>
<figcaption>Figure 23 - "Exemple de Data Channel"</figcaption>
</figure>
<p>Le problème, c'est que comme je viens de le dire, ces données ne sont pas accessibles comme un tableau HTML ou un flux RSS ou un tableau JSON. C'est un flux vidéo.
Il faut savoir qu'entretenir une diffusion de flux vidéo en 1080P pendant deux heures accessible par des milliers d'abonnés est EXTRÊMENT cher, surtout quand on le compare à simplement afficher les données dans un tableau. Ce qui veut dire que ce choix est délibéré et a un sens au niveau économique.
@@ -2271,14 +2276,14 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent ju
<p>J'ai donc décidé de m'occuper de la seconde option : Simuler un navigateur.</p>
<p>Cette option, bien que complexe et difficile à implémenter, propose une solution à tous les problèmes et permet une récupération quasi sans compromis.</p>
<h4 id="simuler-un-navigateur">Simuler un navigateur ?</h4>
<figure class="figure-image">
<figure class="figure-image" id="figure-24">
<a class="glightbox" href="./Images/Screens/headless-firefox.jpg"><img (sans="" alt="" headless="" navigateur="" src="./Images/Screens/headless-firefox.jpg" tête)""=""/></a>
<figcaption>"Navigateur Headless (sans tête)"</figcaption>
<figcaption>Figure 24 - "Navigateur Headless (sans tête)"</figcaption>
</figure>
<p>Simuler un navigateur internet n'est pas forcément très difficile. Chromium par exemple offre une panoplie d'outils natifs et énormément de librairies existent permettant de facilement et en quelques lignes simuler un Google Chrome et le contrôler sans afficher son UI (Interface Utilisateur).</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-25">
<a class="glightbox" href="./Images/Screens/ChromiumLogo.png"><img alt="" chromium="" logo""="" src="./Images/Screens/ChromiumLogo.png"/></a>
<figcaption>"Chromium logo"</figcaption>
<figcaption>Figure 25 - "Chromium logo"</figcaption>
</figure>
<p>Cependant, La F1TV n'utilise pas simplement un player HTML5 basique. Elle utilise un service de streaming Bit Movin qui permet de fournir un stream de bonne qualité et surtout qui implémente les DRM (Digital Right Management).</p>
<p>Cela veut dire que quand on ouvre un flux de la F1TV sur chrome et que l'on essaie de prendre une capture d'écran, le player se met en noir et ne permet pas de voir quoi que ce soit (Certaines versions de Chrome le permettent pendant quelques semaines avant de bloquer à nouveau). Ce qui dans notre cas est un immense problème. Mais Firefox ne nous bloque pas de cette façon et il est donc assez facile de passer outre.</p>
@@ -2286,9 +2291,9 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent ju
<p>Dans Chrome, le player par défaut utilise une technologie appelée "PCP" ou "Protected Content Playback" qui leur permet de bloquer au moins une partie des techniques de récupération du flux vidéo et audio.</p>
<p>Cependant, Firefox de pas sa nature Open Source utilise "Open H264" pour lire ces mêmes flux soumis à des DRM et Open H264 n'implémente pas les mêmes restrictions.</p>
<p>Sauf que Firefox n'est pas aussi facilement émulé que chrome et cela réduit notre choix de librairies à ... Une seule… Qui est Selenium. (Il existe aussi Pupetteer C# mais j'ai rencontré énormément de soucis avec cette dernière dès que je voulais lancer une vidéo)</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-26">
<a class="glightbox" href="./Images/Screens/FirefoxLogo.png"><img alt="" dev="" firefox="" logo""="" src="./Images/Screens/FirefoxLogo.png"/></a>
<figcaption>"Firefox dev logo"</figcaption>
<figcaption>Figure 26 - "Firefox dev logo"</figcaption>
</figure>
<p>Mais même si la documentation est plutôt maigre parfois, c'est une bonne librairie qui permet de très bien contrôler une instance de chrome ou de Firefox.</p>
<h4 id="controler-le-navigateur">Contrôler le navigateur</h4>
@@ -2478,18 +2483,18 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent ju
<p>Il y a donc une liste de pilotes dans laquelle on peut ajouter ou supprimer des noms de pilotes. L'idéal serait de mettre tous les pilotes de réserve, comme ça si un pilote est malade sur une course, on n'a pas besoin de venir changer la liste.</p>
<h5 id="zone-principale">Zone principale</h5>
<p>Pour la zone principale, c'est entièrement manuel, on attend de l'utilisateur deux points x, y sur l'image pour ensuite avoir une idée d'où est censé se trouver la zone.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-27">
<a class="glightbox" href="./Images/Screens/MainZoneExample.png"><img alt="" de="" exemple="" principale""="" src="./Images/Screens/MainZoneExample.png" zone=""/></a>
<figcaption>"Exemple de zone principale"</figcaption>
<figcaption>Figure 27 - "Exemple de zone principale"</figcaption>
</figure>
<h5 id="zones-pilotes">Zones pilotes</h5>
<p>C'est là que ça devient intéressant. L'utilisateur n'a pas besoin de faire quoi que ce soit pour que le programme sache où sont les zones des pilotes.</p>
<p>J'aurais pu le faire manuellement en faisant choisir à l'utilisateur de donner deux points qui correspondent à la première zone et extrapoler pour en avoir 20. Sauf que si l'utilisateur n'est pas précis au pixel près (et même comme ça parfois) le vingtième pilote se retrouve avec une zone complètement désaxée.</p>
<p>Là, le programme va "simplement" effectuer une reconnaissance de texte sur toute l'image. Les résultats ne nous intéressent pas vraiment, tout ce que l'on veut, c'est la position des textes.</p>
<p>Avec les positions, il est facile de déterminer où sont toutes les zones de pilotes et donc sans que l'utilisateur ait à toucher quoi que ce soit, dès qu'il a donné les infos pour la zone principale, les zones de pilotes sont déterminées.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-28">
<a class="glightbox" href="./Images/Screens/DriverZoneExample.png"><img alt="" exemple="" pilote""="" src="./Images/Screens/DriverZoneExample.png" zone=""/></a>
<figcaption>"Exemple zone pilote"</figcaption>
<figcaption>Figure 28 - "Exemple zone pilote"</figcaption>
</figure>
<p>Voici un exemple du code utilisé pour trouver ou dessiner des zones de pilotes :</p>
<div class="language-Csharp highlight"><pre><span></span><code><span id="__span-5-1"><a href="#__codelineno-5-1" id="__codelineno-5-1" name="__codelineno-5-1"></a><span class="k">public</span><span class="w"> </span><span class="k">void</span><span class="w"> </span><span class="nf">AutoCalibrate</span><span class="p">()</span><span class="w"></span>
@@ -2558,17 +2563,17 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent ju
<h5 id="windows-pilotes">Windows pilotes</h5>
<p>C'est ici que c'est le plus pénible pour l'utilisateur, il doit sélectionner manuellement les positions des fenêtres de données. Ensuite, dès que l'utilisateur a donné une position pour chaque window, on applique les positions pour chaque zone de pilote.</p>
<p>Il y a plusieurs types de windows et selon le type le traitement est différent comme je l'ai dit plus tôt. Voici des exemples concrets :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-29">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple1.png"><img alt="" de="" exemple="" pneus""="" src="./Images/Screens/TyreZoneExemple1.png" window=""/></a>
<figcaption>"Exemple Window de pneus"</figcaption>
<figcaption>Figure 29 - "Exemple Window de pneus"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-30">
<a class="glightbox" href="./Images/Screens/DriverLapTimeExample.png"><img alt="" au="" exemple="" src="./Images/Screens/DriverLapTimeExample.png" temps="" tour""="" window=""/></a>
<figcaption>"Exemple Window temps au tour"</figcaption>
<figcaption>Figure 30 - "Exemple Window temps au tour"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-31">
<a class="glightbox" href="./Images/Screens/DRSFalse.png"><img alt="" drs""="" exemple="" src="./Images/Screens/DRSFalse.png" window=""/></a>
<figcaption>"Exemple window Drs"</figcaption>
<figcaption>Figure 31 - "Exemple window Drs"</figcaption>
</figure>
<p>Il est important que toutes ces zones soient transmises avec le plus de précision possible pour que l'OCR puisse bien faire son boulot.</p>
<h5 id="stockage">Stockage</h5>
@@ -2749,15 +2754,15 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent ju
<p>Mais avant ça, je dois expliquer certains concepts qui seront importants.</p>
<h4 id="fonctionnement-general_1">Fonctionnement général</h4>
<p>Voici un screenshot de la page DATA de la F1TV que le programme va recevoir :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-32">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" f1tv""="" screen="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Screen F1TV"</figcaption>
<figcaption>Figure 32 - "Screen F1TV"</figcaption>
</figure>
<p>Si on regarde de loin, on peut se dire que la structure est plutôt simple, mais c'est loin d'être le cas.
On peut y voir au moins quatre zones contenant de l'information dans un format différent.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-33">
<a class="glightbox" href="./Images/Figma/WindowZoneExplanation1.png"><img alt="" principales""="" src="./Images/Figma/WindowZoneExplanation1.png" zones=""/></a>
<figcaption>"Zones principales"</figcaption>
<figcaption>Figure 33 - "Zones principales"</figcaption>
</figure>
<p>Dans l'exemple ci-dessus, on peut voir trois zones, mais on aurait également pu comprendre la zone de position des pilotes autour du circuit pour faire 4.</p>
<p>Ces quatre zones sont très différentes et contiennent d'autres informations. Pour ce travail de diplôme, je ne m'occupe que de la zone principale. Mais je pense que le titre et les infos de circuit ne prendrait pas tant de temps que ça à implémenter.</p>
@@ -2784,40 +2789,40 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<li>L'objet Window n'est quasi jamais utilisé, c'est presque tout le temps des enfants de Window plus spécifiques qui sont utilisés, le but est que chaque type d'information sur l'image aie son type de window.</li>
</ul>
<p>Voilà donc un petit diagramme qui montre le découpage du programme :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-34">
<a class="glightbox" href="./Images/Figma/WindowZoneExplanationDiagram.png"><img alt="" de="" des="" diagramme="" explicatif="" l'architecture="" src="./Images/Figma/WindowZoneExplanationDiagram.png" zones""=""/></a>
<figcaption>"Diagramme explicatif de l'architecture des zones"</figcaption>
<figcaption>Figure 34 - "Diagramme explicatif de l'architecture des zones"</figcaption>
</figure>
<p>Pour visualiser encore un peu mieux comment ce découpage prend forme, voici ce que chaque zone et Window contient.</p>
<p>Main Zone :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-35">
<a class="glightbox" href="./Images/Screens/MainZoneExample.png"><img alt="" exemple="" principale""="" src="./Images/Screens/MainZoneExample.png" zone=""/></a>
<figcaption>"Exemple zone principale"</figcaption>
<figcaption>Figure 35 - "Exemple zone principale"</figcaption>
</figure>
<p>Driver Zone :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-36">
<a class="glightbox" href="./Images/Screens/DriverZoneExample.png"><img alt="" de="" exemple="" pilote""="" src="./Images/Screens/DriverZoneExample.png" zone=""/></a>
<figcaption>"Exemple zone de pilote"</figcaption>
<figcaption>Figure 36 - "Exemple zone de pilote"</figcaption>
</figure>
<p>Driver Position Window :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-37">
<a class="glightbox" href="./Images/Screens/DriverPositionExample.png"><img alt="" de="" exemple="" fenêtre="" position""="" src="./Images/Screens/DriverPositionExample.png"/></a>
<figcaption>"Exemple de fenêtre de position"</figcaption>
<figcaption>Figure 37 - "Exemple de fenêtre de position"</figcaption>
</figure>
<p>Driver name Window :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-38">
<a class="glightbox" href="./Images/Screens/DriverNameExample.png"><img alt="" de="" exemple="" fenêtre="" nom""="" src="./Images/Screens/DriverNameExample.png"/></a>
<figcaption>"Exemple de fenêtre de nom"</figcaption>
<figcaption>Figure 38 - "Exemple de fenêtre de nom"</figcaption>
</figure>
<p>Driver LapTime Window :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-39">
<a class="glightbox" href="./Images/Screens/DriverLapTimeExample.png"><img alt="" au="" de="" exemple="" fenêtre="" src="./Images/Screens/DriverLapTimeExample.png" temps="" tour""=""/></a>
<figcaption>"Exemple de fenêtre de temps au tour"</figcaption>
<figcaption>Figure 39 - "Exemple de fenêtre de temps au tour"</figcaption>
</figure>
<p>Driver Tyre Window :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-40">
<a class="glightbox" href="./Images/Screens/DriverTyreWindowExample.png"><img alt="" de="" exemple="" fenêtre="" pneus""="" src="./Images/Screens/DriverTyreWindowExample.png"/></a>
<figcaption>"Exemple de fenêtre pneus"</figcaption>
<figcaption>Figure 40 - "Exemple de fenêtre pneus"</figcaption>
</figure>
<p>Il existe d'autres types de Window mais ce sont les principaux.</p>
<p>On se rend assez facilement compte que chacunes de ces Windows va avoir besoin d'un traitement spécifique, car la manière de reconnaitre le pneu utilisé et le temps au tour ne peut pas être la même.</p>
@@ -2833,30 +2838,30 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>Dans notre cas, le souci est que les chiffres et lettres sont beaucoup trop petits. Ils ne font parfois que 10 pixels de haut et cela fait qu'il n'est pas forcément aisé de toujours les différencier. De plus, comme ils sont petits, les artéfacts d'aliasing sont assez violents et peuvent grandement déformer une lettre ou un chiffre.</p>
<p>Exemple :</p>
<p>Prenons le chiffre 9. Dans l'image, il peut être représenté de cette manière :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-41">
<a class="glightbox" href="./Images/Figma/Bad9Example.png"><img alt="" avant="" chiffre="" de="" exemple="" post="" src="./Images/Figma/Bad9Example.png" traitement""=""/></a>
<figcaption>"Exemple de chiffre avant post traitement"</figcaption>
<figcaption>Figure 41 - "Exemple de chiffre avant post traitement"</figcaption>
</figure>
<p>On peut voir qu'il est flou, pour nous cela ne pose pas de problème et je pense qu'à peu près n'importe qui peut dire que c'est un 9.</p>
<p>Cependant, comme les contours sont flous et même si on essaie de retirer le background :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-42">
<a class="glightbox" href="./Images/Figma/Aliased9.png"><img 9="" alt="" antialiasing""="" avec="" src="./Images/Figma/Aliased9.png"/></a>
<figcaption>"9 avec antialiasing"</figcaption>
<figcaption>Figure 42 - "9 avec antialiasing"</figcaption>
</figure>
<p>On voit que le 9 n'est pas clairement défini. En effet, on pourrait le comprendre comme :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-43">
<a class="glightbox" href="./Images/Figma/Horrible9.png"><img alt="" contours""="" de="" exemple="" premier="" src="./Images/Figma/Horrible9.png"/></a>
<figcaption>"Premier exemple de contours"</figcaption>
<figcaption>Figure 43 - "Premier exemple de contours"</figcaption>
</figure>
<p>Ou comme :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-44">
<a class="glightbox" href="./Images/Figma/Clean9Example.png"><img alt="" contours""="" de="" exemple="" second="" src="./Images/Figma/Clean9Example.png"/></a>
<figcaption>"Second exemple de contours"</figcaption>
<figcaption>Figure 44 - "Second exemple de contours"</figcaption>
</figure>
<p>Voire simplement comme :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-45">
<a class="glightbox" href="./Images/Figma/Filled9.png"><img alt="" contour="" de="" exemple="" généreux""="" src="./Images/Figma/Filled9.png"/></a>
<figcaption>"Exemple de contour généreux"</figcaption>
<figcaption>Figure 45 - "Exemple de contour généreux"</figcaption>
</figure>
<p>Et on se rend bien compte que les performances de détection ne sont pas les mêmes dans ces trois cas.</p>
<p>Il faut donc faire un certain post traitement des images pour supprimer les éléments parasites, les couleurs, et augmenter la visibilité des contours importants.</p>
@@ -2867,31 +2872,31 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>C'est je pense la plus simple de toutes car Tesseract est particulièrement bien entrainé pour.</p>
<p>Cette reconnaissance concerne donc des lettres qui font des mots ou des noms.</p>
<p>Voici un exemple de la WINDOW nom de pilote en entrée :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-46">
<a class="glightbox" href="./Images/Screens/ExempleTextRaw.png"><img alt="" cru""="" exemple="" src="./Images/Screens/ExempleTextRaw.png" texte=""/></a>
<figcaption>"Exemple texte cru"</figcaption>
<figcaption>Figure 46 - "Exemple texte cru"</figcaption>
</figure>
<p>Ce texte peut paraitre bon, cependant quand on le lance dans Tesseract, il ne va pas toujours donner un résultat parfait. Il faut aussi savoir qu'il y a des noms pas mal plus pénibles que Tesseract à plus de mal à reconnaître, soit à cause des lettres utilisées, soit, car le nom est un nom d'une autre région et qui ne veut rien dire en anglais, ce qui empêche l'utilisation de dictionnaire (Ex : Tsunoda est un nom japonais et parfois, il est difficile pour Tesseract de le reconnaitre puisque si une lettre pose un problème, il ne peut pas trouver de contexte qui puisse l'aider).</p>
<p>Donc pour le rendre plus facilement lisible et augmenter les chances que toutes les lettres soient découvertes, voici les étapes que j'ai mis en place.</p>
<p>1 : J'inverse les couleurs. Je me suis rendu compte qu'il était souvent plus facile de trouver un noir sur blanc que blanc sur noir. Je ne suis pas sûr que cette étape soit capitale cependant</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-47">
<a class="glightbox" href="./Images/Screens/ExempleTextINvertColor.png"><img alt="" inversé""="" src="./Images/Screens/ExempleTextINvertColor.png" texte=""/></a>
<figcaption>"Texte inversé"</figcaption>
<figcaption>Figure 47 - "Texte inversé"</figcaption>
</figure>
<p>2 : Je fais un <em>Treshhold</em> de 165, car avec moins le texte occasionnellement prend trop du background et avec plus les lettres sont trop fines.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-48">
<a class="glightbox" href="./Images/Screens/ExempleTextTresholding.png"><img alt="" après="" src="./Images/Screens/ExempleTextTresholding.png" texte="" treshold""=""/></a>
<figcaption>"Texte après Treshold"</figcaption>
<figcaption>Figure 48 - "Texte après Treshold"</figcaption>
</figure>
<p>3 : Je fais un <em>Resize</em> de l'image pour avoir une meilleure résolution et permettre une meilleure détection. J'augmente la hauteur et la largeur par un facteur 2. J'ai trouvé cette valeur suffisante et aller plus haut consomme beaucoup de ressources.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-49">
<a class="glightbox" href="./Images/Screens/ExempleTextResize.png"><img alt="" après="" resize""="" src="./Images/Screens/ExempleTextResize.png" texte=""/></a>
<figcaption>"Texte après Resize"</figcaption>
<figcaption>Figure 49 - "Texte après Resize"</figcaption>
</figure>
<p>4 : Je fais une très rapide <em>Dilatation</em> du texte pour retirer le flou amené par la méthode de Resize. Je n'utilise qu'une valeur de 1, car je ne veux pas trop changer comment le texte est modelé, je veux juste retirer le flou.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-50">
<a class="glightbox" href="./Images/Screens/ExempleTextDilatation.png"><img alt="" après="" dilatation""="" src="./Images/Screens/ExempleTextDilatation.png" texte=""/></a>
<figcaption>"Texte après Dilatation"</figcaption>
<figcaption>Figure 50 - "Texte après Dilatation"</figcaption>
</figure>
<p><em>Explication des méthodes précises plus bas</em></p>
<p>Voilà pour ce qui est du post processing. Je ne dis pas que ce sont les meilleurs paramètres possibles, mais dans mes tests ce sont ceux qui ont le mieux marchés.</p>
@@ -2919,37 +2924,37 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>La grande différence ce sont les ordres de grandeur. Les temps au tour sont en général entre 50 secondes et deux minutes. Tandis que les secteurs sont entre 20 et 30 secondes alors que le retard sur le leader peut être de plusieurs minutes.</p>
<p>Cependant, tous ces temps possèdent le même type de post-traitement avant d'être envoyés à Tesseract.</p>
<p>Voici un exemple de temps au tour avant toute transformation :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-51">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeBefore.png"><img alt="" au="" avant="" src="./Images/Screens/ExempleLapTimeBefore.png" temps="" tour="" traitement""=""/></a>
<figcaption>"Temps au tour avant traitement"</figcaption>
<figcaption>Figure 51 - "Temps au tour avant traitement"</figcaption>
</figure>
<p>On peut avoir l'impression que ce texte est tout à fait lisible et facile à décoder, surtout quand on le voit de loin comme ça. Cependant, il faut imaginer que ces chiffres font 13 pixels de haut en comptant le flou et comme expliqué plus haut, ce flou dans ces échelles est terrible.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-52">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeBeforeUpscaled.png"><img alt="" au="" src="./Images/Screens/ExempleLapTimeBeforeUpscaled.png" temps="" tour="" zoomé""=""/></a>
<figcaption>"Temps au tour zoomé"</figcaption>
<figcaption>Figure 52 - "Temps au tour zoomé"</figcaption>
</figure>
<p>Si on donne cette image à Tesseract, les '3' deviennent des '9', des '9' deviennent des '8', des '2' deviennent, eux aussi, des '9', le tout parfois inversement et de manière complètement imprévisible. Ça n'est simplement pas utilisable.</p>
<p>Cette partie est un peu plus complexe, car si la détection n'est pas fiable, les chiffres sont juste inutilisables. Si à tout moment un temps au tour de 1:39.106 devient 1:32.108 c'est juste pas possible.</p>
<p>Voici donc les étapes de post-traitement que j'ai mis en place pour leur détection :</p>
<p>1 : J'applique un <em>Treshold</em> de 185 pour enlever les ambiguïtés d'alisaising et avoir une image en noir et blanc claire. La valeur de 185 est assez élevée, car le but est de vraiment garder uniquement les contours. Comme les chiffres se ressemblent beaucoup plus que les lettres, il faut tenter le plus possible de conserver leurs formes spécifiques. Je me suis rendu compte que cette valeur était une de celles qui marchent le mieux.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-53">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeTreshold.png"><img alt="" après="" au="" src="./Images/Screens/ExempleLapTimeTreshold.png" temps="" tour="" treshold""=""/></a>
<figcaption>"Temps au tour après Treshold"</figcaption>
<figcaption>Figure 53 - "Temps au tour après Treshold"</figcaption>
</figure>
<p>2 : J'applique un <em>Resize</em> de 2 pour augmenter la résolution des chiffres et permettre une meilleure détection. Le but est d'avoir plus de pixels et donc de permettre à Tesseract de mieux utiliser ses matrices de convolution.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-54">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeResize.png"><img alt="" après="" au="" resize""="" src="./Images/Screens/ExempleLapTimeResize.png" temps="" tour=""/></a>
<figcaption>"Temps au tour après Resize"</figcaption>
<figcaption>Figure 54 - "Temps au tour après Resize"</figcaption>
</figure>
<p>3 : Comme le <em>Resize</em> amène du flou, j'utilise une méthode de <em>Dilatation</em> qui me permet de retirer ce flou et de remplir un peu plus certaines parties qui ont été un peu laissée par le <em>Resize</em>;</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-55">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeDilatation.png"><img alt="" après="" au="" dilatation""="" src="./Images/Screens/ExempleLapTimeDilatation.png" temps="" tour=""/></a>
<figcaption>"Temps au tour après Dilatation"</figcaption>
<figcaption>Figure 55 - "Temps au tour après Dilatation"</figcaption>
</figure>
<p>4 : Contrairement aux mots plus haut, la rondeur ajoutée par la dilatation n'est pas vraiment désirée. En effet, elle peut rendre confuse certains chiffres et empêcher Tesseract de bien trouver le chiffre. Alors, j'applique une <em>Érosion</em> qui me permet de contrecarrer en partie les rondeurs ajoutées par la dilatation et retrouver des chiffres bien formés. Pour l'<em>Érosion</em> et la <em>Dilatation</em>, j'ai utilisé une valeur de 1, car je ne voulais pas trop changer les chiffres.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-56">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeErode.png"><img alt="" après="" au="" src="./Images/Screens/ExempleLapTimeErode.png" temps="" tour="" érosion""=""/></a>
<figcaption>"Temps au tour après Érosion"</figcaption>
<figcaption>Figure 56 - "Temps au tour après Érosion"</figcaption>
</figure>
<p><em>Explication des méthodes précises plus bas</em></p>
<p>Et avec ce post processing, on retrouve de plutôt bons résultats qui demandent peu de traitement.</p>
@@ -2982,32 +2987,32 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<li>Les pneus intermédiaires</li>
<li>Les pneus pluie</li>
</ul>
<figure class="figure-image">
<figure class="figure-image" id="figure-57">
<a class="glightbox" href="./Images/Photos/Tyres.png"><img alt="" de="" gamme="" pirelli""="" pneus="" src="./Images/Photos/Tyres.png"/></a>
<figcaption>"Gamme de pneus Pirelli"</figcaption>
<figcaption>Figure 57 - "Gamme de pneus Pirelli"</figcaption>
</figure>
<p>Les trois premiers pneus sont des pneus faits pour piste sèche, le pneu intermédiaire pour piste humide et le pneu pluie pour la pluie.</p>
<p>Chaque pneu a sa durée de vie et son niveau de performance propre, mais je ne vais pas rentrer dans le détail ici. Tout ce qu'il faut savoir, ce que savoir sur quel pneu chaque pilote est et depuis combien de temps, il les chausse est une information très importante.</p>
<p>Chaque pneu a une couleur donnée qui permet de les différencier.</p>
<p>Voici un exemple de ce à quoi une WINDOW de pneus peut ressembler :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-58">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple3.png"><img 1""="" alt="" exemple="" pneus="" src="./Images/Screens/TyreZoneExemple3.png" zone=""/></a>
<figcaption>"Exemple zone pneus 1"</figcaption>
<figcaption>Figure 58 - "Exemple zone pneus 1"</figcaption>
</figure>
<p>Mais cette zone peut aussi ressembler à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-59">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple2.png"><img 2""="" alt="" exemple="" pneus="" src="./Images/Screens/TyreZoneExemple2.png" zone=""/></a>
<figcaption>"Exemple zone pneus 2"</figcaption>
<figcaption>Figure 59 - "Exemple zone pneus 2"</figcaption>
</figure>
<p>Mais aussi à ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-60">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple1.png"><img 3""="" alt="" exemple="" pneus="" src="./Images/Screens/TyreZoneExemple1.png" zone=""/></a>
<figcaption>"Exemple zone pneus 3"</figcaption>
<figcaption>Figure 60 - "Exemple zone pneus 3"</figcaption>
</figure>
<p>Voire même ça :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-61">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple4.png"><img 4""="" alt="" exemple="" pneus="" src="./Images/Screens/TyreZoneExemple4.png" zone=""/></a>
<figcaption>"Exemple zone pneus 4"</figcaption>
<figcaption>Figure 61 - "Exemple zone pneus 4"</figcaption>
</figure>
<p>Je pense que vous pouvez tout de suite comprendre la difficulté que représente la tâche de récupération de données à partir de cette image.</p>
<p>En gros, le fonctionnement de cette zone d'information est assez simple.</p>
@@ -3023,14 +3028,14 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>Le programme va tirer un trait depuis le bord droit de la zone, et il va avancer vers la gauche jusqu'à trouver un obstacle. Je détecte un obstacle si le pixel sur lequel est mon trait possède une valeur de plus de 0x50 dans le channel R, G ou B. J'ai trouvé en faisant des tests que les couleurs de background de la F1TV ne dépassaient jamais ces valeurs.</p>
<p>Ensuite, après avoir trouvé le premier obstacle, je récupère une zone qui doit englober le cercle.</p>
<p>Voici un exemple avec cette image en entrée :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-62">
<a class="glightbox" href="./Images/Screens/TyreZoneFull.png"><img alt="" complète""="" src="./Images/Screens/TyreZoneFull.png" zone=""/></a>
<figcaption>"Zone complète"</figcaption>
<figcaption>Figure 62 - "Zone complète"</figcaption>
</figure>
<p>Elle est automatiquement coupée de cette façon :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-63">
<a class="glightbox" href="./Images/Screens/TyreZoneCropped.png"><img alt="" automatiquement""="" coupée="" src="./Images/Screens/TyreZoneCropped.png" zone=""/></a>
<figcaption>"Zone coupée automatiquement"</figcaption>
<figcaption>Figure 63 - "Zone coupée automatiquement"</figcaption>
</figure>
<p>Cela me permet d'isoler uniquement ce qui m'intéresse, ce qui est très pratique pour Tesseract et pour la détection de couleur.</p>
<p>Ensuite, avec cette image, je peux commencer le processus de reconnaissance.</p>
@@ -3038,39 +3043,39 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>Ensuite, j'utilise une méthode qui calcule la différence entre la couleur obtenue et la liste de couleurs possible.</p>
<p>Il y a cinq couleurs des pneus possibles :</p>
<p>"#ff0000" pneu tendre/soft</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-64">
<a class="glightbox" href="./Images/Photos/SoftTyreColor.png"><img alt="" couleur="" d'un="" pneu="" src="./Images/Photos/SoftTyreColor.png" tendre""=""/></a>
<figcaption>"Couleur d'un pneu tendre"</figcaption>
<figcaption>Figure 64 - "Couleur d'un pneu tendre"</figcaption>
</figure>
<p>"#f5bf00" pneu medium</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-65">
<a class="glightbox" href="./Images/Photos/MediumTyreColor.png"><img alt="" couleur="" d'un="" medium""="" pneu="" src="./Images/Photos/MediumTyreColor.png"/></a>
<figcaption>"Couleur d'un pneu medium"</figcaption>
<figcaption>Figure 65 - "Couleur d'un pneu medium"</figcaption>
</figure>
<p>"#a4a5a8" pneu dur/hard</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-66">
<a class="glightbox" href="./Images/Photos/HardTyreColor.png"><img alt="" couleur="" d'un="" dur""="" pneu="" src="./Images/Photos/HardTyreColor.png"/></a>
<figcaption>"Couleur d'un pneu dur"</figcaption>
<figcaption>Figure 66 - "Couleur d'un pneu dur"</figcaption>
</figure>
<p>"#00a42e" pneu inter</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-67">
<a class="glightbox" href="./Images/Photos/IntermediateTyreColor.png"><img alt="" couleur="" d'un="" intermédiaire""="" pneu="" src="./Images/Photos/IntermediateTyreColor.png"/></a>
<figcaption>"Couleur d'un pneu intermédiaire"</figcaption>
<figcaption>Figure 67 - "Couleur d'un pneu intermédiaire"</figcaption>
</figure>
<p>"#2760a6" pneu pluie/wet</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-68">
<a class="glightbox" href="./Images/Photos/WetTyreColor.png"><img alt="" couleur="" d'un="" pluie""="" pneu="" src="./Images/Photos/WetTyreColor.png"/></a>
<figcaption>"Couleur d'un pneu pluie"</figcaption>
<figcaption>Figure 68 - "Couleur d'un pneu pluie"</figcaption>
</figure>
<p>Ce qui est pratique, c'est que même dans les cas où il n'y a pas beaucoup de couleur comme celui-là :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-69">
<a class="glightbox" href="./Images/Screens/TyreZoneHard.png"><img 0="" alt="" avec="" dur="" pneu="" src="./Images/Screens/TyreZoneHard.png" tours""=""/></a>
<figcaption>"Pneu dur avec 0 tours"</figcaption>
<figcaption>Figure 69 - "Pneu dur avec 0 tours"</figcaption>
</figure>
<p>On arrive à une couleur moyenne de :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-70">
<a class="glightbox" href="./Images/Screens/TyreZoneHardAVG.png"><img alt="" après="" background""="" ci-dessus="" couleur="" de="" du="" l'image="" moyenne="" soustraction="" src="./Images/Screens/TyreZoneHardAVG.png"/></a>
<figcaption>"Couleur moyenne de l'image ci-dessus après soustraction du background"</figcaption>
<figcaption>Figure 70 - "Couleur moyenne de l'image ci-dessus après soustraction du background"</figcaption>
</figure>
<p>Et il est donc assez facile de déterminer le type de pneu en question.</p>
<p>Attention, les résultats peuvent être très vite dérangés par la couleur du pneu précédent si le découpage de la fenêtre n'a pas été assez précis.</p>
@@ -3079,26 +3084,26 @@ On peut y voir au moins quatre zones contenant de l'information dans un format d
<p>Vous saurez que Tesseract, en plus de détester les grandes images et les images avec des couleurs, déteste également les formes dans une image. Ainsi dans notre cas, le round de couleur autour du chiffre, même s'il n'est pas complet, il interfère avec la reconnaissance et empêche de bien lire le chiffre.</p>
<p>Il faut donc retirer le background et ensuite la couleur. Sauf que comme le chiffre est de la couleur du background, si on retire le background et ensuite la couleur, il ne reste plus rien. Il faut alors retirer le background AUTOUR du rond, et ensuite si on retire la couleur, il devrait rester le chiffre sur fond blanc.</p>
<p>Pour ce faire, j'ai tiré des traits depuis les bords de l'image jusqu'à ce qu'ils rencontrent le rond. Ensuite, je retire tous les pixels entre le rond et les bords de l'image, ce qui nous donne ceci :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-71">
<a class="glightbox" href="./Images/Screens/TyreZoneCropedWithoutBackGround.png"><img alt="" avec="" background="" en="" le="" moins""="" pneu="" src="./Images/Screens/TyreZoneCropedWithoutBackGround.png" zone=""/></a>
<figcaption>"Zone pneu avec le background en moins"</figcaption>
<figcaption>Figure 71 - "Zone pneu avec le background en moins"</figcaption>
</figure>
<p>Ensuite, on peut retirer les pixels qui ont une valeur dans un channel RGB plus haute qu'un certain seuil :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-72">
<a class="glightbox" href="./Images/Screens/TyreZoneFilter1.png"><img alt="" avec="" couleurs="" des="" le="" reste="" src="./Images/Screens/TyreZoneFilter1.png" supprimées""="" zone=""/></a>
<figcaption>"Zone avec le reste des couleurs supprimées"</figcaption>
<figcaption>Figure 72 - "Zone avec le reste des couleurs supprimées"</figcaption>
</figure>
<p>Et là, on a ce que l'on veut !</p>
<p>À partir de là, ce sont les filtres que l'on connait qui sont utilisés pour en faire une image plus facile à utiliser par Tesseract.</p>
<p>1 : On effectue un <em>Resize</em> de facteur 4 (oui, c'est beaucoup, mais en même temps le chiffre est vraiment petit à la base) qui permet d'avoir une image d'une bien meilleure résolution.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-73">
<a class="glightbox" href="./Images/Screens/TyreZoneFilter2.png"><img 1""="" alt="" filtre="" src="./Images/Screens/TyreZoneFilter2.png"/></a>
<figcaption>"Filtre 1"</figcaption>
<figcaption>Figure 73 - "Filtre 1"</figcaption>
</figure>
<p>2 : On fait une <em>Dilatation</em> de facteur 1 pour retirer tout le flou de l'image pour aider Tesseract</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-74">
<a class="glightbox" href="./Images/Screens/TyreZoneAfter.png"><img alt="" resultat""="" src="./Images/Screens/TyreZoneAfter.png"/></a>
<figcaption>"Resultat"</figcaption>
<figcaption>Figure 74 - "Resultat"</figcaption>
</figure>
<p>Et on a un chiffre qui est utilisable par Tesseract !</p>
<p><em>Explication des méthodes précises plus bas</em></p>
@@ -3122,9 +3127,9 @@ Voici un sommaire des méthodes utilisées et comment elles fonctionnent.</p>
<p>Cette méthode sert à passer d'une image en couleurs à une image binaire noir-blanc.
C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'isoler du texte de son background.</p>
<p>Un exemple ici :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-75">
<a class="glightbox" href="./Images/Photos/TresholdExemple1.webp"><img alt="" exemple="" src="./Images/Photos/TresholdExemple1.webp" treshold""=""/></a>
<figcaption>"Exemple treshold"</figcaption>
<figcaption>Figure 75 - "Exemple treshold"</figcaption>
</figure>
<p>Le fonctionnement est assez simple, mais il peut être fait de différentes manières, mais dans mon cas voici comment l'algorithme fonctionne sachant qu'il demande en entrée la Bitmap que l'on veut modifier ainsi que la valeur de Treshold :</p>
<ol>
@@ -3137,24 +3142,24 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p><em>Resize</em></p>
<p>Cette méthode sert à augmenter la résolution d'une image pour améliorer la précision de l'algorithme de Tesseract. En effet, avec trop peu de pixels, la matrice de convolution n'est pas toujours aussi efficace.</p>
<p>Il ne faut pas confondre cette méthode d'augmentation de la taille avec une simple interpolation. En effet, une augmentation de taille interpolée ne va pas vraiment changer la résolution, l'image sera toujours aussi pixelisée, seulement, les pixels seront composés de plus de pixels comme dans l'exemple ci-dessous :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-76">
<a class="glightbox" href="./Images/Photos/InterpolationExemple.png"><img alt="" d'interpolation="" exemple="" linéaire""="" src="./Images/Photos/InterpolationExemple.png"/></a>
<figcaption>"Exemple d'interpolation linéaire"</figcaption>
<figcaption>Figure 76 - "Exemple d'interpolation linéaire"</figcaption>
</figure>
<p>Dans mon projet, j'utilise de l'interpolation bicubique qui va créer de l'information pour tenter de combler le vide et produire une image réellement plus grande et avec plus de détails, mais en ajoutant du flou.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-77">
<a class="glightbox" href="./Images/Photos/BicubicExample.png"><img alt="" d'interpolation""="" des="" différents="" exemple="" src="./Images/Photos/BicubicExample.png" types=""/></a>
<figcaption>"Exemple des différents types d'interpolation"</figcaption>
<figcaption>Figure 77 - "Exemple des différents types d'interpolation"</figcaption>
</figure>
<p>Le but est d'aller chercher dans les pixels alentours les couleurs qui sont déjà présentes et de jouer avec des poids pour tenter de faire une prédiction de ce que ce pixel aurait été si l'image avait plus de détails.</p>
<p>Voici un exemple assez parlant :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-78">
<a class="glightbox" href="./Images/Photos/BicubicExample1.webp"><img (avant)""="" alt="" bicubique="" exemple="" interpolation="" src="./Images/Photos/BicubicExample1.webp"/></a>
<figcaption>"Exemple interpolation bicubique (avant)"</figcaption>
<figcaption>Figure 78 - "Exemple interpolation bicubique (avant)"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-79">
<a class="glightbox" href="./Images/Photos/BicubicExample2.webp"><img (après)""="" alt="" bicubique="" exemple="" interpolation="" src="./Images/Photos/BicubicExample2.webp"/></a>
<figcaption>"Exemple interpolation bicubique (après)"</figcaption>
<figcaption>Figure 79 - "Exemple interpolation bicubique (après)"</figcaption>
</figure>
<p>On pourrait croire que c'est inutile, mais dans le contexte de Tesseract ajouter des détails pour tenter de simuler une meilleure résolution même en créant du flou est intéressant pour mieux remplir la matrice de convolution.</p>
<p>Mais il est possible de réduire ce flou avec d'autres méthodes également.</p>
@@ -3171,18 +3176,18 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<h6 id="petit-point-resolution">Petit point résolution</h6>
<p>Comme on peut l'imaginer, la résolution est extrêmement importante pour l'OCR. Et en avançant sur le projet de l'émulateur, je me suis rendu compte qu'il était possible de récupérer des images en 4K (Plutôt 1080 avec l'upscaling du lecteur). Cela est une superbe nouvelle car cela permet de simplifier énormément le processing sur les différentes windows.</p>
<p>Quelques exemples pour se faire une idée</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-80">
<a class="glightbox" href="./Images/Screens/F1TVLOWRES.png"><img 720p""="" alt="" echantillon="" src="./Images/Screens/F1TVLOWRES.png"/></a>
<figcaption>"Echantillon 720P"</figcaption>
<figcaption>Figure 80 - "Echantillon 720P"</figcaption>
</figure>
<p>;</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-81">
<a class="glightbox" href="./Images/Screens/F1TVHIGHRES.png"><img 1080p""="" alt="" echantillon="" src="./Images/Screens/F1TVHIGHRES.png"/></a>
<figcaption>"Echantillon 1080P"</figcaption>
<figcaption>Figure 81 - "Echantillon 1080P"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-82">
<a class="glightbox" href="./Images/Screens/F1TVHIGHERRES.png"><img 4k""="" alt="" echantillon="" src="./Images/Screens/F1TVHIGHERRES.png"/></a>
<figcaption>"Echantillon 4K"</figcaption>
<figcaption>Figure 82 - "Echantillon 4K"</figcaption>
</figure>
<p>Mais il faut savoir que grâce à cette simplification, j'ai pu aussi créer d'autres méthodes de filtrage pour certaines parties. Mais la simplification était obligatoire, car avec des images aussi grandes, il n'était simplement pas possible de venir appliquer les mêmes filtres car le temps de traitement serait beaucoup plus long.</p>
<p>J'indique ces changements que après l'explication d'avant car ce sont des changements un peu de dernière minute et que la logique expliquée plus haut a été très importante pour le projet OCR même si tout n'est plus forcément utilisé maintenant que j'ai des images de meilleure qualité.</p>
@@ -3198,18 +3203,18 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p><em>VanishOxyAction</em></p>
<p>Cette méthode est une méthode plutôt simple, mais qui est importante. Elle se base beaucoup sur le code de la méthode <em>Grayscale</em> et sur la méthode <em>Tresholding</em> car elle essaie de regrouper le meilleur dès deux en réglant quelques soucis que ces dernières créaient.</p>
<p>Les soucis avec la méthode grayscale c'est que quand le texte est de couleur (Ce qui arrive souvent pour les temps de secteurs) la méthode <em>GrayScale</em> rend les couleurs dans une nuance de gris un peu trop sombre ce qui fait qu'ensuite la méthode de <em>Tresholding</em> défonce tout.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-83">
<a class="glightbox" href="./Images/Screens/VanishRaw.png"><img alt="" couleur""="" de="" en="" exemple="" secteur="" src="./Images/Screens/VanishRaw.png"/></a>
<figcaption>"Exemple de secteur en couleur"</figcaption>
<figcaption>Figure 83 - "Exemple de secteur en couleur"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-84">
<a class="glightbox" href="./Images/Screens/VanishGrayScale.png"><img alt="" de="" en="" exemple="" grayscale""="" secteur="" src="./Images/Screens/VanishGrayScale.png"/></a>
<figcaption>"Exemple de secteur en grayscale"</figcaption>
<figcaption>Figure 84 - "Exemple de secteur en grayscale"</figcaption>
</figure>
<p>L'idée est alors de prendre pour chaque pixel et de garder uniquement la valeur de R, G ou B la plus haute et de mettre les deux autres canaux au même niveau pour avoir une image blanchie qui puisse être ensuite utilisée avec la méthode de <em>Tresholding</em> sans soucis.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-85">
<a class="glightbox" href="./Images/Screens/VanishVanish.png"><img alt="" avec="" blanchi="" de="" exemple="" secteur="" src="./Images/Screens/VanishVanish.png" vanishoxyaction""=""/></a>
<figcaption>"Exemple de secteur blanchi avec vanishoxyAction"</figcaption>
<figcaption>Figure 85 - "Exemple de secteur blanchi avec vanishoxyAction"</figcaption>
</figure>
<p><em>SobelEdgeDetection</em></p>
<p>On pourrait se dire qu'avec ce genre de méthode le tresholding est inutile ensuite, mais ça n'est pas le cas, car le tresholding sert ensuite pour rendre les contours plus ou moins agressif. Parce que même si l'image ressemble à une image binarisée, il reste des nuances que le treshold va pouvoir utiliser.</p>
@@ -3219,9 +3224,9 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p>Cette méthode a besoin d'une image passée en noir et blanc au préalable à laquelle on applique ensuite les matrices de filtres. Et avec ces filtres ajoutés à l'image, on peut ensuite calculer le "Gradient" pour créer les bords.</p>
<p>Le seul souci de cette méthode, c'est qu'elle est assez gourmande et qu'elle fournit des formes creuses dû à la nature des matrices données.</p>
<p>Voici un exemple de ce dont cette méthode est capable :</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-86">
<a class="glightbox" href="./Images/Screens/SobelArtefacts.png"><img alt="Artefacts de la détection de bords de Sobel" src="./Images/Screens/SobelArtefacts.png"/></a>
<figcaption>Artefacts de la détection de bords de Sobel</figcaption>
<figcaption>Figure 86 - Artefacts de la détection de bords de Sobel</figcaption>
</figure>
<p>Apparemment l'OCR aime assez bien cette méthode et elle permet de beaucoup moins souvent oublier les '.' ou ':'</p>
<h3 id="traitement-des-donnees">Traitement des données</h3>
@@ -3246,13 +3251,13 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p>Mais l'exemple qui détruit vraiment tout, ce sont les écarts avec le leader. Autant un temps au tour, c'est toujours x:xx.xxx et un temps de secteur, c'est xx.xxx. Mais un écart avec le leader ça peut être 0.345 comme 1:12.345. Ce qui fait que lorsque je reçois 121345 est-ce que c'est 12.345 ou 1:21.345...?</p>
<p>Souvent, on peut quand même déduire, mais cela demande de prévoir presque tous les cas limites, ce qui est assez pénible.</p>
<p>On pourrait se dire qu'il suffit de voir si la valeur est trop en dehors des normes. Le souci, c'est qu'il n'est pas impossible qu'un temps au tour ou un écart prenne d'un coup une grosse différence. Cela arrive même assez souvent quand des pilotes sortent de la piste.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-87">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeBefore.png"><img alt="" au="" exemple="" src="./Images/Screens/ExempleLapTimeBefore.png" temps="" tour""=""/></a>
<figcaption>"Exemple temps au tour"</figcaption>
<figcaption>Figure 87 - "Exemple temps au tour"</figcaption>
</figure>
<figure class="figure-image">
<figure class="figure-image" id="figure-88">
<a class="glightbox" href="./Images/Screens/VanishRaw.png"><img alt="" exemple="" secteur""="" src="./Images/Screens/VanishRaw.png" temps=""/></a>
<figcaption>"Exemple temps secteur"</figcaption>
<figcaption>Figure 88 - "Exemple temps secteur"</figcaption>
</figure>
<p>Pour ce qui est du DRS et de la position des pilotes, il n'y a pas vraiment de traitement supplémentaire. Non pas, car la détection est parfaite, mais par ce que la détection ne peut pas rater de 200 façons. Le DRS ne peut retourner que TRUE ou FALSE et la position du pilote est entre 1 et 20 compris. Le peu de nuance fait que ce sont des cas de figures qui ne demandent pas un traitement particulier au-delà de l'OCR</p>
<h3 id="stockage-des-donnees">Stockage des données</h3>
@@ -3261,9 +3266,9 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p>Il faut donc garder en mémoire les différentes choses qui se sont passées. Techniquement, on pourrait stocker ces données dans de bêtes listes C#. Mais le souci avec ça, c'est que même si des outils comme LinQ existent, ça n'est pas le plus pratique quand on veut faire des recherches complexes.</p>
<p>Il faut aussi voir que si le projet dans sa forme actuelle aurait peut-être pu se satisfaire de listes simples, le but est d'ensuite pouvoir construire sur ces bases pour faire des prédictions et des insertions de stats beaucoup plus intéressantes qui demandent de faire des requêtes complexe rapidement.</p>
<p>Je me suis dit que la meilleure méthode serait d'avoir une base de donnée dans laquelle je peux faire des requêtes SQL. Mais, comme je n'ai pas besoin de toutes les features de SQl et que je ne veux pas avoir à gérer un serveur de base de donnée et tout ce qui va avec, je me suis dit qu'une bonne option serait d'utiliser SQLite.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-89">
<a class="glightbox" href="./Images/Photos/SQLite_Logo.png"><img alt="" logo="" sqlite""="" src="./Images/Photos/SQLite_Logo.png"/></a>
<figcaption>"Logo SQLite"</figcaption>
<figcaption>Figure 89 - "Logo SQLite"</figcaption>
</figure>
<p>;</p>
<p>SQLite est vraiment pratique, car cela me permet d'avoir une DB sans avoir de serveur, donc pas vraiment complexe ou quoi que ce soit, mais qui conserve les avantages de rapidité et d'utilisation de requêtes SQL.</p>
@@ -3430,9 +3435,9 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
<p>Sauf que il faut ajouter à cette reflexion qu'un pneu peut être chaussé sans qu'il soit neuf. Ce qui veut dire que l'on ne peut pas simplement choisir qu'un pilote a changé de pneus quand ses pneus sont à 1 tour. Il peut très bien reprendre des pneus de qualif qui peuvent avoir 10 tours dans les pattes.</p>
<p>En plus quand le pilote change de pneus il y a un phenomene assez pénible qui fait que les deux premiers tours faits avec ne sont pass vraiment déchiffrables car ils sont un peu cachés derrière la lettre qui indique le nouveau pneu chaussé.</p>
<p>Exemple : </p>
<figure class="figure-image">
<figure class="figure-image" id="figure-90">
<a class="glightbox" href="./Images/Screens/CroppedTyres.png"><img alt="" chevauche""="" de="" infographie="" pneu="" qui="" se="" src="./Images/Screens/CroppedTyres.png"/></a>
<figcaption>"Infographie de pneu qui se chevauche"</figcaption>
<figcaption>Figure 90 - "Infographie de pneu qui se chevauche"</figcaption>
</figure>
<p>Voici le code que j'avais écrit pour tenter de trouver quand un pilote avait fait un pitstop :</p>
<div class="language-Csharp highlight"><pre><span></span><code><span id="__span-8-1"><a href="#__codelineno-8-1" id="__codelineno-8-1" name="__codelineno-8-1"></a><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">data</span><span class="p">.</span><span class="n">CurrentTyre</span><span class="p">.</span><span class="n">Coumpound</span><span class="w"> </span><span class="p">!=</span><span class="w"> </span><span class="n">Tyre</span><span class="p">.</span><span class="n">Type</span><span class="p">.</span><span class="n">Undefined</span><span class="w"> </span>
@@ -3465,9 +3470,9 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
</span></code></pre></div>
<p>C'est l'affichage le plus simple et celui qui est le plus soumis à des erreurs. En effet, si un pilote est mal detecté on le verra directement mal s'afficher dans la Form principale.</p>
<p>C'est également l'affichage le moins intéressant car il ne crée aucune information, il ne fait que remontrer les infos que l'on peut déja voir dans la F1TV</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-91">
<a class="glightbox" href="./Images/Screens/SmallDriverInfoExemple.png"><img alt="" d'affichage="" exemple="" live""="" src="./Images/Screens/SmallDriverInfoExemple.png"/></a>
<figcaption>"Exemple d'affichage live"</figcaption>
<figcaption>Figure 91 - "Exemple d'affichage live"</figcaption>
</figure>
<h4 id="affichage-calcule">Affichage calculé</h4>
<p>La encore il y a plusieurs types d'affichages :</p>
@@ -3475,9 +3480,9 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
<p>Pour ce qui est des affichages hybrides ce sont des affichages qui vont chercher des informations lives et des informations dans la base de donnée. Ils ne font pas de calculs à proprement parler mais ils affichent plus d'informations que ce que montre la F1TV. Cela veut dire qu'ils représentent un début de plusvalue par rapport à l'alternative qu'est la page DATA de la F1TV.</p>
<p>Ils ne sont pas beaucoup plus durs à implémenter mais demandent de faire des requêtes à la base de donnée.</p>
<p>Comme exemple d'affichage hybride on a l'affichage des cinq derniers tours d'un pilote. C'est un affichage qui ne demande aucun calcul mais qui permet deja de se rendre compte de si le pilote est enn train de perdre ou gagner du temps ou si il est constant, ce qui n'est pas possible actuellement avec la F1TV à moins d'avoir une excellente mémoire.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-92">
<a class="glightbox" href="./Images/Screens/SmallDriverInfoFullExemple.png"><img alt="" d'informations="" d'un="" fenêtre="" pilote""="" propos="" src="./Images/Screens/SmallDriverInfoFullExemple.png" à=""/></a>
<figcaption>"Fenêtre d'informations à propos d'un pilote"</figcaption>
<figcaption>Figure 92 - "Fenêtre d'informations à propos d'un pilote"</figcaption>
</figure>
<p>Voici un exemmple du type de code necessaire pour afficher ce genre de données:</p>
<div class="language-Csharp highlight"><pre><span></span><code><span id="__span-10-1"><a href="#__codelineno-10-1" id="__codelineno-10-1" name="__codelineno-10-1"></a><span class="k">public</span><span class="w"> </span><span class="n">List</span><span class="p">&lt;(</span><span class="kt">int</span><span class="w"> </span><span class="n">LapTime</span><span class="p">,</span><span class="w"> </span><span class="kt">int</span><span class="w"> </span><span class="n">Lap</span><span class="p">)&gt;</span><span class="w"> </span><span class="n">GetDriverLaptimes</span><span class="p">(</span><span class="kt">string</span><span class="w"> </span><span class="n">driverName</span><span class="p">,</span><span class="kt">int</span><span class="w"> </span><span class="n">numberOfLaptimes</span><span class="p">)</span><span class="w"></span>
@@ -3512,9 +3517,9 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
</span></code></pre></div>
<p>Note: Le code montré ici n'est pas forcément le code utilisé dans le projet.</p>
<p>D'une certaine facon les fenêtres de bataille et de dépassements sont aussi des hybrides.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-93">
<a class="glightbox" href="./Images/Screens/BattlesWindowExemple.png"><img alt="" batailles""="" des="" exemple="" fenêtre="" src="./Images/Screens/BattlesWindowExemple.png"/></a>
<figcaption>"Exemple fenêtre des batailles"</figcaption>
<figcaption>Figure 93 - "Exemple fenêtre des batailles"</figcaption>
</figure>
<p>Ici ce sont les batailles qui sont représentées. Aucune donnée n'est calculée, c'est litterallement directement les données de la F1TV, mais la nuance est qu'on ne montre que les pilotes qui sont en train de se battre et que on leur assigne une couleur selon à quel point ils sont proches. On a une plus-value sur la F1TV sans pour autant faire de monstres calculs.</p>
<p>Pour info, les pilotes considèrés comme êtant en train de se battre sont les pilotes à moins de trois secondes les uns des autres et les couleurs sont suivantes :</p>
@@ -3523,18 +3528,18 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
<li>Jaune : Plus d'une seconde</li>
<li>Noir : Plus de deux secondes</li>
</ul>
<figure class="figure-image">
<figure class="figure-image" id="figure-94">
<a class="glightbox" href="./Images/Screens/OvertakesWindowExemple.png"><img alt="" des="" dépassements""="" exemple="" fenêtre="" src="./Images/Screens/OvertakesWindowExemple.png"/></a>
<figcaption>"Exemple fenêtre des dépassements"</figcaption>
<figcaption>Figure 94 - "Exemple fenêtre des dépassements"</figcaption>
</figure>
<p>La c'est l'historique des dépassements qui est affiché. On pourrait presque dire que c'est un affichage complêtement calculé car ce ne sont pas des informations disponibles directement sur la F1TV cependant je dirais que cela reste un hybride car il n'y a aucuns calculs. On regarde juste les différences entre l'ancienne position d'un pilote et la nouvelle et on affiche les changements.</p>
<h5 id="affichage-totalement-calcule">Affichage totalement calculé</h5>
<p>L'affichage complêtement calculé est un type d'affichage qui ne montre aucune information trouvée sur la page de la F1TV. C'est le premier affichage à traiter l'information qu'il trouve et il retourne des informations nouvelles. La nuance avec les affichages prédictif est qu'il ne crée pas réellement de l'information, il la déduit.</p>
<p>Le but est de prendre un certain nombre d'informations trouvées sur la page de la F1TV et de calculer des choses pour faire ressortir des tendances à l'utilisateur. Cependant on reste sur des informations factuelles. Ce sont des infos déduites que techniquement unn humain avec une bonne mémoire et fort en calcul mental pourrait faire. Mais la c'est fait automatiquement pour tous les pilotes et c'est affiché de sorte à faire ressortir les valeurs spéciales.</p>
<p>Comme c'est un peu plus abstrait, je pense qu'un exemple vaut mieux que 1000 mots.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-95">
<a class="glightbox" href="./Images/Screens/SlowestAndFastestExemple.png"><img alt="" calculées""="" d'informations="" de="" exemple="" fenêtre="" src="./Images/Screens/SlowestAndFastestExemple.png" totalement=""/></a>
<figcaption>"Exemple de fenêtre d'informations totalement calculées"</figcaption>
<figcaption>Figure 95 - "Exemple de fenêtre d'informations totalement calculées"</figcaption>
</figure>
<p>Ci dessus on peut voir un bon exemple. C'est une fenêtre qui montre qui sont les pilotes les plus rapides et les moins rapides et qui montre la différence de temps au tour.</p>
<p>Cette information est totalement déduite et n'est en aucun cas trouvable sur la F1TV mais elle n'est pas inventée. Elle est simplement calculée.</p>
@@ -3627,9 +3632,9 @@ Les seules données qui changent entre deux passages de l'OCR sont les écarts e
</span><span id="__span-12-36"><a href="#__codelineno-12-36" id="__codelineno-12-36" name="__codelineno-12-36"></a><span class="p">}</span><span class="w"></span>
</span></code></pre></div>
<p>Tout le code supplémentaire qui ne fait pas partie des étapes citées est juste la pour manipuler le format des résultats pour qu'il soit comparable.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-96">
<a class="glightbox" href="./Images/Screens/DataSetGaps.png"><img alt="" d'échantillons="" exemple="" les="" pour="" src="./Images/Screens/DataSetGaps.png" tests""=""/></a>
<figcaption>"Exemple d'échantillons pour les tests"</figcaption>
<figcaption>Figure 96 - "Exemple d'échantillons pour les tests"</figcaption>
</figure>
<p>Ce qui est pratique avec cette approche, c'est qu'il est très facile de rajouter des cas spécifiques et voir comment le programme les gère.
Si je vois qu'un certain nombre est souvent mal reconnu, je peux faire exprès de le mettre dans le dossier et modifier mon code d'OCR jusqu'à ce que le test passe.</p>
@@ -3685,33 +3690,33 @@ Si je vois qu'un certain nombre est souvent mal reconnu, je peux faire exprès d
<p>Pour ce qui est du démarrage, malheureusement, on ne peut pas faire grand-chose. Lancer le browser et naviguer à travers la F1TV prend du temps, surtout si la connexion du client est mauvaise. Pour certaines actions, j'ai fait un système qui essaie pendant 10 secondes de cliquer sur un bouton plutôt que d'attendre 10 secondes et cliquer pour tenter d'économiser un peu, mais malheureusement, c'est lent et on ne peut pas y faire grand-chose.</p>
<p>Pour la génération des instances de Tesseract, c'est un peu pareil, mais pour d'autres raisons. Comme Tesseract n'est pas "Thread Safe" (Ce qui veut dire qu'il n'est pas parallélisable), si on veut faire plusieurs reconnaissances à la fois, il faut plusieurs instances de Tesseract loadées en mémoire. J'ai donc décidé, pour une question de simplicité et de performances, de faire en sorte que chaque fenêtre de donnée ou "Window" aie sa propre instance de Tesseract.</p>
<p>Vous qui lisez ces lignes êtes peut-être en train de vous dire "Oulala mais ça doit beaucoup de mémoire son truc là " et vous auriez parfaitement raison !</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-97">
<a class="glightbox" href="./Images/Screens/MemoryUtilisation.png"><img alt="" après="" avoir="" commencé="" consommation="" de="" détection""="" la="" mémoire="" peu="" src="./Images/Screens/MemoryUtilisation.png"/></a>
<figcaption>"Consommation de mémoire peu après avoir commencé la détection"</figcaption>
<figcaption>Figure 97 - "Consommation de mémoire peu après avoir commencé la détection"</figcaption>
</figure>
<p>Ce programme consomme en effet une quantité absolument catastrophique de mémoire vive. Mais si je l'ai fait, c'est pour une bonne raison. Cela prend juste beaucoup trop de temps de créer une nouvelle instance à chaque boucle de Tesseract et c'est encore plus long de faire toutes les opérations d'OCR les unes après les autres pour n'avoir qu'un seul Tesseract de loadé.</p>
<p>On peut parfois arriver à des chiffres qui approchent les 4GB de RAM ce qui est absolument RIDICULE. Cependant, c'est un compromis que j'étais prêt à faire pour avoir une application qui soit plus rapide.</p>
<p>Je suis absolument certain que cette solution et les autres solutions que j'ai trouvées pour ce projet ne sont pas les meilleures ou les plus efficaces. Mais ce sont les solutions que j'ai trouvé pour faire en sorte que le projet avance et fonctionne à peu près vite.</p>
<p>Ensuite pour ce qui est de ce qui se passe à chaque boucle, là le mot magique, c'est "Parallèle". Le traitement de toutes les zones est fait en même temps.</p>
<p>La structure du projet en zones, sous zones et fenêtres de données fait qu'il est assez facile de venir paralléliser le processus si on les implémente correctement.</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-98">
<a class="glightbox" href="./Images/Figma/ZonesStuctureDiagram.png"><img alt="Diagramme qui montre comment les zones et fenêtres interagissent" src="./Images/Figma/ZonesStuctureDiagram.png"/></a>
<figcaption>Diagramme qui montre comment les zones et fenêtres interagissent</figcaption>
<figcaption>Figure 98 - Diagramme qui montre comment les zones et fenêtres interagissent</figcaption>
</figure>
<p>On peut voir sur ce diagramme que la zone principale demande à toutes les sous zones de décoder leur contenu. Ces dernières font l'exacte même chose avec les fenêtres de données qui retournent chacune ce qu'elles contiennent après un coup d'OCR et ensuite les zones recombinent les informations et les envoient à la zone principale.</p>
<p>Tout cela est très bien, mais quel rapport avec la parallélisation ? Eh bien, comme chaque zone de pilote est indépendante, on peut tout simplement faire une boucle for parallèle qui appelle toutes les zones pilotes.</p>
<p>On passe de 15 à 20 secondes de traitement à un peu plus de trois juste avec cette technique. Alors ça n'était pas simple à implémenter, car il a fallu programmer les zones de sorte qu'elles soient toutes indépendantes les unes des autres. Mais une fois que le travail en amont a été effectué, il est très simple de paralléliser.</p>
<p>Les filtres fonctionnent de la même façon sauf que là, on parallélise le traitement de chaque ligne dans une image. L'impact est moindre qu'avec les zones, mais si on teste avec une machine assez puissante cela pourrait faire la différence.</p>
<p>Seul souci avec cette méthode, cela veut dire que le processeur est particulièrement sollicité '^^...</p>
<figure class="figure-image">
<figure class="figure-image" id="figure-99">
<a class="glightbox" href="./Images/Screens/CPUUsage.png"><img alt="" de="" du="" fonctionnement="" l'application""="" le="" pendant="" processeur="" src="./Images/Screens/CPUUsage.png" utilisation=""/></a>
<figcaption>"Utilisation du processeur pendant le fonctionnement de l'application"</figcaption>
<figcaption>Figure 99 - "Utilisation du processeur pendant le fonctionnement de l'application"</figcaption>
</figure>
<p>Mon laptop ne possède malheureusement que six coeurs ce qui limite pas mal la puissance de la paralellisation. Mais je suis convaincu qu'avec un CPU avec plus de coeurs on pourrait arriver à d'encore meilleurs résultats.</p>
<p>Mais cette utilisation du processeur a aussi un inconvénient... </p>
<figure class="figure-image">
<figure class="figure-image" id="figure-100">
<a class="glightbox" href="./Images/Photos/PCThermals.jpg"><img alt="" de="" du="" fonctionnement="" l'application""="" laptop="" le="" pendant="" src="./Images/Photos/PCThermals.jpg" températures=""/></a>
<figcaption>"Températures du laptop pendant le fonctionnement de l'application"</figcaption>
<figcaption>Figure 100 - "Températures du laptop pendant le fonctionnement de l'application"</figcaption>
</figure>
<p>;</p>
<p>Donc si je veux commenter la F1 avec cet outil, note à moi même, je ne dois pas utiliser le laptop si je ne veux pas me cramer les doigts.</p>
@@ -3751,9 +3756,9 @@ Si je vois qu'un certain nombre est souvent mal reconnu, je peux faire exprès d
<p>Mais il est intéressant de mentionner que mon application met en péril la sécurité des cookies de l'utilisateur et qu'il serait bien dans le futur de mettre un message explicatif au premier démarrage ou dans l'installeur de l'application pour prévenir l'utilisateur.</p>
<h2 id="utilisation-de-chat-gpt">Utilisation de Chat GPT</h2>
<hr/>
<figure class="figure-image">
<figure class="figure-image" id="figure-101">
<a class="glightbox" href="./Images/Screens/GPTLogo.png"><img alt="" chat="" gpt""="" logo="" src="./Images/Screens/GPTLogo.png"/></a>
<figcaption>"Logo chat Gpt"</figcaption>
<figcaption>Figure 101 - "Logo chat Gpt"</figcaption>
</figure>
<p>Cette année, ChatGPT est venu s'installer dans la liste des outils que j'utilise presque quotidiennement pour avancer sur mes projets.</p>
<p>J'ai utilisé ChatGPT un certain nombre de fois pendant ce travail et je pense qu'il m'a fait gagner un certain nombre d'heures. En effet, dans certains cas très précis, ChatGPT est une ressource absolument géniale.</p>
+288 -235
View File
File diff suppressed because it is too large Load Diff
+14135 -22169
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
+1303
View File
File diff suppressed because it is too large Load Diff