From ac5641125ac504d5a2cbd84e082646bf695c1a4e Mon Sep 17 00:00:00 2001 From: maxluli Date: Thu, 8 Jun 2023 14:24:18 +0200 Subject: [PATCH] Edited syntax --- docs/index.md | 1132 ++++++++++++++++++++++++------------------------- 1 file changed, 565 insertions(+), 567 deletions(-) diff --git a/docs/index.md b/docs/index.md index d56a071..02dee52 100644 --- a/docs/index.md +++ b/docs/index.md @@ -18,11 +18,11 @@ Pour le contexte, en dehors des cours, j'exerce différentes activités dont cel Ce dernier ressemble à cela : -!["Screenshot du feed data de la f1tv"](./Images/Screens/ScreenF1TvData.png) +!["Screenshot du feed data de la f1TV"](./Images/Screens/ScreenF1TvData.png) -(Attention ce n'est pas un joli tableau HTML, mais bien une vidéo qui contient un tableau.) +(Attention, ce n'est pas un joli tableau HTML, mais bien une vidéo qui contient un tableau.) -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. +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. Le but du projet est donc de fournir un outil qui hiérarchise et affiche différemment les données pour faciliter leur lecture et me permettre de faire de meilleurs commentaires. @@ -34,16 +34,16 @@ To understand everything,first ,a little bit of context. In my free time I have You can see in the chapter above an example of the F1TV DATA CHANNEL. -[Note : Even tough it looks like a pretty HTML table on wich you could easely get infos... Its not. Its a video feed] +[Note : Even tough it looks like a pretty HTML table on wich you could easely get infos... Its not. It's a video feed] -You can see a lot of data all well and good BUT! All the data is displayed the same in a big table which make it really hard to read totally in a hurry, which means that I miss a lot of useful information. +You can see a lot of data, all well and good BUT! All the data is displayed the same in a big table which make it really hard to read totally in a hurry, which means that I miss a lot of useful information. The point of the project then is to provide a tool that can display those data by taking into account their relevance. -So for example a driver that is 10s away from everyone and that is doing some normal lapTimes will be less displayed or even not displayed at all so I can focus on the drivers that are battling each others. +So for example, a driver that is 10s away from everyone and that is doing some normal lap times will be less displayed or even not displayed at all, so I can focus on the drivers that are battling each others. -This tool would help me not miss the battles and details that are happening in the back and therefore not being broadcasted on TV.And it could be a usefull tool for anyone who wants a better insight of how the race is going by looking at the data. +This tool would help me not miss the battles and details that are happening in the back and therefore not being broadcasted on TV. And it could be a useful tool for anyone who wants a better insight of how the race is going by looking at the data. -This kind of project already exists in the form of the AWS tool "F1 Insight" but it is not avaible to the public. We can only see some of its predictions (that are trash) and data dumps in the live feed when the TV directors feel like it. +This kind of project already exists in the form of the AWS tool "F1 Insight" but it is not avaible to the public. We can only see some of its predictions (that are rubbish) and data dumps in the live feed when the TV directors feel like it. ### Description du besoin @@ -121,7 +121,7 @@ Les données viennent du flux vidéo et ainsi dans un premier temps, il va fallo Ensuite, dans un second temps, il faut lire les informations directement sur l'image en utilisant une librairie prévue pour (exemple Tesseract) et vérifier l'intégrité de ces dernières pour qu'on puisse ensuite les stocker. -Dans un troisième temps, il faut stocker toutes ces données dans une forme qui permette d'aller facilement faire des requêtes de récupération et déjà préparer des méthodes qui permettent de récupérer des infos importantes (ex : la moyenne des cinq derniers tours, le temps moyen d'arrêt etc.) pour faciliter la dernière étape +Dans un troisième temps, il faut stocker toutes ces données dans une forme qui permette d'aller facilement faire des requêtes de récupération et déjà préparer des méthodes qui permettent de récupérer des infos importantes (ex : la moyenne des cinq derniers tours, le temps moyen d'arrêt, etc.) pour faciliter la dernière étape Quand tout cela est fait, on peut ensuite s'amuser un peu avec les Data. @@ -148,7 +148,7 @@ Voire même si c'est possible : Voici un exemple d'interface possible pour une page : -!["Protype de l'app fait sur Figma"](./Images/Figma/Prototype.png) +!["Prototype de l'app fait sur Figma"](./Images/Figma/Prototype.png) ### Cas d'utilisation @@ -192,65 +192,65 @@ Quand le programme affiche les data : ---- -Ici je vais parler de l'étât du projet à la date du 12 Juin 2023. +Ici, je vais parler de l'état du projet à la date du 12 Juin 2023. -A cette date, le projet est fonctionel mais comporte quelques différences avec le cahier des charges original. Je vais expliquer non seulement ces différences mais aussi les raisons qui font qu'elles sont la. +À cette date, le projet est fonctionnel, mais comporte quelques différences avec le cahier des charges original. Je vais expliquer non seulement ces différences, mais aussi les raisons qui font qu'elles sont là. -Pour bien comprendre les différences il faut s'en réfèrer au cahier des charges original. +Pour bien comprendre les différences, il faut s'en référer au cahier des charges original. -L'application doit être "Un outil de style compagnon sous forme d'application C# Windows Form qui récupère en temps réel les informations de la course et affiche les informations les plus importantes". C'est ca la phrase la plus importante dans tout le CDC. Et je pense que très honnêtement, ce cahier des charges est rempli ! +L'application doit être "Un outil de style compagnon sous forme d'application C# Windows Form qui récupère en temps réel les informations de la course et affiche les informations les plus importantes". C'est ça la phrase la plus importante dans tout le CDC. Et je pense que très honnêtement, ce cahier des charges est rempli ! -L'application actuellement disponible sur le répo GIT est une application de style compagnion Windows Forms qui récupère les infos de la F1TV en temps réel et elle affiche les informations qu'elle trouve importante. Donc je dirais que l'objectif général est remplis. +L'application actuellement disponible sur le repos GIT est une application de style compagnion Windows Forms qui récupère les infos de la F1TV en temps réel et elle affiche les informations qu'elle trouve importante. Donc, je dirais que l'objectif général est rempli. -Maintenant c'est dans les détails que cela pêche. +Maintenant, c'est dans les détails que cela pêche. -Il est mentionné trois exemples d'infos à suivre je cite : +Il est mentionné trois exemples d'infos à suivre, je cite : -- "Les pilotes qui sont proches (moins de 1-2 secondes qui sont donc en train de se battre)." +- "Les pilotes qui sont proches (moins de 1-2 secondes qui sont ainsi en train de se battre)." - "Les pilotes qui améliorent leur temps au tour et ceux qui perdent le plus de temps" - "Le classement pondéré tenant compte des futurs arrêts au stand" résultats : -1. Dans l'application on peut effectivement voir les pilotes proches (Ce sont ceux qui sont à moins de 3 secondes dans le version finale) -2. Dans l'application on peut aussi voir un affichage qui permet de voir les pilotes les plus rapides et les plus lents sur le circuit. -3. On ne peut en revanche pas voir de classement pondéré selon les arrêts aux stands car l'application a du mal à detecter des arrêts. +1. Dans l'application, on peut effectivement voir les pilotes proches (Ce sont ceux qui sont à moins de 3 secondes dans le version finale) +2. Dans l'application, on peut aussi voir un affichage qui permet de voir les pilotes les plus rapides et les plus lents sur le circuit. +3. On ne peut en revanche pas voir de classement pondéré selon les arrêts aux stands, car l'application a du mal à détecter des arrêts. -Ensuite pour ce qui est des prédictions il n'y en a aucunes comme ca c'est simple. +Ensuite pour ce qui est des prédictions, il n'y en a aucunes comme ça, c'est simple. -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 car il manque beaucoup de choses comme les prédictions et certains affichages. +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. -On peut aussi se dire ca en comparant la maquette du CDC et le résultat final. +On peut aussi se dire ça en comparant la maquette du CDC et le résultat final. !["Maquette originale du projet faite sur Figma"](./Images/Figma/Prototype.png) !["Maquette originale du projet faite sur Figma"](./Images/Screens/MainPage2.png) -Clairement un oeuil non avisé pourrait être très décu et pourrait dire que c'est un echec. +Clairement, un œil non avisé pourrait être très déçu et pourrait dire que c'est un échec. -Et moi je vais vous expliquer pourquoi au contraire c'est un total succès. +Et moi je vais vous expliquer pourquoi, au contraire c'est un total succès. -Déja, la beauté de l'interface est très difficile a répliquer en Windows Forms et il faudrait plus d'une semaine de travail pour arriver à quelque chose qui pourrait ressembler un tout petit peu à la maquette. +Déjà, la beauté de l'interface est très difficile à répliquer en Windows Forms et il faudrait plus d'une semaine de travail pour arriver à quelque chose qui pourrait ressembler un tout petit peu à la maquette. -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éja une grosse plus-value par rapport à la page Data de la F1TV. +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. -Et finalement, les prédictions, les affichages et le style ce sont les choses les moins compliquées du projet. On ne se rends pas compte que pour simplement afficher les 20 pilotes dans le bon ordre il faut énormément de travail. +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. -Voici une petite représentation graphique de la quantité de travail nescessaire pour en arriver à l'étât actuel du projet : +Voici une petite représentation graphique de la quantité de travail nécessaire pour en arriver à l'état actuel du projet : !["Graphique représentant la quantité de travail requise"](./Images/Figma/TimeRepartition.png) -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. +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. -J'ai passé presque 90% du temps de mon projet à développer des choses qui permettront ensuite de faire de l'affichage. +J'ai passé presque 90 % du temps de mon projet à développer des choses qui permettront ensuite de faire de l'affichage. -Le fait qu'il y aie quoi que ce soit de logique qui s'affiche cela veut dire que TOUT LE RESTE fonctionne ! Le moindre soucis à la récupération des images, ou surtout à la reconnaissance de texte et de chiffres et l'affichage est ruiné. +Le fait qu'il y ait quoi que ce soit de logique qui s'affiche, cela veut dire que TOUT LE RESTE fonctionne ! Le moindre souci à la récupération des images, ou surtout à la reconnaissance de texte et de chiffres, et l'affichage est ruiné. -Si j'avais passé ne serait-ce qu'une semaine de plus juste sur l'affichage le résultat final n'aurait rien à voir. +Si j'avais passé ne serait-ce qu'une semaine de plus juste sur l'affichage, le résultat final n'aurait rien à voir. -Le soucis c'est simplement que le cahier des charges ne parle pas du tout du reste du projet et ne parle que du résultat final. +Le souci, c'est simplement que le cahier des charges ne parle pas du tout du reste du projet et ne parle que du résultat final. -Pour toutes ces raisons je dirais que le CDC était trop superficiel mais que l'application est conforme à l'idée générale de ce dernier et qu'il serait très facile de la rendre parfaitement conforme maintenant que tout le travail de fond a été fait et fonctionne et je pense donc que c'est un succès. +Pour toutes ces raisons, je dirais que le CDC était trop superficiel, mais que l'application est conforme à l'idée générale de ce dernier et qu'il serait très facile de la rendre parfaitement conforme maintenant que tout le travail de fond a été fait et fonctionne et je pense donc que c'est un succès. ## Planning prévisionnel @@ -300,13 +300,13 @@ Il y a déjà des croquis de poster et j'ai clairement prévu de travailler sur Cette tâche est dédiée à l'écriture de la documentation et plus précisément de l'analyse de l'existant. -Comme il y a pas mal de technologies utilisées dans mon projet, j'aimerais faire correctement un vrai debrief de pourquoi j'ai utilisé l'une ou l'autre alors, j'ai assigné deux jours dessus. +Comme il y a pas mal de technologies utilisées dans mon projet, j'aimerais faire correctement un vrai debrief de pourquoi j'ai utilisé l'une ou l'autre, alors, j'ai assigné deux jours dessus. ##### DT3 Documentation Analyse organique (5) Cette tâche est la plus grosse dans la catégorie documentation. Il s'agit de documenter comment l'application fonctionne. -J'y ai mis cinq jours et je pense que c'est un minimum car c'est dans cette tâche que je vais devoir détailler exactement comment fonctionne chaque partie du projet. +J'y ai mis cinq jours et je pense que c'est un minimum, car c'est dans cette tâche que je vais devoir détailler exactement comment fonctionne chaque partie du projet. Ces cinq jours sont éparpillés sur le projet en général à la fin du développement de chaque grande partie de projet. Le but est de ne rien oublier et de ne pas avoir à tout faire en même temps. @@ -316,7 +316,7 @@ Cette tâche est déjà moins grosse, elle consiste à documenter le fonctionnem Je l'ai mis en fin de projet, car comme j'ai l'habitude de faire des analyses fonctionnelles plutôt précises, le moindre changement dans l'UI peut tout rendre obsolète. -J'y ai mis deux jours, car j'aimerais correctement documenter avec de bonnes photos et scénarios pour qu'on puisse voir toutes les possibilités de l'application. +J'y ai mis deux jours, puisque j'aimerais correctement documenter avec de bonnes photos et scénarios pour qu'on puisse voir toutes les possibilités de l'application. ##### DT5 Documentation Tests (1) @@ -332,15 +332,15 @@ Rubrique programmation qui contient toutes les tâches qui touchent à la progra ##### PT1 Programmation récupération des images (3) -Cette tâche est estimée à seulement trois jours, il ne faut pas s'y méprendre, c'est une des tâches les plus dures et lourdes niveaux documentation en explications. Cependant, un POC (Proof Of Concept) assez avancé a déjà été fait et donc cela permet de n'envisager que trois jours, car il suffit de l'implémenter et de la paufinner. +Cette tâche est estimée à seulement trois jours, il ne faut pas s'y méprendre, c'est une des tâches les plus dures et lourdes au niveau de la documentation et en explications. Cependant, un POC (Proof Of Concept) assez avancé a déjà été fait et donc cela permet de n'envisager que trois jours, car il suffit de l'implémenter et de la peaufiner. Cette tâche consiste à prendre en entrée un lien de Grand Prix et de sortir une image tous les x secondes de la page DATA. Cela peut sembler simple, mais pour le faire sans prendre d'espace d'écran et ne demandant pas à l'utilisateur de copier-coller quoi que ce soit où de donner ses identifiants F1TV c'est un challenge. -Cela peut paraitre curieux alors de mettre cette tâche loin dans le planning même si c'est la première étape du projet. Encore une fois cela s'explique avec le fait qu'il y a déjà un POC qui fonctionne à peu près et que donc préfère commencer avec des tâches plus incertaines dans le cas où elles prendraient plus de temps que prévu. +Cela peut paraitre curieux alors de mettre cette tâche loin dans le planning même si c'est la première étape du projet. Encore une fois, cela s'explique avec le fait qu'il y a déjà un POC qui fonctionne à peu près et que donc préfère commencer avec des tâches plus incertaines dans le cas où elles prendraient plus de temps que prévu. ##### PT2 Programmation OCR (5) -Cette tâche consiste à développer la partie qui reconnait le texte sur les images. C'est très certainement la tâche qui risque le plus de déborder car c'est celle qui est la plus complexe techniquement puisqu'elle demande non seulement la lecture sur image, mais aussi le développement d'algorithmes de traitement de cette donnée pour être sûr qu'elle a bien été lue. +Cette tâche consiste à développer la partie qui reconnait le texte sur les images. C'est très certainement la tâche qui risque le plus de déborder, car c'est celle qui est la plus complexe techniquement puisqu'elle demande non seulement la lecture sur image, mais aussi le développement d'algorithmes de traitement de cette donnée pour être sûr qu'elle a bien été lue. J'y ai ainsi alloué cinq jours, mais j'espère que j'arriverai à gagner du temps sur les autres pour y allouer plus dans le planning effectif, car je suis convaincu que plus, on y passe du temps, meilleur sera le résultat. @@ -358,7 +358,7 @@ Pour ces raisons, je lui ai assigné également cinq jours de travail et elle do ##### PT5 Programmation mise en commun (3) -Cette tâche est aussi un petit peu spéciale, car elle regroupe plusieurs choses. En gros, chaque partie de programmation sera sûrement assez indépendante et il faudra à un moment faire un seul projet C# qui contient tout. +Cette tâche est aussi un petit peu spéciale, car elle regroupe plusieurs choses. En gros, chaque partie de programmation sera assurément assez indépendante et il faudra à un moment faire un seul projet C# qui contient tout. Il est difficile d'estimer à quel point cela va être compliqué alors, j'ai été conservateur et j'ai mis trois jours. @@ -388,25 +388,25 @@ Alors ! Ces lignes sont écrites dans les derniers jours du travail de diplôme et j'ai des choses à dire. -Premièrement je suis plutôt content de mon estimation du travail. Je trouve que j'ai bien estimé la quantité de travail et combien de temps les différentes tâches allaient prendre. La plupart des dépassements sont des imprévus et/ou des allers et retours entre d'autres tâches. +Premièrement, je suis plutôt content de mon estimation du travail. Je trouve que j'ai bien estimé la quantité de travail et combien de temps les différentes tâches allaient prendre. La plupart des dépassements sont des imprévus et/ou des allers et des retours entre d'autres tâches. -La raison pour laquelle je suis plutôt content de ma planification, c'est que malgré l'usine à Gaz que représente ce projet et le nombre de soucis que j'ai eu, j'ai quand même pu arriver à un projet qui fonctionne en suivant plutôt fidèlement le planning. Une chose dont je suis plutôt fier c'est la documentation. En ayant développé le squelette de l'app dès le début du projet ca m'a permis d'avancer au fur et à mesure du projet la conscience tranquille. +La raison pour laquelle je suis plutôt content de ma planification, c'est que malgré l'usine à Gaz que représente ce projet et le nombre de soucis que j'ai eu, j'ai quand même pu arriver à un projet qui fonctionne en suivant essentiellement fidèlement le planning. Une chose dont je suis assez fier, c'est la documentation. En ayant développé le squelette de l'app dès le début du projet, ça m'a permis d'avancer au fur et à mesure du projet la conscience tranquille. -Bon c'est bien joli les fleurs mais clairement c'est loin d'être parfait. Au moment de la planification je n'avais pas prévu de faire des allers et retours entre plusieurs tâches. Dans le planning effectif on peut voir que un jour je suis sur la PT3 (Stockage) et la PT5 (regroupement des mini projets en un seul gros). J'aurais peut-être du inverser l'ordre. +Bon, c'est bien joli les fleurs, mais clairement, c'est loin d'être parfait. Au moment de la planification, je n'avais pas prévu de faire des allers et des retours entre plusieurs tâches. Dans le planning effectif, on peut voir qu'un jour, je suis sur la PT3 (Stockage) et la PT5 (regroupement des mini projets en un seul gros). J'aurais peut-être dû inverser l'ordre. Mais il y a deux gros soucis dans mon planning : -- L'ordre des tâches n'était pas bon (mais il a été décidé comme ca pour que les plus grosse difficultées soient faites en premier) ce qui a créé pas mal de soucis. Ex : L'émulateur de la F1TV a été fait très tard et au final les images récupèrées n'étaient pas de la même qualité que ce que j'avais prévu en développant l'OCR en premier. -- Les Tests ont été négligés et utilisés comme des jours tampons. Ca c'est la plus grosse erreur de planning. Autant les autres sont pénibles etc... mais n'ont pas forcément compromis la bonne réalisation du projet alors que la les tests ont été mal placés et ont au final été balayés alors que si ils avaient été mieux planifiés ca ne serait pas arrivé. +- L'ordre des tâches n'était pas bon (mais il a été décidé comme ça pour que les plus grosses difficultés soient faites en premier) ce qui a créé pas mal de soucis. Ex : L'émulateur de la F1TV a été fait très tard et finalement les images récupérées n'étaient pas de la même qualité que ce que j'avais prévu en développant l'OCR en premier. +- Les Tests ont été négligés et utilisés comme des jours tampons. Ça, c'est la plus grosse erreur de planning. Autant les autres sont pénibles, etc. mais n'ont pas forcément compromis la bonne réalisation du projet alors que les tests ont été mal placés et ont finalement été balayés tandis que s'ils avaient été mieux planifiés ça ne serait pas arrivé. Solutions : -L'ordre des tâches a été décidé exprès de cette facon pour éviter de prendre trop de risques. L'idée était qu'en faisant le plus dur au début, je pourrai facilement changer le cahier des charges. J'ai envie de dire que j'aurais dû être plus confiant mais pour être honnête je pense que c'était un mal pour un bien. Je ne pense pas avoir "bien" fait mais je pense que c'est une erreur qui était rentable pour mon niveau de stress dans le projet. +L'ordre des tâches a été décidé exprès de cette façon pour éviter de prendre trop de risques. L'idée était qu'en faisant le plus dur au début, je pourrai facilement changer le cahier des charges. J'ai envie de dire que j'aurais dû être plus confiant, mais pour être honnête, je pense que c'était un mal pour un bien. Je ne pense pas avoir "bien" fait, mais je pense que c'est une erreur qui était rentable pour mon niveau de stress dans le projet. -Par contre les Tests c'est tout simplement une erreur. J'en parle plus en détail dans la partie test de la documentation mais je vais résumer un peu ici. -La documentation a été faite dès le début du projet. J'ai mis en place le squelette pour qu'ensuite il soit simple d'y ajouter au fur et à mesure. J'aurais dur faire exactement pareil avec les tests. Si j'avais fait au moins le squelette des tests au début du projet j'aurais pu beaucoup plus facilement en faire et cela m'aurait fait gagner un temps fou et j'aurais même pu faire du TDD (Test Driven Developpement). Je suis persuadé que cette bête erreur de planification m'a côuté très chère car ne pas avoir une bonne stratégie de tests a du me faire perdre un temps fou. +Par contre, les Tests c'est tout simplement une erreur. J'en parle plus en détail dans la partie test de la documentation, mais je vais résumer un peu ici. +La documentation a été faite dès le début du projet. J'ai mis en place le squelette pour qu'ensuite, il soit simple d'y ajouter au fur et à mesure. J'aurais dû faire exactement pareil avec les tests. Si j'avais fait au moins le squelette des tests au début du projet, j'aurais pu beaucoup plus facilement en faire et cela m'aurait fait gagner un temps fou et j'aurais même pu faire du TDD (Test Driven Developpement). Je suis persuadé que cette bête erreur de planification m'a coûté très cher, car ne pas avoir une bonne stratégie de tests a dû me faire perdre un temps fou. -Pour conclure je suis content car j'ai réussi à rendre un projet qui marche en suivant assez bien le planning mais il y a des choses que je vais devoir changer dans mes prochains projets. +Pour conclure, je suis content parce que j'ai réussi à rendre un projet qui marche en suivant assez bien le planning, mais il y a des choses que je vais devoir changer dans mes prochains projets. ## Analyse fonctionnelle @@ -424,37 +424,37 @@ Voir "Manuel Utilisateur" tout y est indiqué !["Logo de Visual Studio 2022"](./Images/Screens/Vs2022logo.png) -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#. +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#. -C'est l'outil que j'utilise depuis maintenant 6 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. +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. -Pas grand chose à dire à ce sujet à part que c'est un outil qui marche bien et qui est gratuit si on prend la community edition. +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. #### Visual Studio Code !["Logo de Visual Studio Code"](./Images/Screens/vsCodelogo.png) -Cet outil est déja 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. +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. 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. -Les possibilités de customisation sont presques infinies et c'est un plaisir d'utiliser ce logiciel gratuit fournis par Microsoft mais qui est amélioré constamment par des développeurs indépendants. +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. -Je conseille à nimporte quel développeur de l'essayer à moins qu'il soit uniquement sur C# ou il serait plus intéressant d'utiliser visual studio 2022 +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. #### Material/Mkdocs/Markdown !["Logo de Mkdocs Materials"](./Images/Screens/MaterialsLogo.png) -Pendant ce projet j'ai utilisé exclusivement du markdown avec l'aide de Mkdocs et Materials. +Pendant ce projet, j'ai utilisé exclusivement du Markdown avec l'aide de Mkdocs et Materials. -Le choix de Markdown a été plutôt simple, c'est une facon facile et efficace de créer de la documentation et on n'avait pas le choix de l'utiliser. +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. -On avait également l'obligation (Ou au moins un très forte incitation) par nos professeurs d'utiliser mkdocs et materials pour que notre documentation ne soit pas simplement une liste de fichiers mais un joli site dans lequel il est agréable de chercher des informations. +On avait également l'obligation (Ou au moins un très forte incitation) par nos professeurs d'utiliser mkdocs et materials pour que notre documentation ne soit pas simplement une liste de fichiers, mais un joli site dans lequel il est agréable de chercher des informations. -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é. +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é. -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 facile à lire (Oui oui ca aurait pu être pire, je sais c'est dur à imaginer) +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). #### Figma @@ -464,182 +464,179 @@ Figma est l'outil que j'ai utilisé pour créer mon poster et un certain nombre 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. -C'est un outil en ligne parfaitement gratuit qui conserve tout dans le cloud. Franchement je n'ai rien à dire, je n'ai pas utilisé plus de 15% des features que cet outil propose et je suis déja conquis. +C'est un outil en ligne parfaitement gratuit qui conserve tout dans le cloud. Franchement, je n'ai rien à dire, je n'ai pas utilisé plus de 15 % des features que cet outil propose et je suis déjà conquis. ### Technologies utilisées -Dans ce projet différents choix ont été faits pour ce qui est des technologies. +Dans ce projet, différents choix ont été faits pour ce qui est des technologies. -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. +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. #### Selenium -!["Logo de selenium"](./Images/Photos/Selenium_Logo.png) +!["Logo de sélénium"](./Images/Photos/Selenium_Logo.png) -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 est 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 supers test unitaires. +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. -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 facilemnt utiliser Selenium pour scraper tous les sites qui nous passent par la tête. +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. Le cahier des charges que j'avais en tête en cherchant une technologie de contrôle de navigateur internet était le suivant : - Simple - Permettant de contrôler un navigateur Headless (Voir chapitre "Simuler un navigateur ?") -- Permettant de contrôler firefox +- Permettant de contrôler Firefox - Ayant un wrapper C# -- Permettre de changer certaines choses comme les cookies en Live +- Permettre de changer certaines choses comme les cookies en direct - Permettre d'interagir avec les éléments d'une page - Fonctionner -Simple car je ne voulais pas avoir à passer trop de temps dessus (ca n'a pas bien vieillit lol...). Je voulais que l'on puisse utiliser Firefox car il n'implémente pas les mêmes sécuritées que Chrome pour faire simple. J'avais besoin que la lib puisse contrôler un Firefox HEADLESS car je ne voulais pas avoir une page web ouvert sur mon ordi quand je commente car c'est de l'espace utilisé pour rien. J'avais besoin d'un wrapper C# car c'est le language que j'utilise. Pour finir j'avais besoin d'interragir 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 detecter les bots. +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. -Avec un cahier des charges parreil 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 restreind quand on veut pouvoir contrôler Chrome OU Firefox. +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. -A la base mon choix c'était porté sur Puppeteer Sharp qui est une librairie qui se veut être exactement ce que je veux. +À la base, mon choix, c'était porté sur Puppeteer Sharp qui est une librairie qui se veut être exactement ce que je veux. !["Logo de Pupeteer"](./Images/Photos/Pupetteer_Logo.png) -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 innapercu par les systèmes de detection de bots. +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. -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 que avec le wrapper C# j'ai eu un certain nombre de problèmes: +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 : -- Toutes les versions de la librairie ne fonctionnaient pas. Il fallait faire des tests avec différentes versions de la librairie et de ses dépendences simplement pour faire démarrer un browser. Et ca c'est quand ca marchait car il y avait des jours ou des machines ou je n'ai simplement pas pu faire fonctionner la librairie. -- Même avec les techniques proposées par les plugins "Stealth" je n'arrivais pas à bypass les sécuritées de la page de login de la F1TV. J'ai essayé tout ce que j'ai pu trouver sur internet mais on se fait toujours chopper dès que l'on arrive sur la page. -- Et le pire de tout, impossible de faire fonctionner un vidéo. J'ai pu faire tout ce que je voulais faire au final en passant par l'utillisation de cookies pour la connexion. Tout ca pour arriver au moment ou il faut lancer la vidéo, et la, crash. Impossible de faire fonctionner Puppeteer Sharp avec une vidéo. Dès qu'elle se lance c'est un crash assuré sans message d'erreur clair. Et le soucis c'est que le wrapper C# n'est pas vraiment bien supporté et que si c'est un bug de la lib je ne risque pas de voir de fix avant un moment si ce n'est jamais. +- Toutes les versions de la librairie ne fonctionnaient pas. Il fallait faire des tests avec différentes versions de la librairie et de ses dépendances simplement pour faire lancer un browser. Et ça, c'est quand ça marchait, car il y avait des jours où des machines sur lesquelles je n'ai juste pas pu faire fonctionner la librairie. +- Même avec les techniques proposées par les plugins "Stealth" je n'arrivais pas à bypass les sécurités de la page de login de la F1TV. J'ai essayé tout ce que j'ai pu trouver sur internet, mais on se fait toujours chopper dès que l'on arrive sur la page. +- Et le pire de tous, impossible de faire fonctionner une vidéo. J'ai pu faire tout ce que je voulais faire finalement en passant par l'utillisation de cookies pour la connexion. Tout ça pour arriver au moment où il faut lancer la vidéo, et là, crash. Impossible de faire fonctionner Puppeteer Sharp avec une vidéo. Dès qu'elle se lance, c'est un crash assuré sans message d'erreur clair. Et le souci, c'est que le wrapper C# n'est pas vraiment bien supporté et que si c'est un bug de la lib, je ne risque pas de voir de fix avant un moment si ce n'est jamais. -Pour toutes ces raisons, j'ai du abandonner cette librairie ce qui a été très dur car j'avais passé beaucoup de temps dessus à essayer de la faire marcher. +Pour toutes ces raisons, j'ai dû abandonner cette librairie, ce qui a été très dur, car j'avais passé beaucoup de temps dessus à essayer de la faire marcher. -Ensuite le choix de Selenium était plutôt simple, c'était la seule option restante. A ce jour je ne connait aucune autre librairie que Puppeteer ou Selenium qui puisse contrôler un Firefox Headless en respectant mon cahier des charges et qui soit donc disponible depuis C#. +Ensuite le choix de Selenium était plutôt simple, c'était la seule option restante. À ce jour, je ne connais aucune autre librairie que Puppeteer ou Selenium qui puisse contrôler un Firefox Headless en respectant mon cahier des charges et qui soit donc disponible depuis C#. -Si je n'arrivais pas à faire fonctionner Selenium j'aurai du abandonner l'idée de simuler un navigateur tout simplement. Mais j'ai eu la chance que cette librairie fasse tout ce que je pouvais demander. C'est une super lib et même si la version C# n'est vraiment pas bien documentée, la plupart des documentations de la version JS sont pertinentes pour al version C# même si ca n'est pas la même syntaxe. +Si je n'arrivais pas à faire fonctionner Selenium, j'aurais dû abandonner l'idée de simuler un navigateur tout simplement. Mais j'ai eu la chance que cette librairie fasse tout ce que je pouvais demander. C'est une super lib et même si la version C# n'est vraiment pas bien documentée, la plupart des documentations de la version JS sont pertinentes pour la version C# même si ça n'est pas la même syntaxe. -Pour résumer, j'ai choisis Puppeteer car c'était la seule option viable pour mon besoin. +Pour résumer, j'ai choisi Puppeteer car c'était la seule option viable pour mon besoin. -(Note : Par contre si je trouve la personne chez mozilla ou puppeteer qui a décidé d'hardcoder 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 TRES MAL SE PASSER) +(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) #### CSharp !["Logo C#"](./Images/Photos/Csharp_Logo.png) -Je pense que c'est le choix le plus simple à expliquer. C# est un language de programmation orienté objet relativement haut niveau qui a été créé par Microsoft et qui a comme cible le developpement d'applications pour Windows. (On peut evidemment trouver des adaptations pour le faire tourner sur Linux mais ce n'est pas vraiment le but du language) +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) -En plus d'être un superbe language de programmation, c'est le language que l'on apprend au CFPT informatique. C'est donc un language avec lequel je suis beaucoup plus à l'aise que pour d'autres languages comme le Python ou le JS. +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. -Mon but n'était pas de faire une application Web et je travaille sous Windows. Je savais que mon projet allait demander un minimum de programmation orientée objet. J'ai donc immédiattement pensé à utliser C#. +Mon but n'était pas de faire une application Web et je travaille sous Windows. Je savais que mon projet allait demander un minimum de programmation orientée objet. J'ai ainsi immédiatement pensé à utiliser C#. -Cependant j'aurais très bien pu utiliser un language comme python qui m'aurait clairement facilité la tâche avec des librairies bien plus fournies et plus souvent mises à jour. Mais comme je ne suis pas du tout aussi à l'aise avec je pense que le C# était la meilleure option. +Cependant, j'aurais très bien pu utiliser un langage comme python qui m'aurait clairement facilité la tâche avec des librairies bien plus fournies et plus souvent mises à jour. Mais comme je ne suis pas du tout aussi à l'aise avec, je pense que le C# était la meilleure option. +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. -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 rendres 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. - -#### Python? +#### Python ? !["Logo Python"](./Images/Photos/Python_Logo.png) -Alors ce choix la est plus commpliqué à comprendre. +Alors ce choix-là est plus compliqué à comprendre. -Pour tout le projet j'ai tenté de garder le C# comme language et de ne pas utiliser autre chose. Cependant j'ai du utiliser une seule fois le Python dans un cas très précis. +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. -Je n'aime vraiment pas coder en python de base et clairement j'aurais préfèré ne pas l'utiliser mais je n'avais pas le choix. +Je n'aime vraiment pas coder en python de base et clairement, j'aurais préféré ne pas l'utiliser, mais je n'avais pas le choix. Le besoin dans le cas du python était le suivant : -J'avais besoin d'un moyen de récupèrer des strings et les décoder avec une clé encodée avec le système propriétaire de windows d'encodage. +J'avais besoin d'un moyen de récupérer des strings et les décoder avec une clé encodée avec le système propriétaire de Windows d'encodage. -Le soucis que j'avais avec le C# c'est que les methodes de decryption ne fonctionnent pas pareil que en python et tous les exemples que je pouvais trouver étaient en python. J'ai essayé pendant un sacré moment de faire fonctionner la decryption en C# mais sans succès. +Le souci, c'est que j'avais avec le C# c'est que les méthodes de décryptions ne fonctionnent pas pareil qu'en python et tous les exemples que je pouvais trouver étaient en python. J'ai essayé pendant un sacré moment de faire fonctionner la décryptions en C# mais sans succès. -J'ai donc directement utilisé le python comme faisait toutes les personnes que je pouvais voir sur internet et je pense que ca n'est pas une mauvaise idée. En effet, cela veut dire que si à un moment Chrome est mis à jour, je n'aurai pas besoin d'aller ouvrir tout le code source de mon projet pour tout recompiler, j'aurai simplement besoin de changer ce script. +J'ai donc directement utilisé le python comme faisait toutes les personnes que je pouvais voir sur internet et je pense que ça n'est pas une mauvaise idée. En effet, cela veut dire que si à un moment Chrome est mis à jour, je n'aurai pas besoin d'aller ouvrir tout le code source de mon projet pour tout recompiler, j'aurai simplement besoin de changer ce script. -Un des avantages du Python est quand même qu'il y beaucoup plus de gens qui codent dessus, et pour ce genre d'utilisation très spécifiques c'est plutôt pratique. +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. -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) +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). #### Firefox !["Logo Firefox Headless"](./Images/Photos/Firefox_logo_dev.png) -J'en parle deja plus bas, mais le choix de navigateur est super important. +J'en parle déjà plus bas, mais le choix de navigateur est super important. -Deja tous les navigateurs n'ont pas un mode Headless(sans tête, mieux expliqué dans la rubrique "Simuler un naviguateur ?"). 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. +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. -Autre soucis, les librairies d'automatisation ne supportent pas tous les navigateurs. Par exemple, beaucoup supportent chrome mais très peu supportent Firefox ou Edge. +Autre souci, les librairies d'automatisation ne supportent pas tous les navigateurs. Par exemple, beaucoup supportent chrome, mais très peu supportent Firefox ou Edge. +Donc, il me fallait un navigateur qui puisse opérer en Headless et qui soit supporté par plusieurs librairies d'automatisation. -Donc il me fallait un navigateur qui puisse opèrer en Headless et qui soit supporté par plusieurs librairies d'automatisation. +Il n'y a que Firefox et Chrome qui soient conformes à ces exigences. (Je n'ai pas vérifié pour TOUS les navigateurs. Peut-être que les Opera GX ont aussi un mode headless super, mais je me suis concentré sur les navigateurs plus grand public). -Il n'y a que Firefox et Chrome qui sont conforme à ces exigeances (Je n'ai pas verifié pour TOUS les navigateurs. Peut-être que les Opera GX ont aussi un mode headless super, mais je me suis concentré sur les navigateurs plus grand public). - -Chrome est supporté par plus de lib, mais le soucis c'est que la F1TV utilise un lecteur de vidéo avec DRM (Plus d'infos la dessus dans la partie "Simuler un navigateur?") et donc le choix était simple. Il ne restait que Firefox. +Chrome est supporté par plus de lib, mais le souci c'est que la F1TV utilise un lecteur de vidéo avec DRM (Plus d'infos là-dessus dans la partie "Simuler un navigateur ?") et donc le choix était simple. Il ne restait que Firefox. #### Tesseract Je pense que le choix le plus simple après le C# fut l'utilisation de Tesseract. -C'est tout simplement l'outil le plus utilisé pour faire de l'OCR. A la base c'est une lib Python (Ah tiens encore ?) qui peut être redoutablement efficace avec le bon dataset. +C'est tout simplement l'outil le plus utilisé pour faire de l'OCR. À la base, c'est une lib Python (Ah tiens encore ?) qui peut être redoutablement efficace avec le bon dataset. -Il existe d'autres outils mais j'ai décidé de prendre celui la à cause de son support juste incroyable et de son omniprésence dans la documentation OCR. +Il existe d'autres outils, mais j'ai décidé de prendre celui-là à cause de son support juste incroyable et de son omniprésence dans la documentation OCR. En plus il est facile à utiliser et je ne pense pas encore avoir fait le tour de tout son potentiel dans ce projet. ### Fonctionnement général -Avant de passer à l'explication de chaques parties du projet en détail, je pense qu'il est important de faire un petit point sur comment toutes les parties du projet s'emboitent et fonctionnement ensemble. Comme ca quand vous lirez l'explication d'une étape vous serez conscient de à quoi elle sert et ou elle s'înscrit dans le projet principal. +Avant de passer à l'explication de chaque partie du projet en détail, je pense qu'il est important de faire un petit point sur comment toutes les parties du projet s'emboitent et fonctionnement ensemble. Comme ça, quand vous lirez l'explication d'une étape, vous serez conscient de à quoi elle sert, et où elle s'inscrit dans le projet principal. #### Les briques principales -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. +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. -##### Recupération d'images +##### Récupération d'images -!["Diagramme simplifié représentant le processus de récupèration des images"](./Images/Figma/DiagrammeRecupImages.png) +!["Diagramme simplifié représentant le processus de récupération des images"](./Images/Figma/DiagrammeRecupImages.png) -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. +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. -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 que 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#. +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#. -Ces deux partie sont liées car pour se connecter à la F1TV Selenium a besoin des cookies de connexion récupèrés par le programme Python. +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. 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. ##### OCR -!["Diagramme simplifié représentant le processur d'OCR"](./Images/Figma/DiagrammeOCR.png); +!["Diagramme simplifié représentant le processus d'OCR"](./Images/Figma/DiagrammeOCR.png); -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 continennent 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# +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# -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) +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) ##### Traitement et affichage !["Diagramme simplifié représentant le processus de traitement et d'affichage"](./Images/Figma/DiagrammeTraitement.png) -On peut voir dans ce dernier mini diagramme simplifié que on prend les données que l'on récupèré 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 nescessaires pour des affichages (Ces affichages sont directements récupèrés depuis le projet en cours de fonctionnement) +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). #### Résumé du fonctionnement général -!["Diagramme simplifé représentant le processus général du projet"](./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png) +!["Diagramme simplifié représentant le processus global du projet"](./Images/Figma/DiagrammeG%C3%A9n%C3%A9ral.png) 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érentes des 3 autre diagramme car le but ici est surtout de montrer le chemin que fait la donnée à travers les couches +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. Toutes les parties du projet ne sont pas incluses, notamment la partie calibration dans un objectif de simplifier la lecture. -Dans l'ordre, on peut voir que pour la partie récupèration d'images, le python va récupèrer les cookies dans la base de données chrome pour ensuite les retourner à Selenium. +Dans l'ordre, on peut voir que pour la partie récupération d'images, le python va récupérer les cookies dans la base de données chrome pour ensuite les retourner à Selenium. -Selenium va ensuite pouvoir lancer un navigateur (en l'occurence Firefox) et utiliser les cookies récupèrés pour aller sur la page de la F1TV qui va retourner un certain nombre d'infos à Selenium. +Selenium va ensuite pouvoir lancer un navigateur (en l'occurrence Firefox) et utiliser les cookies récupérés pour aller sur la page de la F1TV qui va retourner un certain nombre d'infos à Selenium. -L'info qui nous intéresse le plus depuis Selenium c'est les images de la page data de la F1Tv et c'est elles que l'on va envoyer dans la partie LOAD du diagramme. +L'info qui nous intéresse le plus depuis Selenium ce sont les images de la page data de la F1Tv et ce sont elles que l'on va envoyer dans la partie LOAD du diagramme. -Dans cette partie on prend l'image de la F1TV et on la decoupe selon les directives données par le fichier Config.JSON (il renseigne les zones à découper et ce qu'elles représentent) et après le découpage on se retrouve avec une zone principale, vingt zones de pilotes et 9 fenêtres de données par zone de pilote donc 180 fenêtres en tout. +Dans cette partie, on prend l'image de la F1TV et on la découpe selon les directives données par le fichier Config.JSON (il renseigne les zones à découper et ce qu'elles représentent) et après le découpage, on se retrouve avec une zone principale, vingt zones de pilotes et 9 fenêtres de données par zone de pilote donc 180 fenêtres en tout. Ces fenêtres sont ensuite envoyées pour être filtrées (retirer le flou, mettre en évidence les caractères, en gros les préparer pour la reconnaissance) dans la partie OCR -Dans cette partie, après avoir filtré les images, on les envoie à Tesseract pour qu'il nous retourne des résultats d'OCR. Ces résultats sont ce que Tesseract a trouvé sur les image et ils sont retournés sous al forme de Data Pilote. Ex (Position: 1,Tour : 45, Temps au tour : 1:34.683, Pneus: Medium etc....) +Dans cette partie, après avoir filtré les images, on les envoie à Tesseract pour qu'il nous retourne des résultats d'OCR. Ces résultats sont ce que Tesseract a trouvé sur les images et ils sont retournés sous la forme de Data Pilote. Ex (Position : 1,Tour : 45, Temps au tour : 1:34.683, Pneus : Medium etc....) -Finalement ces données ont envoyées dans la partie traitement qui va faire des vérifications d'usage pour s'assurer qu'elles sont correctes et quand c'est fait, tout est envoyé dans une base de données SQLITE. +Finalement, ces données ont envoyées dans la partie traitement qui va faire des vérifications d'usage pour s'assurer qu'elles sont correctes et quand c'est fait, tout est envoyé dans une base de données SQLite. -On ne montre pas non plus dans ce diagramme la parte affichage des données car je ne trouve pas pertinent de l'inclure ici. +On ne montre pas non plus dans ce diagramme la parte affichage des données, car je ne trouve pas pertinent de l'inclure ici. -Et voila c'est le fonctionnement très général et simplifié de l'application. Je vous invite à continuer à lire cette documentation pour des informations plus précises à propos de toutes ces étapes. Bonne lecture ! +Et voilà, c'est le fonctionnement très général et simplifié de l'application. Je vous invite à continuer à lire cette documentation pour des informations plus précises à propos de toutes ces étapes. Bonne lecture ! ### Récupération des images @@ -647,77 +644,77 @@ Voici la première grande étape du projet. 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. -On peut voir ce nom apparaître assez souvent quand on regarde un Grand Prix car comme ils ont la main-mise 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) +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) !["Exemple insertion AWS en GP"](./Images/Screens/AWSExample1.jpg) -Ce service s'appelle F1 Insights (Oui c'est un meilleur nom de projet que F1 Companion mais bon) et c'est, je pense, la raison pour laquelle on ne voit aucune API publique qui permette de correctement se renseigner en donées en direct pendant un Grand Prix. Ils ont du 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 +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. !["Exemple data d'AWS"](./Images/Screens/AWSExample2.jpg) -Evidemment 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. +É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. -Il existe bien quelques API un peu bancales publiques, mais le problème c'est qu'elles ne sont vraiment pas suffisante et je ne peux pas leur faire confiance quand je commente. Ce qu'il m'aurait fallut c'est une API publique et officielle qui me permette d'être sur que les données sont les bonnes et qu'elles arrivent le plus vite possible. +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. -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". +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". 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. !["Exemple de Data Channel"](./Images/Screens/ScreenF1TvData.png) 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. -Je pense donc que c'est justement pour éviter que des petits malins puissent simplement venir scraper l'intégralité des données qu'ils proposent et fasse sa propre API. (C'est d'ailleurs un des sites avec la meilleure protection anti bot du monde) +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. +Je pense donc que c'est justement pour éviter que des petits malins puissent juste venir scraper l'intégralité des données qu'ils proposent et fasse sa propre API. (C'est d'ailleurs un des sites avec la meilleure protection anti-bot du monde) -MAIS ce n'est pas par ce que les données ne sont pas facile à avoir qu'elles sont IMPOSSIBLE à avoir. Et c'est la que ce projet entre en jeu. Mais pour décoder les données d'une image il faut dabord ... (roulement de tambours) ... Avoir des images ! +MAIS ce n'est pas par ce que les données ne sont pas faciles à avoir qu'elles sont IMPOSSIBLE à avoir. Et c'est là que ce projet entre en jeu. Mais pour décoder les données d'une image, il faut d'abord ... (roulement de tambours) ... Avoir des images ! -Et c'est la que vient se glisser cette partie du projet. +Et c'est là que vient se glisser cette partie du projet. #### Comment faire ? -Le but de ce segment est de se concentrer sur la récupèration et la mise à disposition pour le reste du programme, des images en direct de la F1TV dans la meilleure qualité possible et dans les meilleurs délais. +Le but de ce segment est de se concentrer sur la récupération et la mise à disposition, pour le reste du programme, des images en direct de la F1TV dans la meilleure qualité possible et dans les meilleurs délais. -Pour ce faire il y a plusieurs solutions : +Pour ce faire, il y a plusieurs solutions : -- Reverse engeneer la F1TV pour accèder directement au flux sans passer par la plateforme internet et pouvoir prendres images à volonté. -- Avoir tout simplement une page de la F1TV ouverte sur un écran et prendres des screenshots à intervals réguliers. +- Reverse engeneer la F1TV pour accéder directement au flux sans passer par la plateforme internet et pouvoir prendre images à volonté. +- Avoir tout simplement une page de la F1TV ouverte sur un écran et prendre des screenshots à intervalles réguliers. - Simuler un navigateur internet sans qu'il soit affiché et le contrôler automatiquement pour qu'il prenne des captures. -La première option aurait été la plus élégante mais lors d'un POC que je tentais de réaliser je me suis rendu compte que cela serait un peu trop compliqué et long à faire. Sans compter le fait que les rediffusions de Grand Prix ne sont pas gèrées de la même manière que les diffusions en live. Et que pour faire des Tests en live il faudrait attendre à chaque fois un weekend de Grand Prix et le faire en plus du commentaire que je dois produire. +La première option aurait été la plus élégante, mais lors d'un POC que je tentais de réaliser, je me suis rendu compte que cela serait un peu trop compliqué et long à faire. Sans compter le fait que les rediffusions de Grand Prix ne sont pas gérées de la même manière que les diffusions en direct. Et que pour faire des Tests en direct, il faudrait attendre à chaque fois un weekend de Grand Prix et le faire en plus du commentaire que je dois produire. -Pour toutes ces raisons et bien d'autres je l'ai rangée dans la case "Trop dur, Trop chiant, Sûrement illégal" (Oui je sais c'est une catégorie bien spécifique mais c'est ma documentation je fais ce que je veux) +Pour toutes ces raisons et bien d'autres, je l'ai rangée dans la case "Trop dur, Trop chiant, Sûrement illégal" (Oui, je sais, c'est une catégorie bien spécifique, mais c'est ma documentation, je fais ce que je veux). La troisième option aurait été la plus simple (et moins drôle) et je suis presque sûr que je peux implémenter cette dernière en moins d'une après-midi. Sauf qu'elle apporte de gros soucis. -1. On ne peux pas garantir l'intégrité et la continuité des données si l'utilisateur avance ou fait pause même par simple inadvertance. +1. On ne peut pas garantir l'intégrité et la continuité des données si l'utilisateur avance ou fait pause, même par simple inadvertance. 2. La moindre fenêtre qui s'afficherait devant ruinerait toute la reconnaissance de caractères. 3. On ne peut pas contrôler la qualité du flux et on est obligé de faire confiance en l'utilisateur 4. On ne peut pas vraiment automatiser quoi que ce soit niveau tests ou même pour faire du scrapping auto pour remplir une base de donnée. -5. Et finalement le pire inconvénient : C'EST NUL ! Je ne pourrais jamais utiliser un projet qui fonctionne de cette facon, je ne peux pas me permettre d'avoir un écran inutilisable quand je commente et auquel je dois constamment faire attention pour ne pas perturber la reconnaissance. Pour moi cette option aurait été celle à choisir en cas d'extrême urgence et en dernier recours car le projet deviendrait inutile. +5. Et finalement le pire inconvénient : C'EST NUL ! Je ne pourrais jamais utiliser un projet qui fonctionne de cette façon, je ne peux pas me permettre d'avoir un écran inutilisable quand je commente et auquel je dois constamment faire attention pour ne pas perturber la reconnaissance. Pour moi, cette option aurait été celle à choisir en cas d'extrême urgence et en dernier recours, car le projet deviendrait inutile. J'ai donc décidé de m'occuper de la seconde option : Simuler un navigateur. -Cette option bien que complexe et difficile à implémenter propose une solution à tous les problême et permet une récupèration quasi sans compromis. +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. #### Simuler un navigateur ? -!["Navigateur Headless(sans tête)"](./Images/Screens/headless-firefox.jpg) +!["Navigateur Headless (sans tête)"](./Images/Screens/headless-firefox.jpg) 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). !["Chromium logo"](./Images/Screens/ChromiumLogo.png) -Cependant. La F1TV n'utilise pas simplement un player HTML5 basique. Elle utilise un service de streaming BitMovin qui permet de fournir un stream de bonne qualité et surtout qui implémente les DRM (Digital Right Management) +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). -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 version 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 facon et il est donc assez facile de passer outre. +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. L'explication sans trop rentrer dans les détails est la suivante : -Dans chrome, le player par défaut utilise une technologie appellé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. +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. -Cependant Firefox de pas sa nature Open Source utilise "OpenH264" pour lire ces mêmes flux soumis à des DRM et OpenH264 n'implémente pas les mêmes restrictions. +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. -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) +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) !["Firefox dev logo"](./Images/Screens/FirefoxLogo.png) @@ -729,14 +726,14 @@ Maintenant que l'on sait quel navigateur simuler et avec quelle technologie, on Ce qu'il y a de bien avec Selenium, c'est qu'on a un certain nombre de commandes très haut niveau qui nous permettent de contrôler un navigateur de manière plutôt précise. -Je vais décrire ici la procédure habituelle utilisée sous une forme de recette de cuisine pour que l'on puisse facilement comprendre ce qu'il se passe. +Je vais décrire ici la procédure habituelle utilisée sous une forme de recette de cuisine pour que l'on puisse simplement comprendre ce qu'il se passe. -Durant cette explication je vais parler à un moment de Cookies, ne vous en faites pas c'est le sous chapitre suivant qui va vous en parler. +Durant cette explication, je vais parler à un moment de Cookies, ne vous en faites pas, c'est le sous-chapitre suivant qui va vous en parler. -Recette de cuisine pour récupèrer des images de la F1TV : +Recette de cuisine pour récupérer des images de la F1TV : 1. Démarrer une instance de navigateur avec les bons arguments -2. Ajouter les bons paramêtres pour ne pas se faire flag comme un bot +2. Ajouter les bons paramètres pour ne pas se faire flag comme un bot 3. Naviguer sur la page de la F1TV 4. Ajouter les cookies de connexion pour avoir accès au contenu de la page 5. Naviguer sur la page du Grand Prix demandé @@ -744,13 +741,13 @@ Recette de cuisine pour récupèrer des images de la F1TV : 7. Cliquer sur l'invite de cookies 8. Attendre cinq secondes le temps que la page se reload 9. Cliquer sur le bouton qui permet de passer du feed live à la DATA CHANNEL -10. Appuyer sur Espace pour faire apparaitre le bouton d'accès au paramêtres -11. Cliquer sur le menu déroulant des résolution -12. Trouver l'option 1080P et la selectionner +10. Appuyer sur Espace pour faire apparaitre le bouton d'accès au paramètres +11. Cliquer sur le menu déroulant des résolutions +12. Trouver l'option 1080P et la sélectionner 13. Cliquer sur le bouton qui met la vidéo en plein écran -14. Prendre de screenshots à intervales réguliers +14. Prendre de screenshots à intervalles réguliers -Pour faire toutes ces actions on doit récupèrer les éléments selon leur ID ou leur classe. +Pour faire toutes ces actions, on doit récupérer les éléments selon leur ID ou leur classe. Voici un exemple qui récupère le bouton de plein écran et qui clique dessus : @@ -759,17 +756,17 @@ IWebElement fullScreenButton = Driver.FindElement(By.ClassName("bmpui-ui-fullscr fullScreenButton.Click(); ``` -Ca peut paraître plutôt simple dit comme ca et quand tout fonctionne ca l'est mais la difficulté vient du fait que à peu près nimporte laquelle de ces étapes peut rater et qu'il faut donc faire un bon système de gestion d'erreurs qui puisse aider l'utilisateur en cas de problème. +Ça peut paraître plutôt simple dit comme ça et quand tout fonctionne ça l'est, mais la difficulté vient du fait qu'à peu près n'importe laquelle de ces étapes peut rater et qu'il faut donc faire un bon système de gestion d'erreurs qui puisse aider l'utilisateur en cas de problème. -Parfois il est aussi difficile de trouver un élément selon son ID,sa classe, ou sa value. +Parfois, il est aussi difficile de trouver un élément selon son ID, sa classe, ou sa value. -Par exemple l'option qui permet de passer en 1080P peut avoir comme value `1080_9011456` ou `1080_9011200` si on refresh la page. Cela demande de passer par des expression régulières ce qui n'est pas compliqué en soi mais c'est toutes ces petites choses qui rendent le processus long à mettre en place. +Par exemple, l'option qui permet de passer en 1080P peut avoir comme value `1080_9011456` ou `1080_9011200` si on refresh la page. Cela demande de passer par des expressions régulières, ce qui n'est pas compliqué en soi, mais ce sont toutes ces petites choses qui rendent le processus long à mettre en place. -Il faut dire aussi que les sites ne sont pas forcément très content de voir des bots passer car cela peut être un risque de DDOS et de Scraping (Comme moi) et donc ils mettent en place des systèmes pour nous empêcher de faire ce que l'on veut +Il faut dire aussi que les sites ne sont pas forcément très contents de voir des bots passer, car cela peut être un risque de DDOS et de Scraping (Comme moi) et donc ils mettent en place des systèmes pour nous empêcher de faire ce que l'on veut. -On peut utiliser différntes techniques pour passer outre ces restrictions comme : +On peut utiliser différentes techniques pour passer outre ces restrictions comme : -- Changer son UserAgent +- Changer son User Agent - Changer sa résolution - Ne pas avoir des patterns trop prévisibles - Avoir un historique @@ -778,43 +775,43 @@ On peut utiliser différntes techniques pour passer outre ces restrictions comme - Passer par un proxy pour ne pas se faire flag - Utiliser des librairies plus discrètes -J'ai eu l'occasion de tester toutes ces methodes pour tenter de passer derrière les radars de la F1TV et visiblement j'ai réussi pour les pages principales mais pas pour les pages de Login. +J'ai eu l'occasion de tester toutes ces méthodes pour tenter de passer derrière les radars de la F1TV et visiblement, j'ai réussi pour les pages principales, mais pas pour les pages de Login. -Il faut savoir que la bataille entre bots et propriétaires de sites est un grand jeu du chat et de la souris et que les plateformes innovent constamment leur sécurité. Et il se trouve que la partie login de la F1TV est hebergée autre part que le reste du site chez Amazon et que elle possède les meilleures sécurités que j'aie pu voir. Aucunes des methodes que j'ai citées et d'autres encore que j'ai essayé n'ont réussi à fourvoyer le système. +Il faut savoir que la bataille entre bots et propriétaires de sites est un grand jeu du chat et de la souris et que les plateformes innovent constamment leur sécurité. Et il se trouve que la partie login de la F1TV est hébergée autre part que le reste du site chez Amazon et qu'elle possède les meilleures sécurités que j'aie pu voir. Aucunes des méthodes que j'ai citées et d'autres encore que j'ai essayé n'ont réussi à fourvoyer le système. -J'ai donc été obligé de faire appel à la connexion par Cookies pour pouvoir accèder au reste du site internet. +J'ai donc été obligé de faire appel à la connexion par Cookies pour pouvoir accéder au reste du site internet. -#### Récupèrer les cookies ? +#### Récupérer les cookies ? -Alors, on va mettre de côté toutes les questions de sécurité et de violation de la vie privée et de protection des données des utilisateurs pour ce chapitre. Car pour faire simple, je siphonne TOUS les cookies de la persone qui utilise mon app. +Alors, on va mettre de côté toutes les questions de sécurité et de violation de la vie privée et de protection des données des utilisateurs pour ce chapitre. Car pour faire simple, je siphonne TOUS les cookies de la personne qui utilise mon app. -Alors évidemment ca n'est pas pour faire des bétises avec et c'est pour une "bonne" raison, mais bon quand même ca peut faire bizarre comme ca. +Alors évidemment ça n'est pas pour faire des bêtises avec et c'est pour une "bonne" raison, mais bon quand même ça peut faire bizarre comme ça. -Je pense que vous savez déja ce qu'est un Cookie, mais je vais quand même faire un petit point la dessus car c'est important pour la suite. +Je pense que vous savez déjà ce qu'est un Cookie, mais je vais malgré tout faire un petit point là-dessus, car c'est important pour la suite. -Quand on va sur un site internet et que l'on se connecte avec nos identifiants nous sommes connectés sur la session. +Quand on va sur un site internet et que l'on se connecte avec nos identifiants, nous sommes connectés sur la session. -Cependant, si on quitte le site ou que l'on ferme le navigateur, le site ne peut pas garder en mémoire que c'est bien vous quand le lendemain vous retournez dessus. Pour palier à cette limitation on a inventé cette chose magnifique (hem...) que sont les cookies ! +Cependant, si on quitte le site ou que l'on ferme le navigateur, le site ne peut pas garder en mémoire que c'est bien vous quand le lendemain, vous retournez dessus. Pour palier à cette limitation, on a inventé cette chose magnifique (hem...) que sont les cookies ! Les cookies sont des petits fichiers qui sont stockés dans votre navigateur et qui peuvent servir à beaucoup de choses comme traquer votre activité sur internet et espionner un peu ou aussi par exemple, servir de jeton de connexion. -L'idée est que quand vous vous connectez sur le site avec vos identifiants, le site envoie un petit fichier dans votre navigateur qui va servir de jeton. Et donc quand vous reviendrez, le site pourra voir que vous avez le jeton et vous connectera automatiquement. +L'idée est que quand vous vous connectez sur le site avec vos identifiants, le site envoie un petit fichier dans votre navigateur qui va servir de jeton. Et donc lorsque vous reviendrez, le site pourra voir que vous avez le jeton et vous connectera automatiquement. -Ca peut paraître génial, et c'est effectivement bien pratique, cependant ce n'est pas sans risques. En effet, imaginons qu'un acteur malveillant parvienne à s'emparer de ces petits fichiers, il pourrait ainsi facilement se faire passer pour vous. Alors un cookie expire à un moment donné pour temperer les risques, mais ils sont toujours présents. +Ça peut paraître génial, et c'est effectivement bien pratique, cependant ce n'est pas sans risques. En effet, imaginons qu'un acteur malveillant parvienne à s'emparer de ces petits fichiers, il pourrait ainsi facilement se faire passer pour vous. Alors un cookie expire à un moment donné pour tempérer les risques, mais ils sont toujours présents. -Dans notre cas on peut vite comprendre pourquoi cela peut être intéressant de récupèrer ces cookies. En effet, si on peut mettre la main sur le jeton de connexion de l'utilisateur de notre application. On pourra se connecter automatiquement à la F1TV et aller prendre des photos directement sans que l'utilisateur aie à faire quoi que ce soit. +Dans notre cas, on peut vite comprendre pourquoi cela peut être intéressant de récupérer ces cookies. En effet, si on peut mettre la main sur le jeton de connexion de l'utilisateur de notre application. On pourra se connecter automatiquement à la F1TV et aller prendre des photos directement sans que l'utilisateur ait à faire quoi que ce soit. -Sauf que les cookies ne sont pas stockés en clair comme ca. Evidemment Google Chrome a mis en place quelques techniques pour éviter que nimporte qui puisse s'amuser à aller taper dans les cookies de la machine. +Sauf que les cookies ne sont pas stockés en clair comme ça. Évidemment, Google Chrome a mis en place quelques techniques pour éviter que n'importe qui puisse s'amuser à aller taper dans les cookies de la machine. -Tous les cookies sont stockés dans une base de données sqlite avec les noms en clair et les valeurs sont encryptées en utilisant la methode AES 256 qui est une methode de cryptage très utilisée et efficace. +Tous les cookies sont stockés dans une base de données SQLite avec les noms en clair et les valeurs sont encryptées en utilisant la méthode AES 256 qui est une méthode de cryptage très utilisée et efficace. -Tellement efficace qu'il serait complêtement inutile de tenter de les decrypter en utilisant de la force brute pour trouver la valeur ou même une attaque de dictionnaire ou quoi que ce soit. +Tellement efficace qu'il serait complètement inutile de tenter de les décrypter en utilisant de la force brute pour trouver la valeur ou même une attaque de dictionnaire ou quoi que ce soit. -Si ces valeurs peuvent être encodées et décodées en local sur la machine sans connexion internet, cela veut dire que la clé est stockée sur la machine. Et si je peux mettre la mais sur cette clé alors je pourrai lire tous les cookies de la machine. +Si ces valeurs peuvent être encodées et décodées en local sur la machine sans connexion internet, cela veut dire que la clé est stockée sur la machine. Et si je peux mettre là, mais sur cette clé, alors je pourrai lire tous les cookies de la machine. -Cette clé est stocké dans les fichiers de Google Chrome sous `Google\Chrome\User Data\Local State`. Et dans ce fichier on peut trouver une liste de données en clé valeurs et on peut trouver la clé sous `os_crypt` `encrypted_key`. On pourrait croire que l'on a déja touché le jackpot mais il reste encore une étape. Cette clé est cryptée en utilisant le système d'encryption de Windows. Cette encryption est utilisée pour empêcher des utilisateurs non connectés d'accèder à certaines données. Mais comme nous sommes connectés nous pouvons facilement utiliser les librairies de decryption pour trouver la valeur de cette clé. +Cette clé est stockée dans les fichiers de Google Chrome sous `Google\Chrome\User Data\Local State`. Et dans ce fichier, on peut trouver une liste de données en clé valeurs et on peut trouver la clé sous `os_crypt` `encrypted_key`. On pourrait croire que l'on a déjà touché le jackpot, mais il reste encore une étape. Cette clé est cryptée en utilisant le système d'encryption de Windows. Cette encryption est utilisée pour empêcher des utilisateurs non connectés d'accéder à certaines données. Mais comme nous sommes connectés, nous pouvons facilement utiliser les librairies de décryptions pour trouver la valeur de cette clé. -Et à partir de la il suffit d'utiliser cette clé pour décrypter tous les cookies de la machine pour aller chercher ceux qui nous intéressent. +Et à partir de là, il suffit d'utiliser cette clé pour décrypter tous les cookies de la machine pour aller chercher ceux qui nous intéressent. Voici un exemple du code python qui permet d'aller chercher la clé d'encryption dans les fichiers de Google Chrome : @@ -935,52 +932,52 @@ public string GetCookie(string host, string name) } ``` -Maintenant que l'on sait comment simuler et manipuler un navigateur internet, que l'on sait comment se connecter sur le compte F1TV de l'utilisateur sans qu'il n'aie rien à faire. On a tous les ingrédients pour automatiquement récupèrer des images de la F1TV du Grand Prix que l'on souhaite. +Maintenant que l'on sait comment simuler et manipuler un navigateur internet, que l'on sait comment se connecter sur le compte F1TV de l'utilisateur sans qu'il n’aie rien à faire. On a tous les ingrédients pour automatiquement récupérer des images de la F1TV du Grand Prix que l'on souhaite. #### Calibration -Maintenant que l'on a des images de la page Data de la F1TV on pourrait croire que c'est tout bon on peut direct passer à la partie OCR. Mais que nenni ! +Maintenant que l'on a des images de la page Data de la F1TV, on pourrait croire que c'est tout bon, on peut direct passer à la partie OCR. Mais que nenni ! -Le gros soucis de l'OCR c'est que sa précision est grandement réduite dès que l'on augmente la taille de la zone de recherche. Même simplement deux mots sur une image, si on les prends dans images individuelles on a de grandes chances de trouver quelque chose mais si on les mets les deux sur la même et que on tente l'OCR on va avoir de résultats bien moins bons. +Le gros souci de l'OCR c'est que sa précision est grandement réduite dès que l'on augmente la taille de la zone de recherche. Même simplement deux mots sur une image, si on les prend dans les images individuelles, on a de grandes chances de trouver quelque chose, mais si on les met les deux sur la même et qu'on tente l'OCR, on va avoir de résultats bien moins bons. -Et puis il faut aussi voir que selon les données que je cherche je ne peux pas faire le même traitement. +Et puis il faut aussi voir que selon les données que je cherche, je ne peux pas faire le même traitement. Par exemple, savoir si le DRS est allumé, savoir quels pneus chausse un pilote et depuis combien de tours et savoir quel est le temps de son dernier tour, ce sont des informations qui demandent des traitements qui n'ont rien à voir. Il faut donc pouvoir dire au programme d'OCR ou se trouvent les informations et quelle est leur nature pour qu'il puisse les décoder. -Il faut donc faire une calibration qui puisse donner toutes les infos importantes mais qui en même temps soit facile à utiliser car un utilisateur doit être capable de le faire assez facilement. +Il faut donc faire une calibration qui puisse donner toutes les infos importantes, mais qui en même temps soit facile à utiliser, car un utilisateur doit être capable de le faire assez facilement. -Voici la liste des informations que l'on doit récupèrer : +Voici la liste des informations que l'on doit récupérer : -- La liste des pilotes présent sur le Grand Prix +- La liste des pilotes présents sur le Grand Prix - La position de la zone principale - La position de chaque zone de pilote -- La position de toutes les Window sur chaque zone de pilote +- La position de toutes les Windows sur chaque zone de pilote -Le but a été de retirer le plus d'étapes possibles à l'utilisateur. Techniquement j'aurais pu faire une version complêtement manuelle mais ca aurait pris trop de temps alors il y a des systèmes qui permettent de rendre cette tâche moins pénible. +Le but a été de retirer le plus d'étapes possibles à l'utilisateur. Techniquement, j'aurais pu faire une version complètement manuelle, mais ça aurait pris trop de temps, alors il y a des systèmes qui permettent de rendre cette tâche moins pénible. ##### Liste des pilotes -Pour la liste des pilotes j'ai pensé à utiliser une API externe pour avoir une liste dans laquelle on pourrait selectionner des noms de pilotes sauf que j'ai abandonné l'idée car je trouvais que le projet avait déja bien assez de points qui dépendent de l'exterieur. +Pour la liste des pilotes, j'ai pensé à utiliser une API externe pour avoir une liste dans laquelle on pourrait sélectionner des noms de pilotes, sauf que j'ai abandonné l'idée, car je trouvais que le projet avait déjà bien assez de points qui dépendent de l'extérieur. -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 reserve comme ca si un pilote est malade sur une course on a pas besoin de venir changer la liste. +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. ##### Zone principale -Pour la zone principale c'est complêtement manuel, on attend de l'utilisateur deux points x,y sur l'image pour ensuite avoir une idée de ou est sensé se trouver la zone. +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. !["Exemple de zone principale"](./Images/Screens/MainZoneExample.png) ##### Zones pilotes -C'est la que ca devient intéressant. L'utilisateur n'a pas besoin de faire quoi que ce soit pour que le programme sache ou sont les zones des pilotes. +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. -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 ca parfois) le vingtième pilote se retrouve avec une zone complêtement desaxée. +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. -La, le programme va "simplement" effectuer une reconaissance 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. +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. -Avec les position il est facile de determiner ou sont toutes les zones de pilotes et donc sans que l'utilisateur n'aie à toucher quoi que ce soit, dès qu'il a donné les infos pour la zone principale, les zones de pilotes sont determinées. +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. !["Exemple zone pilote"](./Images/Screens/DriverZoneExample.png) @@ -1053,7 +1050,7 @@ public void AutoCalibrate() ##### Windows pilotes -C'est ici que c'est le plus pénible pour l'utilisateur, il doit selectionner manuellement les positions des fenêtres de données. Ensuite dès que l'utilisateur a donnée une position pour chaque window, on applique les positions pour chaque zone de pilote. +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. 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 : @@ -1067,11 +1064,11 @@ Il est important que toutes ces zones soient transmises avec le plus de précisi ##### Stockage -Ensuite quand l'utilisateur a finit de configurer son flux, la configuration est stockée pour qu'il puisse ensuite la réutiliser pour tous les autres Grand Prix de l'année. +Ensuite, quand l'utilisateur a fini de configurer son flux, la configuration est stockée pour qu'il puisse ensuite la réutiliser pour tous les autres Grand Prix de l'année. -Le stockage est fait sous format JSON et est fait pour que le programme d'OCR puisse lire dedans toutes les infos nescessaires. +Le stockage est fait sous format JSON et est fait pour que le programme d'OCR puisse lire dedans toutes les infos nécessaires. -Cela fait des fichiers plutôt gros mais je n'avais pas vraiment le choix. J'ai testé une version avec seulement les infos de la première zone de pilote mais avec l'interpolation, les derniers pilotes se retrouvent avec des zones clairement pas à la bonne taille. +Cela fait des fichiers plutôt gros, mais je n'avais pas vraiment le choix. J'ai testé une version avec seulement les infos de la première zone de pilote, mais avec l'interpolation, les derniers pilotes se retrouvent avec des zones clairement pas à la bonne taille. Voici un exemple de ce à quoi ressemble le JSON final : @@ -1241,19 +1238,19 @@ Voici un exemple de ce à quoi ressemble le JSON final : } ``` -Et avec tout ca. L'OCR peut démarrer dans de bonnes conditions +Et avec tout ça. L'OCR peut démarrer dans de bonnes conditions ### OCR -Maintenant que on a des images qui arrivent automatiquement et que l'on sait ou se trouvent les informations sur ces dites images, je vais parler de la seconde partie du projet qui parle du processus de reconnaissance de data sur une image du feed DATA de la F1TV. +Maintenant qu'on a des images qui arrivent automatiquement et que l'on sait où se trouvent les informations sur ces dites images, je vais parler de la seconde partie du projet qui parle du processus de reconnaissance de data sur une image du feed DATA de la F1TV. C'est je pense la partie qui a demandé le plus tests et de refactor. Toute la partie OCR a été développée dans un projet à part avant d'être intégrée dans le projet final. -Il faut savoir que la reconnaissance est différente celon ce que l'on cherche. Je vais donc décomposer cette partie du document en sous rubriques selon les données recherchées. +Il faut savoir que la reconnaissance est différente selon ce que l'on cherche. Je vais donc décomposer cette partie du document en sous rubriques selon les données recherchées. -Mais avant ca je dois expliquer certains concepts qui seront importants. +Mais avant ça, je dois expliquer certains concepts qui seront importants. #### Fonctionnement général @@ -1261,16 +1258,16 @@ Voici un screenshot de la page DATA de la F1TV que le programme va recevoir : !["Screen F1TV"](./Images/Screens/ScreenF1TvData.png) -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 4 zones contenant de l'information dans un format différent. +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. !["Zones principales"](./Images/Figma/WindowZoneExplanation1.png) -Dans l'exemple ci dessus on peut voir 3 zones mais on aurait également pu comprendre la zone de position des pilotes autour du circuit pour faire 4. +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. -Ces 4 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 ca à implémenter. +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. -J'ai utilisé le mot "Zone" plus haut et ca n'est pas juste un mot utilisé au hasard. C'est le nom de l'objet que j'utilise pour les représenter dans mon programme. Mais comme c'est important de bien comprendre ce concept avant de continuer je vais vous l'expliquer. +J'ai utilisé le mot "Zone" plus haut et ça n'est pas juste un mot utilisé au hasard. C'est le nom de l'objet que j'utilise pour les représenter dans mon programme. Mais comme c'est important de bien comprendre ce concept avant de continuer, je vais vous l'expliquer. ZONE : @@ -1278,36 +1275,36 @@ L'objet "Zone" parent est un objet qui est une zone d'image. Je m'explique, le b Le but d'une Zone est de contenir une liste de plus petites Zones ou bien une liste de "Window" (j'explique ce que c'est juste après). Elle contient la portion d'image qui la concerne et ses propres dimensions. -Le parent zone ne prévoit que de pouvoir ajouter ou supprimer des éléments des listes de zones ou de windows ainsi qu'une methode qui permet d'aller chercher toutes informations des livres qu'elle contient. +Le parent zone ne prévoit que de pouvoir ajouter ou supprimer des éléments des listes de zones ou de fenêtres ainsi qu'une méthode qui permet d'aller chercher toutes informations des livres qu'elle contient. -L'intérêt d'une zone est de pouvoir compartimenter une image dans des parties intéressantes au niveau de la reconnaissance mais pas de traiter d'information. +L'intérêt d'une zone est de pouvoir compartimenter une image dans des parties intéressantes au niveau de la reconnaissance, mais pas de traiter d'information. WINDOW : -L'objet "Window" est un objet qui peut ressembler beaucoup à l'objet "Zone". En effet elle aussi est une partie d'une image plus grande et contient ses dimensions, mais elle se distingue en deux points importants. +L'objet "Window" est un objet qui peut ressembler beaucoup à l'objet "Zone". En effet, elle aussi est une partie d'une image plus grande et contient ses dimensions, mais elle se distingue en deux points importants. - Elle ne contient pas d'autres Zones ou Windows - Elle peut retourner les informations écrites sur son image. -Toutes les Window qui héritent du parent Window peuvent implémenter une methode qui permet de renvoyer ce qui peut être décodé sur son image. Les enfants peuvent aussi aller piocher dans les nombresues methodes de récupèration de données contenues dans le parent Window. Mieux vaut réutiliser le plus possible que de réinventer la roue pour chaque Window. +Toutes les Window qui héritent du parent Window peuvent implémenter une méthode qui permet de renvoyer ce qui peut être décodé sur son image. Les enfants peuvent aussi aller piocher dans les nombreuses méthodes de récupération de données contenues dans le parent Window. Il vaut mieux réutiliser le plus possible que de réinventer la roue pour chaque Window. Une analogie un peu bancale pourrait se présenter comme la suivante : -La zone est une armoire ou une bibliotèque. Si c'est une zone qui contient d'autres zones c'est une bibliotèque et chacune de ces sous-zones sont des armoires. Leur unique but est de contenir de manière ordonnée des objets qui eux contiennent de l'information. +La zone est une armoire ou une bibliothèque. Si c'est une zone qui contient d'autres zones, c'est une bibliothèque et chacune de ces sous-zones sont des armoires. Leur unique but est de contenir de manière ordonnée des objets qui eux contiennent de l'information. -Les livres ici sont les Windows. Ils contiennet de l'information et sont stockés dans des armoires et on y accède en allant dans la bonne bibliotèque et en allant dans la bonne armoire. +Les livres ici sont les Windows. Ils contiennent de l'information et sont stockés dans des armoires et on y accède en allant dans la bonne bibliothèque et en allant dans la bonne armoire. -Dernières choses pour comprendre le diagramme: +Dernières choses pour comprendre le diagramme : -- Il existe une Main Zone qui est une des 4 grandes zones dont je parlais dans la décomposition de l'image. +- Il existe une Main Zone qui est une des quatre grandes zones dont je parlais dans la décomposition de l'image. - Il existe aussi des "Driver Zone" qui sont de plus petites zones contenues dans la Main Zone qui et qui ne contiennent que les informations d'un pilote. - 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. -Voila donc un petit diagramme qui montre le découpage du programme : +Voilà donc un petit diagramme qui montre le découpage du programme : !["Diagramme explicatif de l'architecture des zones"](./Images/Figma/WindowZoneExplanationDiagram.png) -Pour visualiser encore un peu mieux comment ce découpage prend forme voici ce que chaque zone et Window contient. +Pour visualiser encore un peu mieux comment ce découpage prend forme, voici ce que chaque zone et Window contient. Main Zone : @@ -1335,41 +1332,41 @@ Driver Tyre Window : Il existe d'autres types de Window mais ce sont les principaux. -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. +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. -Pour résumer, on a un programme qui prend en entrée un fichier de configuration, qui prend des images de la F1TV et les découpe dans des ZONES qui elles même sont découpées en WINDOWS pour qu'on puisse plus facilement les décoder. +Pour résumer, on a un programme qui prend en entrée un fichier de configuration, qui prend des images de la F1TV et les découpe dans des ZONES qui elles même sont découpées en WINDOWS pour qu'on puisse plus simplement les décoder. -Maintenant qu'on a une liste de différent types de zones on peut commencer à chercher ce qu'il y a marqué dessus. +Maintenant qu'on a une liste de différents types de zones, on peut commencer à chercher ce qu'il y a marqué dessus. -Pour cela il faut dabord comprendre un petit peu comment l'OCR fonctionne et comment des libraries comme Tesseract fonctionnent pour donner du texte en partant d'une image. +Pour cela, il faut d'abord comprendre un petit peu comment l'OCR fonctionne et comment des libraires comme Tesseract fonctionnent pour donner du texte en partant d'une image. -Pour faire très simple, nous avons un modèle qui est entrainé. C'est à dire que on donne à un programme un très grand nombre de mots ou de lettres en lui disant ce que contiennent chaques images. Ensuite le programme va créer des matrices de convolutions pour chaque lettre avec comme objectif de detecter les points communs entre les lettres pour créer un alpphabet. +Pour faire très simple, nous avons un modèle qui est entrainé. C'est-à-dire qu'on donne à un programme un très grand nombre de mots ou de lettres en lui disant ce que contiennent chaques images. Ensuite le programme va créer des matrices de convolutions pour chaque lettre avec comme objectif de détecter les points communs entre les lettres pour créer un alpphabet. -Par exemple la matric de la lettre 'H' donnerait un poids important à des lignes verticales connectées par une ligne centrale. Et si on fournis assez de données de bonne qualité au modèle, les matrices peuvent être très efficace à detecter si une lettre est un H ou un M. +Par exemple, la matrice de la lettre 'H' donnerait un poids important à des lignes verticales connectées par une ligne centrale. Et si on fournit assez de données de bonne qualité au modèle, les matrices peuvent être très efficace à détecter si une lettre est un H ou un M. -Il y a pleins d'autres methodes comme l'utilisation d'un dictionnaire de mots de la langue pour permettre la reconnaissance de mots même si une lettre au milieu n'est pas comprise ou en ajoutant d'autres informations sur le contexte mais ca ne nous intéresse pas ici. +Il y a pleins d'autres méthodes comme l'utilisation d'un dictionnaire de mots de la langue pour permettre la reconnaissance de mots même si une lettre au milieu n'est pas comprise ou en ajoutant d'autres informations sur le contexte, mais ça ne nous intéresse pas ici. -C'est important de comprendre comment cette reconnaissance de caractères avec des matrices fonctionne car cela va nous aider à préparer nos données pour lui rendre la vie facile et augmenter la précision de nos résultats. +C'est important de comprendre comment cette reconnaissance de caractères avec des matrices fonctionne, car cela va nous aider à préparer nos données pour lui rendre la vie facile et augmenter la précision de nos résultats. ##### Filtres et traitement -On peut essayer de donner toutes nos images directement à Tesseract pour qu'il reconnaisse tout le texte qu'il y voit mais on risque de se retrouver avec des résultats au mieux inconsistents. +On peut essayer de donner toutes nos images directement à Tesseract pour qu'il reconnaisse tout le texte qu'il y voit, mais on risque de se retrouver avec des résultats au mieux inconsistants. -Dans notre cas, le soucis est que les chiffres et lettres sont beaucoup trop petits. Ils ne font parfoisd que 10 pixels de haut et cela fait que il n'est pas forcément facile 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. +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. Exemple : -Prenons le chiffre 9. Dans l'image il peut être représenté de cette manière : +Prenons le chiffre 9. Dans l'image, il peut être représenté de cette manière : !["Exemple de chiffre avant post traitement"](./Images/Figma/Bad9Example.png) -On peut voir qu'il est flou, pour nous cela ne pose pas de problème et je pense que à peu près nimporte qui peut dire que c'est un 9. +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. -Cependant comme les contours sont flous et même si on essaie de retirer le background : +Cependant, comme les contours sont flous et même si on essaie de retirer le background : -!["9 avec anti aliasing"](./Images/Figma/Aliased9.png) +!["9 avec antialiasing"](./Images/Figma/Aliased9.png) -On voit que le 9 n'est pas clairement définit. En effet on pourrait le comprendre comme : +On voit que le 9 n'est pas clairement défini. En effet, on pourrait le comprendre comme : !["Premier exemple de contours"](./Images/Figma/Horrible9.png) @@ -1377,15 +1374,15 @@ Ou comme : !["Second exemple de contours"](./Images/Figma/Clean9Example.png) -Voire même simplement comme : +Voire simplement comme : -!["Exemple de coutour généreux"](./Images/Figma/Filled9.png) +!["Exemple de contour généreux"](./Images/Figma/Filled9.png) -Et on se rend bien compte que les performances de detection ne sont pas les mêmes dans ces trois cas. +Et on se rend bien compte que les performances de détection ne sont pas les mêmes dans ces trois cas. 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. -Mais chaque type de donnée va avoir des methodes de post traitement différents. +Mais chaque type de donnée va avoir des méthodes de post traitement différents. Donc voici les différents types de reconnaissance et leur post traitements : @@ -1401,15 +1398,15 @@ Voici un exemple de la WINDOW nom de pilote en entrée : !["Exemple texte cru"](./Images/Screens/ExempleTextRaw.png) -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 a plus de mal à reconnaitres, 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 car si une lettre pose problême il ne peut pas trouver de contexte qui puisse l'aider). +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). 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. -1 : J'inverse les couleurs. Je me suis rendu compte que il était souvent plus facile de trouver un noir sur blanc que blanc sur noir. Je ne suis pas sur que cette étape soit capitale cependant. +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 !["Texte inversé"](./Images/Screens/ExempleTextINvertColor.png) -2 : Je fais un *Treshhold* de 165 car avec moins le texte parfois prend trop du background et avec plus les lettres sont trop fines. +2 : Je fais un *Treshhold* de 165, car avec moins le texte occasionnellement prend trop du background et avec plus les lettres sont trop fines. !["Texte après Treshold"](./Images/Screens/ExempleTextTresholding.png) @@ -1417,44 +1414,44 @@ Donc pour le rendre plus facilement lisible et augmenter les chances que toutes !["Texte après Resize"](./Images/Screens/ExempleTextResize.png) -4: Je fais une très rapide *Dilatation* du texte pour retirer le flou amené par la methode 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. +4 : Je fais une très rapide *Dilatation* 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. !["Texte après Dilatation"](./Images/Screens/ExempleTextDilatation.png) -*Explication des methodes précises plus bas* +*Explication des méthodes précises plus bas* -Voila 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. +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. -C'est aussi les premières methodes que j'ai pu développer alors forcément elles n'ont pas le niveau de détails de certaines autres. +Ce sont aussi les premières méthodes que j'ai pu développer alors forcément, elles n'ont pas le niveau de détails de certaines autres. -Mais comme même avec ce traitement il n'est pas rare que je me retrouve avec une ou deux lettres pas justes, il faut un moyen d'être sûr que c'est le bon nom qui est trouvé. Ce qu'il y a de pratique avec les noms de pilotes c'est que on sait déja comment ils s'appellent avant le Grand Prix. +Mais comme même avec ce traitement, il n'est pas rare que je me retrouve avec une ou deux lettres pas justes, il faut un moyen d'être sûr que c'est le bon nom qui est trouvé. Ce qu'il y a de pratique avec les noms de pilotes, c'est qu'on sait déjà comment ils s'appellent avant le Grand Prix. -En effet dans le fichier de configuration de la reconnaissance, il y a une liste de noms de pilotes. Cela veut dire que au lieu de chercher à trouver parfaitement les bonnes lettres, on peut simplement essayer de trouver quel nom de pilote ressemble le plus au nom trouvé sur l'image. +En effet, dans le fichier de configuration de la reconnaissance, il y a une liste de noms de pilotes. Cela veut dire qu'au lieu de chercher à trouver parfaitement les bonnes lettres, on peut simplement essayer de trouver quel nom de pilote ressemble le plus au nom trouvé sur l'image. -Pour ce faire j'ai utilisé une methode appelée la distance de Levenshtein. Pour faire simple c'est une methode qui va calculer les distances de lettres pour determiner entre des strings laquelle ressemble le plus à une autre. +Pour ce faire, j'ai utilisé une méthode appelée la distance de Levenshtein. Pour faire simple, c'est une méthode qui va calculer les distances de lettres pour déterminer entre des strings laquelle ressemble le plus à une autre. -Pour résumer le fonctionnement dans lordre : +Pour résumer le fonctionnement dans l'ordre : -- On prend l'image on la traite +- On prend l'image, on la traite - On envoie l'image traitée à Tesseract - On trouve quel nom de pilote ressemble le plus à ce résultat - On renvoie le nom du pilote ###### Chiffres -Cette methode en réalité utilise simplement la même methode que celle qui va récupèrer le texte sur une image. Cependant, la, on envoie à Tesseract l'information qu'il ne peut trouver que des chiffres sur l'image ce qui lui permet d'être beaucoup plus précis et de ne pas confondre un 9 avec un P ou un 11 avec un H PAR EXEMPLE (non pas que ca me soit arrivé très régulièrement et que ca me soit resté dans la gorge évidemment) +Cette méthode en réalité utilise juste la même méthode que celle qui va récupérer le texte sur une image. Cependant, là, on envoie à Tesseract l'information qu'il ne peut trouver que des chiffres sur l'image, ce qui lui permet d'être beaucoup plus précis et de ne pas confondre un 9 avec un P ou un 11 avec un H PAR EXEMPLE (non pas que ça me soit arrivé très régulièrement et que ça me soit resté dans la gorge évidemment). -L'avantage c'est que cette methode ne demande même pas de traitement de la donnée en sortie de Tesseract. On éspère simplement que le post traitement aura suffit. +L'avantage, c'est que cette méthode ne demande même pas de traitement de la donnée en sortie de Tesseract. On espère simplement que le post traitement aura suffit. TEMPS : -Cette methode regroupe la détection de temps au tour. Il y a trois grands types de WINDOW qui sont concernées : +Cette méthode regroupe la détection de temps au tour. Il y a trois grands types de WINDOW qui sont concernées : - La WINDOW du temps au tour - La WINDOW du retard sur le leader - La WINDOW des secteurs -La grande différence ce sont les ordres de grandeur. Les temps au tour sont en général entre 50 secondes et 2 minutes. Tandis que les secteurs sont entre 20 et 30 secondes alors que le retard sur le leader peut-être de plusieurs minutes. +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. Cependant, tous ces temps possèdent le même type de post-traitement avant d'être envoyés à Tesseract. @@ -1462,66 +1459,66 @@ Voici un exemple de temps au tour avant toute transformation : !["Temps au tour avant traitement"](./Images/Screens/ExempleLapTimeBefore.png) -On peut avoir l'impression que ce texte est tout à fait lisible et facile à décoder surtout quand on le voit de loin comme ca. 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 echelles est terrible. +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. !["Temps au tour zoomé"](./Images/Screens/ExempleLapTimeBeforeUpscaled.png) -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. Ca n'est simplement pas utilisable. +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. -Cette partie est un peu plus complexe car si la detection n'est pas fiable les chiffres sont simplement inutilisables. Si à tout moment un temps au tour de 1:39.106 devient 1:32.108 c'est juste pas possible. +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. Voici donc les étapes de post-traitement que j'ai mis en place pour leur détection : -1: J'applique un *Treshold* de 185 pour enlever les ambiguité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 ressemlent beaucoup plu que les lettres, il faut tenter le plus possible de conserver leur formes spécifiques. Je me suis rendu compte que cette valeur était une de celles qui marchent le mieux. +1 : J'applique un *Treshold* 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. !["Temps au tour après Treshold"](./Images/Screens/ExempleLapTimeTreshold.png) -2: J'applique un *Resize* 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. +2 : J'applique un *Resize* 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. !["Temps au tour après Resize"](./Images/Screens/ExempleLapTimeResize.png) -3: Comme le *Resize* amène du flou, j'utilise une methode de *Dilatation* qui me permet de retirer ce flou et de remplir un peu plus certaines parties qui ont été un peu laissée par le *Resize*; +3 : Comme le *Resize* amène du flou, j'utilise une méthode de *Dilatation* qui me permet de retirer ce flou et de remplir un peu plus certaines parties qui ont été un peu laissée par le *Resize*; !["Temps au tour après Dilatation"](./Images/Screens/ExempleLapTimeDilatation.png) -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 *Erosion* qui me permet de contrecarrer en partie les rondeurs ajoutées par la dilatation et retrouver des chiffres bien formées. Pour l'*Erosion* et la *Dilatation* j'ai utilisé une valeur de 1 car je ne voulais pas trop changer les chiffres. +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 *Érosion* qui me permet de contrecarrer en partie les rondeurs ajoutées par la dilatation et retrouver des chiffres bien formés. Pour l'*Érosion* et la *Dilatation*, j'ai utilisé une valeur de 1, car je ne voulais pas trop changer les chiffres. -!["Temps au tour après Erosion"](./Images/Screens/ExempleLapTimeErode.png) +!["Temps au tour après Érosion"](./Images/Screens/ExempleLapTimeErode.png) -*Explication des methodes précises plus bas* +*Explication des méthodes précises plus bas* -Et avec ce post processing on retrouve de plutôts bon résultats qui demandent peu de traitement. +Et avec ce post processing, on retrouve de plutôt bons résultats qui demandent peu de traitement. -Le traitement dépend du type de WINDOW cependant. +Le traitement dépend du type de WINDOW cependant : -- Pour les secteurs on indique à Tesseract que les caractères autorisés sont : "0123456789." -- Pour les temps au tour on autorise plutôt "0123456789.:" -- Et pour les écarts on autorise "0123456789.+" +- Pour les secteurs, on indique à Tesseract que les caractères autorisés sont : "0123456789." +- Pour les temps au tour, on autorise plutôt "0123456789.:" +- Et pour les écarts, on autorise "0123456789.+" -Ensuite on récupère une liste de chiffres qui'il va falloir transformer en milisecondes pour faciliter le stockage et l'envoi. +Ensuite, on récupère une liste de chiffres qu'il va falloir transformer en millisecondes pour faciliter le stockage et l'envoi. -Le programme nettoie un peu la chaine avant de la convertir. Par exemple parfois le ':' de 1:34.456 est compris comme un '1' ou un '2' et il faut faire attention à detecter quand ca arriver. +Le programme nettoie un peu la chaine avant de la convertir. Par exemple parfois le ':' de 1:34.456 est compris comme un '1' ou un '2' et il faut faire attention à détecter quand ça arriver. -Je passe les détails du reste du nettoyage car c'est vraiment du cas par cas mais quand on a finit de nettoyer la chaine on peut transformer les chaines de minutes secondes et milisecondes en un total de milisecondes. +Je passe les détails du reste du nettoyage, car c'est vraiment du cas par cas, mais quand on a fini de nettoyer la chaine, on peut transformer les chaines de minutes, secondes et millisecondes en un total de millisecondes. Pour résumer le fonctionnement dans l'ordre : - On prend l'image et on lui applique une série de filtres - On envoie l'image filtrée à Tesseract - On nettoie le résultat Tesseract pour compenser certains biais -- On convertis le résultat en milisecondes +- On convertit le résultat en millisecondes ###### les chiffres (2) -Il faut savoir que avec la dernière version de l'émulateur (dont je vais parler un peu plus tard) +Il faut savoir qu'avec la dernière version de l'émulateur (dont je vais parler un peu plus tard). ###### Pneus -La on arrive sur la partie la plus pénible. +Là, on arrive sur la partie la plus pénible. -Pour comprendre la problématique il faut d'abord faire un petit point sur comment les pneus fonctionnent en Formule 1. +Pour comprendre la problématique, il faut d'abord faire un petit point sur comment les pneus fonctionnent en Formule 1. -Depuis 2019 en Formule 1 nous avons 5 grandes familles de pneus : +Depuis 2019, en Formule 1 nous avons 5 grandes familles de pneus : - Les pneus tendres - Les pneus medium @@ -1531,9 +1528,9 @@ Depuis 2019 en Formule 1 nous avons 5 grandes familles de pneus : !["Gamme de pneus Pirelli"](./Images/Photos/Tyres.png) -Les trois premiers pneus sont des pneus faits pour piste sèche, le pneu intermédiaire pour piste humide et le neu pluie pour la pluie. +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. -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. +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. Chaque pneu a une couleur donnée qui permet de les différencier. @@ -1541,52 +1538,52 @@ Voici un exemple de ce à quoi une WINDOW de pneus peut ressembler : !["Exemple zone pneus 1"](./Images/Screens/TyreZoneExemple3.png) -Mais cette zone peut aussi ressembler à ca : +Mais cette zone peut aussi ressembler à ça : !["Exemple zone pneus 2"](./Images/Screens/TyreZoneExemple2.png) -Mais aussi à ca : +Mais aussi à ça : !["Exemple zone pneus 3"](./Images/Screens/TyreZoneExemple1.png) -Voire même ca : +Voire même ça : !["Exemple zone pneus 4"](./Images/Screens/TyreZoneExemple4.png) -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. +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. -En gros le fonctionnement de cette zone d'information est assez simple. +En gros, le fonctionnement de cette zone d'information est assez simple. - Au fur et à mesure que la course avance, le trait fait de même. -- Le chiffre dans le round tout à droite indique le nombre de tour que le pilote a passé sur ce pneu. +- Le chiffre dans le round tout à droite indique le nombre de tours que le pilote a passé sur ce pneu. - La couleur indique le type de pneu. -- Si il y a une lettre à la place d'un chiffre c'est que c'est le premier tour sur ce pneu. La lettre indique le type de pneu. +- S'il y a une lettre à la place d'un chiffre, c'est que c'est le premier tour sur ce pneu. La lettre indique le type de pneu. -Et pas besoin de dire que si on essaie simplement de donner l'image à Tesseract on ne récupère ni les chiffres ni les lettres correctement si ce n'est pas du tout. +Et pas besoin de dire que si on essaie simplement de donner l'image à Tesseract, on ne récupère ni les chiffres ni les lettres correctement si ce n'est pas du tout. -Il faut donc utiliser une methode qui permette d'isoler le rond le plus à droite, lui appliquer un traitement qui permette à Tesseract de lire ce qu'il y a marqué et qui puisse determiner quel pneu est en train d'être utilisé. +Il faut donc utiliser une méthode qui permette d'isoler le rond le plus à droite, lui appliquer un traitement qui permette à Tesseract de lire ce qu'il y a marqué et qui puisse déterminer quel pneu est en train d'être utilisé. -J'ai décidé de m'occuper dans un premier temps de trouver ce rond avant d'appliquer les filtres car plus l'image est petite plus les filtres sont rapides. +J'ai décidé de m'occuper dans un premier temps de trouver ce rond avant d'appliquer les filtres, car plus l'image est petite, plus les filtres sont rapides. -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. +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. -Ensuite après avoir trouvé le premier obstacle, je récupère une zone qui doit englober le cercle. +Ensuite, après avoir trouvé le premier obstacle, je récupère une zone qui doit englober le cercle. Voici un exemple avec cette image en entrée : -!["Zone complête"](./Images/Screens/TyreZoneFull.png) +!["Zone complète"](./Images/Screens/TyreZoneFull.png) -Elle est automatiquement coupée de cette facon : +Elle est automatiquement coupée de cette façon : !["Zone coupée automatiquement"](./Images/Screens/TyreZoneCropped.png) -Cela me permet d'isoler uniquement ce qui m'intéresse ce qui est très pratique pour Tesseract et pour la detection de couleur. +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. -Ensuite avec cette image je peux commencer le processus de reconnaissance. +Ensuite, avec cette image, je peux commencer le processus de reconnaissance. Je commence par faire une moyenne de tous les pixels de l'image en excluant les pixels trop sombres qui font sûrement partie du background ou du chiffre. -Ensuite j'utilise une methode qui calcule la différence entre la couleur obbtenue et la liste de couleurs possible. +Ensuite, j'utilise une méthode qui calcule la différence entre la couleur obtenue et la liste de couleurs possible. Il y a cinq couleurs des pneus possibles : @@ -1610,49 +1607,49 @@ Il y a cinq couleurs des pneus possibles : !["Couleur d'un pneu pluie"](./Images/Photos/WetTyreColor.png) -Ce qui est pratique c'est que même dans les cas ou il n'y a pas beaucoup de couleur comme celui la : +Ce qui est pratique, c'est que même dans les cas où il n'y a pas beaucoup de couleur comme celui-là : !["Pneu dur avec 0 tours"](./Images/Screens/TyreZoneHard.png) On arrive à une couleur moyenne de : -!["Couleur moyenne de l'image ci dessus après soustraction du background"](./Images/Screens/TyreZoneHardAVG.png) +!["Couleur moyenne de l'image ci-dessus après soustraction du background"](./Images/Screens/TyreZoneHardAVG.png) -Et il est donc assez facile de determiner le type de pneu en question. +Et il est donc assez facile de déterminer le type de pneu en question. 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. -Ensuite il "suffit" de lire le chiffre dans le rond et si on arrive pas à le lire alors c'est que c'est une lettre et on sait que le nombre de tours est donc de 0. +Ensuite il "suffit" de lire le chiffre dans le rond et si on n'arrive pas à le lire alors c'est que c'est une lettre et on sait que le nombre de tours est donc de 0. -Maintenant vient le moment très sympatique de la lecture du chiffre. +Maintenant vient le moment très sympathique de la lecture du chiffre. -Vous saurez que Tesseract en plus de detester les grandes images et les images avec des couleurs, deteste également les formes dans une image. Donc dans notre cas, le round de couleur autour du chiffre, même si il n'est pas complet, il interfère avec la reconnaissance et empêche de bien lire le chiffre. +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. -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 donc retirer le background AUTOUR du rond, et ensuite si on retire la couleur il devrait rester le chiffre sur fond blanc. +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. -Pour se 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 : +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 : !["Zone pneu avec le background en moins"](./Images/Screens/TyreZoneCropedWithoutBackGround.png) -Ensuite on peu retirer les pixels qui ont une valeur dans un channel RGB plus haute qu'un certain seuil : +Ensuite, on peut retirer les pixels qui ont une valeur dans un channel RGB plus haute qu'un certain seuil : -!["Zone avec le reste des couleurs supprimmées"](./Images/Screens/TyreZoneFilter1.png) +!["Zone avec le reste des couleurs supprimées"](./Images/Screens/TyreZoneFilter1.png) -Et la on a ce que l'on veut ! +Et là, on a ce que l'on veut ! -A partir de la c'est les filtres que l'on connait qui sont utilisés pour en faire une image plus facile à utiliser par Tesseract. +À 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. -1 : On effectue un *Resize* 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. +1 : On effectue un *Resize* 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. !["Filtre 1"](./Images/Screens/TyreZoneFilter2.png) -2: On fait une *Dilatation* de facteur 1 pour retirer tout le flou de l'image pour aider Tesseract +2 : On fait une *Dilatation* de facteur 1 pour retirer tout le flou de l'image pour aider Tesseract !["Resultat"](./Images/Screens/TyreZoneAfter.png) Et on a un chiffre qui est utilisable par Tesseract ! -*Explication des methodes précises plus bas* +*Explication des méthodes précises plus bas* Pour résumer : @@ -1667,44 +1664,44 @@ Pour résumer : ###### DRS -Bon ca c'était plutôt simple j'ai simplement vérifié si la moyenne de vert dépassait une certaine valeur et puis voila. +Bon ça, c'était plutôt simple, j'ai simplement vérifié si la moyenne de vert dépassait une certaine valeur et puis voila. -###### Filtres et methodes sur les images +###### Filtres et méthodes sur les images -Dans ce projet on a du utiliser différentes methodes d'édition d'image que ce soit sous forme de filtres ou de modification de l'image directement. -Voici un sommaire des methodes utilisées et comment elles fonctionnent. +Dans ce projet, on a dû utiliser différentes méthodes d'édition d'image, que ce soit sous forme de filtres ou de modification de l'image directement. +Voici un sommaire des méthodes utilisées et comment elles fonctionnent. *Tresholding* -Cette methode sert à passer d'une image en couleurs à une image binaire noir blanc. +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. Un exemple ici : !["Exemple treshold"](./Images/Photos/TresholdExemple1.webp) -Le fonctionnement est assez simple mais il peut être fait de différentes manières mais dans mon cas voici comment l'algorythme fonctionne sachant qu'il demande en entrée la Bitmap que l'on veut modifier ainsi que la valeur de Treshold : +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 : -1. On parcours chaque pixel de l'image -2. On convertir la couleur du pixel en une valeur de gris pour avoir la même valeur en R,G et B (Formule utilisée : grey = R x 0.3 + G x 0.59 + B x 0.11) -3. Si le résultat de la valeur de gris est au dessus de la valeur de treshold, le pixel est passé en blanc complet et dans le cas contraire il est passé en noir complet +1. On parcourt chaque pixel de l'image +2. On convertit la couleur du pixel en une valeur de gris pour avoir la même valeur en R,G et B (Formule utilisée : gray = R x 0.3 + G x 0.59 + B x 0.11) +3. Si le résultat de la valeur de gris est au-dessus de la valeur de treshold, le pixel est passé en blanc complet et dans le cas contraire, il est passé en noir complet. 4. On retourne la Bitmap modifiée -Un algorythme pas forcément complexe mais qui peut augmenter de manière titanesque les chances de réussir une OCR +Un algorithme pas forcément complexe, mais qui peut augmenter de manière titanesque les chances de réussir une OCR *Resize* -Cette methode sert à augmenter la résolution d'une image pour améliorer la précision de l'algorythme de Tesseract. En effet, avec trop peu de pixels, la matrice de convolution n'est pas toujours aussi efficace. +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. -Il ne faut pas confondre cette methode d'augmentation de la taille avec une simple interpolation. En effet une augmentation de taille interpolée ne vas pas vraiment changer la résolution, l'image sera toujours aussi pixelisée, seulement, les pixels seront composées de plus de pixels comme dans l'exemple ci dessous : +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 : !["Exemple d'interpolation linéaire"](./Images/Photos/InterpolationExemple.png) -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 details mais en ajoutant du flou. +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. !["Exemple des différents types d'interpolation"](./Images/Photos/BicubicExample.png) -Le but est d'aller chercher dans les pixels alentours les couleurs qui sont déja présente 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 detail. +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. Voici un exemple assez parlant : @@ -1712,33 +1709,33 @@ Voici un exemple assez parlant : !["Exemple interpolation bicubique (après)"](./Images/Photos/BicubicExample2.webp) -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. +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. Mais il est possible de réduire ce flou avec d'autres méthodes également. -(Dans mon code je n'ai pas utilisé du code fait main mais j'utilise une librairie qui me permet de le faire) +(Dans mon code, je n'ai pas utilisé du code fait main, mais j'utilise une librairie qui me permet de le faire) -Il faut simplement faire attention car c'est un procédé assez lourd en performances. +Il faut simplement faire attention, car c'est un procédé assez lourd en performances. -*Dilatation* et *Erosion* +*Dilatation* et *Érosion* -Cette methode et la suivante font partie des methodes de transformation morphologiques. +Cette méthode et la suivante font partie des méthodes de transformation morphologiques. -Ces methodes sont utilisées pour accentuer les formes et les epaissir ou les réduire et les affiner. Elles possèdent l'aventage également de retirer le flou d'une image ce qui est très pratique si utilisé après l'utilisation de methodes comme *Resize*. +Ces méthodes sont utilisées pour accentuer les formes et les épaissir ou les réduire et les affiner. Elles possèdent l'aventage aussi de retirer le flou d'une image ce qui est très pratique si utilisé après l'utilisation de méthodes comme *Resize*. -Je ne vais pas trop rentrer dans les détails de ces methodes car leur fonctionnement est un peu plus lourd en math si on veut faire une véritable explication du pourquoi et du comment ca marche aussi bien. Pour notre projet je dirais que l'important est de savoir que ce sont deux outils très pratiques pour changer la morphologie des lettres et des chiffres et qu'on peut les utiliser pour corriger du flou et/ou des artéfacts apparus lors de la binarisation de l'image ou de la suppression de fond. +Je ne vais pas trop rentrer dans les détails de ces méthodes, car leur fonctionnement est un peu plus lourd en math si on veut faire une véritable explication du pourquoi et du comment ça marche aussi bien. Pour notre projet, je dirais que l'important est de savoir que ce sont deux outils très pratiques pour changer la morphologie des lettres et des chiffres et qu'on peut les utiliser pour corriger du flou et/ou des artéfacts apparus lors de la binarisation de l'image ou de la suppression de fond. *Remove Background* -Cette methode est assez simple et est juste une methode qui va passer en revue tous les pixels de l'image et si la couleur d'un pixel s'apparente à celle d'un pixel de fond il est passé en noir total ou en blanc total. Le but est de permettre au reste du programme de fonctionner avec des couleurs moins ambigues. +Cette méthode est assez simple et est juste une méthode qui va passer en revue tous les pixels de l'image et si la couleur d'un pixel s'apparente à celle d'un pixel de fond, il est passé en noir total ou en blanc total. Le but est de permettre au reste du programme de fonctionner avec des couleurs moins ambiguës. -Une variante spécialisée pour la reconnaissance des pneus appelée affectueusement *Remove Useless* cherche à atteindre le même bu mais est bien plus soffistiquée et spécialisée pour retirer le background autour d'un cercle de couleur pour ensuite retirer la couleur et qu'il ne reste qu'un chiffre. Pour plus de details voir la detection de pneus. +Une variante spécialisée pour la reconnaissance des pneus appelée affectueusement *Remove Useless* cherche à atteindre le même bu, mais est bien plus sophistiquée et spécialisée pour retirer le background autour d'un cercle de couleur pour ensuite retirer la couleur et qu'il ne reste qu'un chiffre. Pour plus de détails, voir la détection de pneus. -Il y aussi d'autre methodes comme un filtre Gaussien ou *Highlight countour* que j'ai du développer mais que je n'ai pas utilisé donc je ne vais pas en parler ici. +Il y a aussi d'autres méthodes comme un filtre Gaussien ou *Highlight countour* que j'ai dû développer, mais que je n'ai pas utilisé donc je ne vais pas en parler ici. ###### Petit point résolution -Comme on peut l'imaginer la résolution est extrêmement importante pour l'OCR. Et en avancant 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. +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. Quelques exemples pour se faire une idée @@ -1748,64 +1745,64 @@ Quelques exemples pour se faire une idée !["Echantillon 4K"](./Images/Screens/F1TVHIGHERRES.png) -Mais il faut savoir que grâce à cette simplification j'ai pu aussi créer d'autres methodes de filtrage pour certaines parties. Mais la simplification était obligatoire car avec des images aussi grande il n'était simplement pas possible de venir appliquer les mêmes filtres car le temps de traitement serait beaucoup plus long. +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. 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é. -Dans la version actuellement disponible la reconnaissance a été simplifiée sous cette forme : +Dans la version actuellement disponible, la reconnaissance a été simplifiée sous cette forme : - Le "GapToLeader" est décodé avec un premier passage de *Tresholding* à 165 puis un *Resize* de 2 et une *Dilatation* de 1 pour retirer le flou -- Les "Sectors" sont décodés en utilisant une toute nouvelle methode *VanishOxyAction* à cause des couleurs parfois appliquées et ensuite simplement une methode de *Tresholding* de 150 pour rendre le résultat assez propre pour l'OCR. -- Le "LapTime" est dabord passé par un *Tresholding* très strict de 185 pour préparer la *SobelEdgeDetection* qui est également une nouvelle methode qu'il a été possible d'utiliser grâce à la simplification du reste des processus. -- Le "Text" est décodé simplement avec un tresholding de 165 maintenant grâce à l'image 4K. +- Les "Sectors" sont décodés en utilisant une toute nouvelle méthode *VanishOxyAction* à cause des couleurs parfois appliquées et ensuite simplement une methode de *Tresholding* de 150 pour rendre le résultat assez propre pour l'OCR. +- Le "LapTime" est d'abord passé par un *Tresholding* très strict de 185 pour préparer la *SobelEdgeDetection* qui est également une nouvelle méthode qu'il a été possible d'utiliser grâce à la simplification du reste des processus. +- Le "Text" est décodé juste avec un tresholding de 165 désormais grâce à l'image 4K. - Les pneus ont leur propre traitement comme expliqué plus haut auquel on ajoute la *Dilatation* de 1. -Comme on peut le voir le traitement est pas mal plus simple mais cela ne veut pas dire que les autres methodes que je n'utilise plus ne sont pas utiles. La reconnaissance n'est pas encore parfaite et je pense que leur utilisation pourrait aider à améliorer les résultats. (Et parfois ces anciennes methodes sont utiles dans les traitements personnalisés des windows elle mêmes comme par exemple les pneus qui utilisent la methode *GrayScale* pour isoler les couleurs) +Comme on peut le voir, le traitement est pas mal plus simple, mais cela ne veut pas dire que les autres méthodes que je n'utilise plus ne sont pas utiles. La reconnaissance n'est pas encore parfaite et je pense que leur utilisation pourrait aider à améliorer les résultats. (Et parfois ces anciennes méthodes sont utiles dans les traitements personnalisés des Windows elle même comme par exemple les pneus qui utilisent la méthode *GrayScale* pour isoler les couleurs) *VanishOxyAction* -Cette methode est une methode plutôt simple mais qui est importante. Elle se base beaucoup sur le code de la methode *Grayscale* et sur la methode *Tresholding* car elle essaie de regrouper le meilleur des deux en règlant quelques soucis que ces dernières crééent. +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 *Grayscale* et sur la méthode *Tresholding* car elle essaie de regrouper le meilleur dès deux en réglant quelques soucis que ces dernières créaient. -Le soucis avec la methode grayscale c'est que quand le texte est de couleur (Ce qui arrive souvent pour les temps de secteurs) la methode *GrayScale* rend les couleurs dans une nuance de gris un peu trop sombre ce qui fait que ensuite la methode de *Tresholding* défonce tout. +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 *GrayScale* rend les couleurs dans une nuance de gris un peu trop sombre ce qui fait qu'ensuite la méthode de *Tresholding* défonce tout. !["Exemple de secteur en couleur"](./Images/Screens/VanishRaw.png) !["Exemple de secteur en grayscale"](./Images/Screens/VanishGrayScale.png) -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 methode de *Tresholding* sans soucis. +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 *Tresholding* sans soucis. !["Exemple de secteur blanchi avec vanishoxyAction"](./Images/Screens/VanishVanish.png) *SobelEdgeDetection* -On pourrait se dire que avec ce genre de methode le tresholding est inutile ensuite mais ca n'est pas le cas car le tresholding sert ensuite pour rendre les contours plus ou moins aggressif. Car même si l'image ressemble à une image binarisée, il reste des nuances que le treshold va pouvoir utiliser. +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. *SobelEdgeDetection* -Cette methode est une methode assez classique que je n'ai pas designé moi même alors je ne vais pas trop m'épancher dessus. +Cette méthode est une méthode assez classique que je n'ai pas designé moi-même alors, je ne vais pas trop m'épancher dessus. -En gros on utilise une matrice et une formule mathématique pour redessiner une image et le résultat est une image avec des contours. Je ne l'ai utilisé que pour les temps au tour car ce sont les plus récalcitrants. +En gros, on utilise une matrice et une formule mathématique pour redessiner une image et le résultat est une image avec des contours. Je ne l'ai utilisé que pour les temps au tour, car ce sont les plus récalcitrants. -Cette methode a besoin d'une image passée en noir et blanc au préalable à laquelle on applique ensuite les matrrices de filtres. Et avec ces filtres ajoutés à l'image on peut ensuite calculer le "Gradient" pour créer les bords. +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. -Le seul soucis de cette methode c'est qu'elle est assez gourmande et qu'elle fournit des formes creuses dû à la nature des matrices données. +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. Voici un exemple de ce dont cette méthode est capable : -![Artefacts de la detection de bords de Sobel](./Images/Screens/SobelArtefacts.png) +![Artefacts de la détection de bords de Sobel](./Images/Screens/SobelArtefacts.png) -Apparemment l'OCR aime assez bien cette methode et elle permet de beaucoup moins souvent oublier les '.' ou ':' +Apparemment l'OCR aime assez bien cette méthode et elle permet de beaucoup moins souvent oublier les '.' ou ':' ### Traitement des données -C'est bien gentil de recevoir des résultats de l'OCR, cependant on ne peut pas souvent les utiliser comme tels. En effet les resultats ne sont pas très constants et demandent d'être verifiés pour savoir si ils doivent être pris en compte. +C'est bien gentil de recevoir des résultats de l'OCR, cependant on ne peut pas souvent les utiliser comme tels. En effet, les résultats ne sont pas très constants et demandent d'être vérifiés pour savoir s'ils doivent être pris en compte. -Le post traitement de ces données dépend complêtement du contexte et donc il est différent pour chque type de window. +Le post traitement de ces données dépend complètement du contexte et donc il est différent pour chaque type de window. Voici un florilège des différents types de traitements : - Traitement du nom de pilote -Rien de plus que ce qui est déja détaillé dans la partie OCR +Rien de plus que ce qui est déjà détaillé dans la partie OCR - Traitement des pneus @@ -1813,42 +1810,42 @@ Pareil - Traitement des temps -La par contre c'est intéressant. Dans un monde parfait je pourrais simplement prendre les résultats de l'OCR et les traiter directement. Mais comme nous vivons dans un monde ou la souffrance et la douleur sont les seules choses autorisées on ne peut pas. +Là, par contre, c'est intéressant. Dans un monde parfait, je pourrais simplement prendre les résultats de l'OCR et les traiter directement. Mais comme nous vivons dans un monde ou la souffrance et la douleur sont les seules choses autorisées, on ne peut pas. -Le problème vient du fait que les temps que l'on peut trouver sur la F1TV sont encodés avec des '.' et des ':' qui determinent les limites entre les chiffres qui désignent les minutes, les secondes et les milisecondes. Et le soucis avec ces séparateurs c'est qu'ils aiment bien mettre le chaos dans la reconnaissance. Quand ils ne sont pas compris comme des autres chiffres ils sont parfois simplement oubliés ou pris en double c'est un enfer. +Le problème vient du fait que les temps que l'on peut trouver sur la F1TV sont encodés avec des '.' et des ':' qui déterminent les limites entre les chiffres qui désignent les minutes, les secondes et les millisecondes. Et le souci avec ces séparateurs, c'est qu'ils aiment bien mettre le chaos dans la reconnaissance. Quand ils ne sont pas compris comme des autres chiffres, ils sont parfois juste oubliés ou pris en double, c'est un enfer. -Il faut donc trouver un moyen de detecter quand cela arrive. Et je n'ai pas trouvé de meilleur moyen que de faire du cas par cas. +Il faut donc trouver un moyen de détecter quand cela arrive. Et je n'ai pas trouvé de meilleurs moyens que de faire du cas par cas. -Cela peut paraître simple quand on parle par exemple des secteurs. On sasit que on attend deux chiffres avant un '.' et trois chiffres après. Il est donc facile de voir que si je trouve six chiffres et pas de séparation le troisième est le séparateur mal compris. +Cela peut paraître simple quand on parle par exemple des secteurs. On sait qu'on attend deux chiffres avant un '.' et trois chiffres après. Il est ainsi facile de voir que si je trouve six chiffres et pas de séparation, le troisième est le séparateur mal compris. -Mais l'exemple qui détruit vraiment tout c'est 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 ca peut être 0.345 comme 1:12.345. Ce qui fait que quand je 121345 est-ce que c'est 12.345 ou 1:21.345...? +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...? -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. +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. -On pourrait se dire qu'il suffit de voir si la valeur est trop en dehors des normes. Le soucis c'est que il n'est pas impossible que 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. +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. !["Exemple temps au tour"](./Images/Screens/ExempleLapTimeBefore.png) !["Exemple temps secteur"](./Images/Screens/VanishRaw.png) -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 detection est parfaite, mais par ce que la detection ne peut pas rater de 200 facons. 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 +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 ### Stockage des données -Dans ce projet le but n'est pas simplement de trouver les données et les afficher. L'intérêt de les récupèrer est de pouvoir les comparer à d'autres données précédentes. +Dans ce projet, le but n'est pas simplement de trouver les données et les afficher. L'intérêt de les récupérer est de pouvoir les comparer à d'autres données précédentes. -Le vrai soucis de la F1TV c'est justement que l'on ne peut pas facilement voir les évolutions. On ne peut voir que des "photos" de la situation actuelle de la course. +Le vrai souci de la F1TV c'est justement que l'on ne peut pas facilement voir les évolutions. On ne peut voir que des "photos" de la situation actuelle de la course. -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 soucis avec ca c'est que même si des outils comme LinQ existent, ca n'est pas le plus pratique quand on veut faire des recherches complexes. +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. -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 predictions et des insertions de stats beaucoup plus intéressantes qui demandent de faire des requêtes complexe rapidement. +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. -Je me suis dit que la meilleure methode serait d'avoir une base de donnée dans laquelle je peux faire des requètes SQL. Mais commme je n'ai pas besoin de toutes les features de SQl et que je ne veut 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. +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. -!["Logo Sqlite"](./Images/Photos/SQLite_Logo.png); +!["Logo SQLite"](./Images/Photos/SQLite_Logo.png); -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 aventages de rapidité et d'utilisation de requetes SQl. +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. -J'ai créé trois tables dans cette base de donnée SQLITE que voici : +J'ai créé trois tables dans cette base de donnée SQLite que voici : #### Base de donnée @@ -1883,36 +1880,36 @@ Stats La table Drivers sert juste à stocker les différents noms de pilote pour qu'ils soient utilisés dans le reste de la DB -La table Pitstops n'est pas vraiment utilisée dans l'état actuel du projet. Mais le but était de la remplir dès que le programme détectais un arrêt aux stands. Le but est ensuite de pouvoir construire un classement pondèré en fonction des arrêts des différents pilotes et d'afficher la stats tout le temps sur l'affichage principal. -Elle n'est pas vraiment utilisée car la detection de pitstop n'a pas pu être commplêtée. De par la nature des données récupèrées des pneus et des positions, c'est très difficile de detecter avec prescision un arrêt aux stands. +La table Pitstops n'est pas vraiment utilisée dans l'état actuel du projet. Mais le but était de la remplir dès que le programme détectait un arrêt aux stands. Le but est ensuite de pouvoir construire un classement pondéré en fonction des arrêts des différents pilotes et d'afficher la stats tout le temps sur l'affichage principal. +Elle n'est pas réellement utilisée, car la détection de pitstop n'a pas pu être complétée. De par la nature des données récupérées des pneus et des positions, c'est très difficile de détecter avec précision un arrêt aux stands. -La table Stats est la plus importante car elle contient toutes les informations concernant les pilotes à chaque tour. L'idée est qu'elle soit remplie à chaque tour. Les infos ne sont pas scensée être les infos live mais plutôt juste une photo à chaque tour de la situation de chaque pilote pour ensuite pouvoir faire des commparaisons tourspar tours. Des données comme le GapToLeader peuvent évoluer pendant le tour mais on s'en fiche. Ce qui compte vraiment c'est le temps au tour et les secteurs ainsi que les pneus. +La table Stats est la plus importante parce qu'elle contient toutes les informations concernant les pilotes à chaque tour. L'idée est qu'elle soit remplie à chaque tour. Les infos ne sont pas censées être les infos lives, mais plutôt juste une photo à chaque tour de la situation de chaque pilote pour ensuite pouvoir faire des comparaisons tours par tours. Des données comme le GapToLeader peuvent évoluer pendant le tour, mais on s'en fiche. Ce qui compte vraiment, c'est le temps au tour et les secteurs ainsi que les pneus. #### Quand remplir la base ? -Dans ce projet il y a deux type d'information. Les informations live qui sont stockées dans des listes et les informations long terme qui sont stockées dans la DB. +Dans ce projet, il y a deux types d'information. Les informations lives qui sont stockés dans des listes et les informations long terme qui sont stockées dans la DB. -A chaque itération de l'OCR, les données récupèrées sont stockées dans une liste de DRIVERDATA. +À chaque itération de l'OCR, les données récupérées sont stockées dans une liste de DRIVERDATA. -Les DRIVERDATA sont des structures de données qui contiennent toutes les infos d'un pilote à un instant T. Elles peuvent être incomplêtes et sont juste la pour faire de petits calculs et determiner quand insèrer des données permanentes. +Les DRIVERDATA sont des structures de données qui contiennent toutes les infos d'un pilote à un instant T. Elles peuvent être incomplètes et sont juste là pour faire de petits calculs et déterminer quand insérer des données permanentes. -Ce qui nous amène au moment intéressant. Comment on détermine quand il est intéressant d'insèrer des informations dans la base de données. +Ce qui nous amène au moment intéressant. Comment on détermine quand il est intéressant d'insérer des informations dans la base de données. -Il y a deux cas de figure ou on pourrait vouloir insèrer des infos : +Il y a deux cas de figure ou on pourrait vouloir insérer des infos : -##### Quand un pilote a finit un tour +##### Quand un pilote a fini un tour -En effet, j'ai estimé que les seuls moments ou on veut garder une photo de la situation du pilote c'est quand il passe d'un tour à l'autre. +En effet, j'ai estimé que les seuls moments où on veut garder une photo de la situation du pilote, c'est, car il passe d'un tour à l'autre. Le raisonnement est le suivant : -On ne veut pas conserver TOUTES les données car si on prend une phot toutes les trois secondes, la majorité des informations seront redondantes avec les précédentes. -Mais en même temps il ne faut pas rater des changements importants de données. +On ne veut pas conserver TOUTES les données parce que si on prend une photo toutes les trois secondes, la majorité des informations seront redondantes avec les précédentes. +Mais en même temps, il ne faut pas rater des changements importants de données. Les seules données qui changent entre deux passages de l'OCR sont les écarts entre les pilotes et de temps en temps un nouveau secteur s'affiche. Alors que d'un tour à l'autre presque toutes les informations changent. Et on ne perd que les légères fluctuations des écarts entre les pilotes. J'ai donc décidé de conserver une photo par tour. Mais c'est bien joli sauf qu'il reste une difficulté : Comment savoir qu'un pilote a fait son tour ? -Cela peut paraître simple comme question mais elle est plus difficile qu'il n'y parait. Il faut savoir que en F1 un pilote peut être dans son 26ème tour pendant qu'un autre en est à son 24ème. Chaque pilote a sa propre course et au fur et à mesure que les écarts se creusent il peut y avoir un tour voir plusieurs d'écart entre la queue de course et les premiers pilotes. +Cela peut paraître simple comme question, mais elle est plus difficile qu'il n'y parait. Il faut savoir qu'en F1 un pilote peut être dans son 26ᵉ tour pendant qu'un autre en est à son 24ᵉ. Chaque pilote a sa propre course et au fur et à mesure que les écarts se creusent, il peut y avoir un tour voir plusieurs d'écart entre la queue de course et les premiers pilotes. -Ensuite il faut savoir qu'il n'est pas marqué sur la f1TV dans quel tour chaque pilote est. Il faut donc le déduire en fonction des Data. +Ensuite, il faut savoir qu'il n'est pas marqué sur la f1TV dans quel tour chaque pilote est. Il faut donc le déduire en fonction des Data. Voici le code le if qui détecte un nouveau tour @@ -1967,7 +1964,7 @@ Le soucis c'est que ce n'est pas rare que l'OCR nous retourne qu'un pneu est vie Si on veut utiliser cette methode pour trouver les Pitstop il va falloir avant tout améliorer l'OCR sur ce point. -Ce soucis mets en lumière un principe assez important de l'informatique "Ggarbage in, Garbage out". Si les données que je recoit ne sont pas géniales, le résultat ne sera pas génial non plus. Ce qui est frustrant c'est que la detection des pneus n'est pas si mal mais entre les chiffres qui se chevauchent ce qui nous fait lire 0 alors que c'est juste un un '1' derrière un 'H' ou le 1% du temps ou le programme se trompe, on ne peut pour l'instant tout simplement rien faire de mieux. +Ce soucis mets en lumière un principe assez important de l'informatique "Ggarbage in, Garbage out". Si les données que je recoit ne sont pas géniales, le résultat ne sera pas génial non plus. Ce qui est frustran,t c'est que la detection des pneus n'est pas si mal mais entre les chiffres qui se chevauchent ce qui nous fait lire 0 alors que c'est juste un un '1' derrière un 'H' ou le 1% du temps ou le programme se trompe, on ne peut pour l'instant tout simplement rien faire de mieux. ### Affichage des données @@ -2199,88 +2196,88 @@ Tout le code supplémentaire qui ne fait pas partie des étapes citées est just !["Exemple d'échantillons pour les tests"](./Images/Screens/DataSetGaps.png) -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 que 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. +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. -Si j'avais eu plus de temps j'aurais sûrement pu ajouter de vrais tests unitaires qui testent des fonctions très précises. Par exemple verifier que les différentes Windows sont bien appelées et que les zones se créent correctement ou même plus simplement que la lecture du JSON au démarrage marche bien. +Si j'avais eu plus de temps, j'aurais sûrement pu ajouter de vrais tests unitaires qui testent des fonctions très précises. Par exemple, vérifier que les différents Windows sont bien appelées et que les zones se créent correctement ou même plus simplement que la lecture du JSON au démarrage marche bien. -Il faut savoir que même si je n'ai pas eu l'occasion d'écrire beaucoup de tests sous forme de code. Toute la phase de développement de l'OCR j'ai passé plus d'une heure par jour à analyser les résultats. Je gardais toutes les images des WINDOWS et je notais dans le nom du fichier ce que l'algorythme trouvais et je passais en revue manuellement les centaines de résultats pour isoler ceux qui posaient problème. +Il faut savoir que même si je n'ai pas eu l'occasion d'écrire beaucoup de tests sous forme de code. Toute la phase de développement de l'OCR, j'ai passé plus d'une heure par jour à analyser les résultats. Je gardais toutes les images des WINDOWS et je notais dans le nom du fichier ce que l'algorithme trouvait et je passais en revue manuellement les centaines de résultats pour isoler ceux qui posaient un problème. -C'est comme ca que je me suis rendu compte par exemple que, avec cette police, les 4 et les 1 étaient souvent confondus. Donc même si les tests automatisés sont clairement insuffisant par rapport à ce que j'aurais peut-être du faire, j'ai passé énormément de temps à tester mon application. +C'est comme ça que je me suis rendu compte par exemple que, avec cette police, les quatre et les 1 étaient souvent confondus. Donc même si les tests automatisés sont clairement insuffisants par rapport à ce que j'aurais peut-être dû faire, j'ai passé énormément de temps à tester mon application. -### Comment ca aurait du se passer +### Comment ç'aurait dû se passer -Si je devais refaire ce projet aujourd'hui je pense que j'utiliserais un peu la même technique que pour la doc. J'aurais mis les tâches de Tests directement au début du projet et j'aurais determiné le squelette de l'application par la même occasion. +Si je devais refaire ce projet aujourd'hui, je pense que j'utiliserais un peu la même technique que pour la doc. J'aurais mis les tâches de Tests directement au début du projet et j'aurais déterminé le squelette de l'application par la même occasion. -Je pense que j'aurais mis trois jours pour écrire tous les tests dont j'aurais besoin et j'aurais fait une stratégie de TDD (Test Driven Developpement) par ce que je pense que ca marcherait vraiment super bien sur ce type de projet. +Je pense que j'aurais mis trois jours pour écrire tous les tests dont j'aurais besoin et j'aurais fait une stratégie de TDD (Test Driven Developpement) par ce que je pense que ça marcherait vraiment super bien sur ce type de projet. -J'aurais pris je pense 5 une dixaine d'images complêtes de la F1TV de plusieurs GP différents et j'aurais mis toutes les fenêtres découpées dans des fichiers avec des tests comme ceux que j'ai fait pour ce projet. Et comme ca je saurai que mon algo est bon uniquement quand il aura réussi à passer tous les tests. +J'aurais pris, je pense, cinq une dizaine d'images complètes de la F1TV de plusieurs GP différents et j'aurais mis toutes les fenêtres découpées dans des fichiers avec des tests comme ceux que j'ai faits pour ce projet. Et comme ça je saurai que mon algo est bon uniquement quand il aura réussi à passer tous les tests. -Cela règlerait le soucis que j'ai eu le plus : Me retrouver à devoir changer l'OCR 5 fois par ce que à chaque fois que je développe une nouvelle feature je me rends compte d'une faiblesse mon algorythme... +Cela règlerait le souci que j'ai eu le plus : Me retrouver à devoir changer l'OCR 5 fois par ce qu'à chaque fois que je développe une nouvelle feature, je me rends compte d'une faiblesse, mon algorithme… -Non seulement j'aurai eu beaucoup plus de facilité à avancer sur le projet, mais en plus je pense que cela m'aurait fait gagner énormément de temps non seulement car je n'ai plus à tester tout à la main mais en plus par ce que ca veut dire que quand l'OCR passe les tests je n'ai plus jamais à m'en soucier. +Non seulement j'aurais eu beaucoup plus de facilité à avancer sur le projet, mais en plus, je pense que cela m'aurait fait gagner énormément de temps non seulement, car je n'ai plus à tester tout à la main, mais en plus par ce que ça veut dire que quand l'OCR passe les tests, je n'ai plus jamais à m'en soucier. -### Lecons +### Leçons -Je pense que dans mes futurs projets je mettrai les tests en début de projet plutôt que à la fin et je ferai en sorte qu'ils fassent partie du chemin critique et que je ne puisse pas passer à côté sous pretexte que "Je n'ai pas le temps". +Je pense que dans mes futurs projets, je mettrai les tests en début de projet plutôt qu'à la fin et je ferai en sorte qu'ils fassent partie du chemin critique et que je ne puisse pas passer à côté sous prétexte que "Je n'ai pas le temps". -Ecrire des tests c'est jamais marrant et c'est encore moins marrant quand ils nous empêchent d'avancer. Mais je suis convaincu que au final c'est un gain de temps et de sérénité incontournable. +Écrire des tests, ce n'est jamais marrant et c'est encore moins marrant quand ils nous empêchent d'avancer. Mais je suis convaincu qu'à la fin, c'est un gain de temps et de sérénité incontournable. ## Résumé des difficultés techniques ---- -Ici je vais parler très rapidement des difficultées techniques rencontrées. Si vous voulez tout savoir à propos des difficultées vous pouvez aller lire le journal de bord. C'est aussi pour éviter de me répèter par rapport aux explications des différents points dans l'analyse organique. +Ici, je vais parler très rapidement des difficultés techniques rencontrées. Si vous voulez tout savoir à propos des difficultés, vous pouvez aller lire le journal de bord. C'est aussi pour éviter de me répéter par rapport aux explications des différents points dans l'analyse organique. -Je vais pas non plus parler des difficultées rencontrée avec des choses que je n'ai pas gardé dans le programme final donc il est normal que vous vous disiez qu'il n'y a pas eu tant de difficultés que ca. +Je ne vais pas non plus parler des difficultés rencontré avec des choses que je n'ai pas gardées dans le programme final donc il est normal que vous vous disiez qu'il n'y a pas eu tant de difficultés que ça. ### Browser Headless -Il y avait plusieurs difficultées techniques avec cette histoire de Browser Headless. +Il y avait plusieurs difficultés techniques avec cette histoire de Browser Headless. -Deja pouvoir lancer un browser headless et le contrôler. C'est difficile car il faut trouver la bonne librairie et ensuite il faut trouver le bon exectuable de geckoDriver qui permette de faire fonctionner l'application même si l'utilisateur n'a pas Firefox sur sa machine. +Déjà pouvoir lancer un browser headless et le contrôler. C'est difficile, car il faut trouver la bonne librairie et ensuite, il faut trouver le bon exécutable de gecko Driver qui permette de faire fonctionner l'application même si l'utilisateur n'a pas Firefox sur sa machine. -Ensuite la seconde difficulté est celle de ne pas se faire chopper comme un bot par le site de la F1TV. Il faut savoir qu'à ce jour je n'ai toujours pas réussi à faire croire à la page de login de la F1TV que j'étais un user normal en utilisant Selnnium mais au moins maintenant je peux accèder aux vidéos tranquillement. +Ensuite, la seconde difficulté est celle de ne pas se faire chopper comme un bot par le site de la F1TV. Il faut savoir qu'à ce jour, je n'ai toujours pas réussi à faire croire à la page de login de la F1TV que j'étais un user normal en utilisant Sélénium mais au moins maintenant, je peux accéder aux vidéos tranquillement. -Ce soucis de ne pas pouvoir se connecter avec la page de login à la plus grosse difficulté technique de cette partie du projet : la connexion automatique. Pour me connecter à la F1TV avec un browser headless la seule solution que j'ai trouvé a été d'utiliser des cookies. Et pour que l'utilisateur n'aie pas à aller chercher les siens dans son navigateur il a fallut trouver une technique pour aller les chercher directement sans lui demander son avis. +Ce souci de ne pas pouvoir se connecter avec la page de login à la plus grosse difficulté technique de cette partie du projet : la connexion automatique. Pour me connecter à la F1TV avec un browser headless la seule solution que j'ai trouvée a été d'utiliser des cookies. Et pour que l'utilisateur n'ait pas à aller chercher les siens dans son navigateur, il a fallu trouver une technique pour aller les chercher directement sans lui demander son avis. -Autre difficutlé, comme on travaille avec un site web que l'on ne contrôle pas, il faut trouver un moyen de gèrer les erreurs et de réessayer parfois et attendre quand il faut dans les cas ou le chargement est long etc... +Autre difficulté, comme on travaille avec un site web que l'on ne contrôle pas, il faut trouver un moyen de gérer les erreurs et de réessayer parfois et attendre quand il faut dans les cas où le chargement est long etc... -Ensuite après tout ca la dernière difficulté a été de pouvoir contrôler le firefox Headless assez bien pour qu'il puisse non seulement naviguer les pages mais aussi qu'il puisse cliquer sur des boutons qui ne s'affichent pas tout le temps. +Ensuite, après tout ça, la dernière difficulté a été de pouvoir contrôler le Firefox Headless assez bien pour qu'il puisse non seulement naviguer les pages, mais aussi qu'il puisse cliquer sur des boutons qui ne s'affichent pas tout le temps. -(Je ne vais pas mentioner la difficulté que ca a été de mettre le browser en 4K pour des raison de santé mentale) +(Je ne vais pas mentionner la difficulté que c'était de mettre le browser en 4K pour des raisons de santé mentale) ### OCR -Les difficultées ici sont dans un autre niveau. Chaque type de donnée représentait sa difficulté à lui tout seul sans compter l'optimisation. +Les difficultés ici sont dans un autre niveau. Chaque type de donnée représentait sa difficulté à lui tout seul, sans compter l'optimisation. -Pour commencer on a le texte pour les noms de pilotes. Il a fallu trouver un système qui puisse reconnaitre le texte et qui puisse comparer le résultat avec les pilotes que l'on connait. +Pour commencer, on a le texte pour les noms de pilotes. Il a fallu trouver un système qui puisse reconnaitre le texte et qui puisse comparer le résultat avec les pilotes que l'on connait. -Ensuite il a fallu trouver un moyen de detecter la différence entre les fenêtres de DRS où il est ouvert ou fermé. Il fallait également faire attention à ne pas faire de faux positifs. +Ensuite, il a fallu trouver un moyen de détecter la différence entre les fenêtres de DRS où il est ouvert ou fermé. Il fallait également faire attention à ne pas faire de faux positifs. -Pour les temps par secteurs il a fallu trouver des filtres qui permettent de bien différencier les '1' et les '4' sans les confondre et il a aussi fallut trouver un moyen de filter l'image pour que dans le cas ou le texte serait en couleur ca fonctionne quand même. (Car oui un filtre de nuances de gris ne marche pas super avec des couleurs sombres) +Pour les temps par secteurs, il a fallu trouver des filtres qui permettent de bien différencier les '1' et les '4' sans les confondre et il a aussi fallu trouver un moyen de filtrer l'image pour que dans le cas où le texte serait en couleur ça fonctionne quand même. (Car oui, un filtre de nuances de gris ne marche pas super avec des couleurs sombres) -Pour les pneus (le plus dur) il a fallut trouver un moyen de trouver sur toute la longeur de la zone la partie intéressante. Ensuite il a fallut trouver une technique pour savoir quel type de pneu c'est en fonction de la couleur moyenne et ensuite le plus dur a été d'isoler le chiffre du dessin autour car Tesseract aime pas les formes, le tout automatiquement. +Pour les pneus (le plus dur) il a fallu trouver un moyen de trouver sur toute la longueur de la zone la partie intéressante. Ensuite, il a fallu trouver une technique pour savoir quel type de pneu c'est en fonction de la couleur moyenne et ensuite le plus dur a été d'isoler le chiffre du dessin autour, car Tesseract n'aime pas les formes, le tout automatiquement. -Pour les temps au tour il a fallut trouver un moyen de ne pas confondre les ponctuations avec des chiffres tout en ne les ratant pas. Et il a fallu trouver un moyen de detecter quand inévitablement cela arrive quand même. +Pour les temps au tour, il a fallu trouver un moyen de ne pas confondre les ponctuations avec des chiffres tout en ne les ratant pas. Et il a fallu trouver un moyen de détecter quand inévitablement cela arrive quand même. -Et la dernière difficulté (la plus pénible) a été de detecter les écarts entre les pilotes. Il a fallut trouver une facon de decoder le texte en temps mais aussi de faire tout un système qui détecte et règle les cas ou un ':' a été oublié ou confondu tout en ne sachant pas si il était scensé y en avoir à la base car les valeurs peuvent varier entre '1_23.657' et '0.452'. +Et la dernière difficulté (la plus pénible) a été de détecter les écarts entre les pilotes. Il a fallu trouver une façon de décoder le texte en temps, mais aussi de faire tout un système qui détecte et règle les cas ou un ':' a été oublié ou confondu tout en ne sachant pas s'il était censé y en avoir à la base, car les valeurs peuvent varier entre '1_23.657' et '0.452'. ### Stockage -Pour ce qui est du stockage la grande difficulté a été de savoir quand un pilote avait avait finit un tour car chaque pilote finit son tour à un moment différent. Il a également fallut trouver un moyen de savoir les données d'un pilote étaient logiques. +Pour ce qui est du stockage, la grande difficulté a été de savoir quand un pilote avait fini un tour parce que chaque pilote finit son tour à un moment différent. Il a également fallu trouver un moyen de savoir les données d'un pilote étaient logiques. -Une difficulté qui n'a pas été complêtement dépassée est de savoir quand un pilote a fait un arrêt aux stands car la detection de l'age des pneus est plus que mauvaise. +Une difficulté qui n'a pas été complètement dépassée est de savoir quand un pilote a fait un arrêt aux stands, car la détection de l'âge des pneus est plus que mauvaise. -Voila. Ce fut une petite liste non exhaustive de quelques difficultés techniques que j'ai rencontré pendant ce projet. +Voilà. Ce fut une petite liste non exhaustive de quelques difficultés techniques que j'ai rencontrées pendant ce projet. ## Optimisation du programme ---- -Ici je vais parler des techniques que j'ai utilisé pour réduire le temps de traitement de chaques images de 50 secondes à un peu moins de 3 sur le processeur de mon laptop. En effet, dans les premières version du projet, traiter l'intégralité d'une image pouvait prendre presque une minute. +Ici, je vais parler des techniques que j'ai utilisées pour réduire le temps de traitement de chaque image de 50 secondes à un peu moins de 3 sur le processeur de mon laptop. En effet, dans les premières versions du projet, traiter l'intégralité d'une image pouvait prendre presque une minute. -Ce qui est compliqué dans ce projet c'est qu'il y a un certain nombres de choses que je ne contrôle pas. En utilisant Tesseract, je me retrouve avec des incompressibles. En imaginant que l'OCR sur une image prenne 300ms, même si j'avais 180 threads capables de faire cette tâche en même temps, le temps de traitement sera toujours d'au moins 300ms. Créer une instance de Tesseract prend également du temps. Ma mission n'est donc pas d'arriver à des temps de quelques dixaines de milisecondes mais plutôt de rajouter le moins de temps possible pendant le traitement et de tenter de faire le plus du choses possible en paralelle. +Ce qui est compliqué dans ce projet, c'est qu'il y a un certain nombre de choses que je ne contrôle pas. En utilisant Tesseract, je me retrouve avec des incompressibles. En imaginant que l'OCR sur une image prenne 300 ms, même si j'avais 180 threads capables de faire cette tâche en même temps, le temps de traitement sera toujours d'au moins 300 ms. Créer une instance de Tesseract prend également du temps. Ma mission n'est donc pas d'arriver à des temps de quelques dizaines de millisecondes, mais plutôt de rajouter le moins de temps possible pendant le traitement et de tenter de faire le plus de choses possible en parallèle. Voici la liste des choses qui prennent du temps : @@ -2289,39 +2286,39 @@ Voici la liste des choses qui prennent du temps : - Filtrage des images - OCR -Ce sont les quatres gros postes qui coutent le plus cher en ressources. +Ce sont les quatre gros postes qui coutent le plus cher en ressources. -Mais par chance, deux de ces postes ne sont appelés qu'une seule fois au démarrage ce qui fait que ce n'est pas catastrophique si ils prennent du temps. Tandis que l'OCR et le filtrage est fait à chaque détection. +Mais par chance, deux de ces postes ne sont appelés qu'une seule fois au démarrage, ce qui fait que ce n'est pas catastrophique s'ils prennent du temps. Tandis que l'OCR et le filtrage est fait à chaque détection. -Pour ce qui est du démarrage malheureusment on ne peut pas faire grand chose. Lancer le browser et naviguer à travers la F1TV prend du temps surtout si la connection 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 malheureusment, c'est lent et on ne peut pas y faire grand chose. +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. -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 paralellisable), si on veut faire plusieurs reconnaissances à la foix 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. +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. -Vous qui lisez ces lignes êtes peut-être en train de vous dire "Oulala mais ca doit beaucoup de mémoire son truc la " et vous auriez parfaitement raison ! +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 ! !["Consommation de mémoire peu après avoir commencé la détection"](./Images/Screens/MemoryUtilisation.png) -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 Tessreact de loadé. +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é. -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. +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. -Je suis absolument certain que cette solution et les autres solutions que j'ai trouvé 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. +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. -Ensuite pour ce qui est de ce qui se passe à chaque boucle, la le mot magique c'est "Parallel". Le traitement de toutes les zones est fait en même temps. +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. -La structure du projet en zones, sous zones et fenêtres de données fait qu'il est assez facile de venir paralleliser le processus si on les implémente correctement. +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. -![Diagramme qui montre comment les zones et fenêtres intéragissent](./Images/Figma/ZonesStuctureDiagram.png) +![Diagramme qui montre comment les zones et fenêtres interagissent](./Images/Figma/ZonesStuctureDiagram.png) -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 chacunes ce qu'elles contiennent après un coup d'OCR et ensuite les zones recombinent les informations et les envoient à la zone principale. +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. -Tout cela est très bien mais quel rapport avec la paralellisation ? Et bien comme chaque zone de pilote est indépendante, on peut tout simplement faire une boucle for parallelle qui appèle toutes les zones pilotes. +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. -On passe de 15 à 20 secondes de traitement à un peu plus de 3 juste avec cette technique. Alors ca n'était pas facile à implémenter car il a fallu programmer les zones de sorte à ce 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 paralelliser. +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. -Les filtres fonctionnent de la même facon sauf que la on paralellise 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. +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. -Seul soucis avec cette methode, cela feut dire que le processeur est particulièrement solicité '^^... +Seul souci avec cette méthode, cela veut dire que le processeur est particulièrement sollicité '^^... !["Utilisation du processeur pendant le fonctionnement de l'application"](./Images/Screens/CPUUsage.png) @@ -2335,57 +2332,57 @@ Donc si je veux commenter la F1 avec cet outil, note à moi même, je ne dois pa Si je pouvais utiliser le GPU pour accèlérer le processus on pourrait peut-être avoir de meilleurs résultats mais de ce que j'ai pu lire, l'OCR n'est pas spécialement un bon use case pour les GPU. -Pour conclure, je dirais que ce projet est loin d'être un exemple de performances et clairement il y a des choix discutables qui ont été faits et d'une manière générale si je devais refaire tout le projet avec la performance en premier objectif, j'aurais sûrement fait différemment. Maintenant avec le temps que j'ai eu je suis déja content d'avoir pu faire quelque chose qui fonctionne et qui ne prenne pas une minute à traiter une image. +Pour conclure, je dirais que ce projet est loin d'être un exemple de performances et clairement, il y a des choix discutables qui ont été faits et d'une manière générale, si je devais refaire tout le projet avec la performance en premier objectif, j'aurais sûrement fait différemment. Maintenant, avec le temps que j'ai eu, je suis déjà content d'avoir pu faire quelque chose qui fonctionne et qui ne prenne pas une minute à traiter une image. ## Ethique du projet ---- -Ici on va parler des questions éthiques de ce projet. En effet, il y a quelques petites choses qui peuvent poser question. +Ici, on va parler des questions éthiques de ce projet. En effet, il y a quelques petites choses qui peuvent soulever une question. -Il y a deux questions qui reviennent presque à chaques fois que je parle ou présente mon projet : +Il y a deux questions qui reviennent presque à chaque fois que je parle ou présente mon projet : ### Utilisation abusive de la F1TV ? -La F1TV est un service payant qui n'est pas forcément donné (même si pas bien cher pour un utilisateur comme moi qui l'utilise plus d'une fois par semaine plusieurs heures). De ce fait, je ne peut pas rendre son accès plus facile ou faire fuiter des informations de courses que l'on ne peut se procurer que par son utilisation. +La F1TV est un service payant qui n'est pas forcément donné (même si pas bien cher pour un utilisateur comme moi qui l'utilise plus d'une fois par semaine plusieurs heures). De ce fait, je ne peux pas rendre son accès plus facile ou faire fuiter des informations de courses que l'on ne peut se procurer que par son utilisation. -Mais voila pourquoi je pense que mon utilisation n'est pas une utilisation abusive : +Mais voilà pourquoi je pense que mon utilisation n'est pas une utilisation abusive : - L'application ne fonctionne que si l'utilisateur a un compte F1TV valide et qu'il s'est connecté récemment sur sa machine. (Cela veut donc dire que je ne permets pas à des utilisateurs de frauder) -- L'application ne partage aucune information sur le contenu de la F1TV avec l'extérieur. (On peut pas avoir accès à des informations payantes sans abonnement) +- L'application ne partage aucune information sur le contenu de la F1TV avec l'extérieur. (On ne peut pas avoir accès à des informations payantes sans abonnement) - L'application ne simule qu'un seul utilisateur connecté sur une vraie machine (Cela veut donc dire que je ne suis pas en train de faire un système de bot qui regarde 45 flux en même temps pour scrapper tout le site et/ou poser des problèmes de DDOS) - Les données ne sont pas stockées entre les sessions (cela veut dire que l'on ne représente pas un risque de fuite de données et on n'est pas un service qui vient scrapper le contenu pour alimenter une IA ou quoi que ce soit... pour l'instant...) -En fait mon application fonctionne exactement comme si on avait une page ouverte avec la F1TV dessus et qu'un ami à coté de nous la regardait en prenant des notes pour nous aider à suivre. Je ne vois donc pas le mal et je ne vois pas en quoi ce projet serait problématique sur ce point. +En fait mon application fonctionne exactement comme si on avait une page ouverte avec la F1TV dessus et qu'un ami à côté de nous la regardait en prenant des notes pour nous aider à suivre. Je ne vois donc pas le mal et je ne vois pas en quoi ce projet serait problématique sur ce point. -Après dans le futur, le but est clairement de conserver les infos trouvées pour entrainer un algorythme de prédiction et la peut-être que cela pourrait poser plus de problèmes, mais ce n'est pas le cas à lheure ou j'écris ces lignes. +Après dans le futur, le but est clairement de conserver les infos trouvées pour entrainer un algorithme de prédiction et là peut-être que cela pourrait poser plus de problèmes, mais ce n'est pas le cas à l'heure ou j'écris ces lignes. ### Récupération de cookies à l'insu de l'utilisateur ? -Alors la on est clairement sur le sujet un peu plus épineux... +Alors là, on est clairement sur le sujet un peu plus épineux... -Un peu de contexte dabord : +Un peu de contexte d'abord : -A la base je voulais que l'utilisateur entre ses identifiants dans mon application et ensuite que le navigateur les rentre dans la page de login automatiquement et qu'il puisse se connecter. +À la base, je voulais que l'utilisateur entre ses identifiants dans mon application et ensuite que le navigateur les rentre dans la page de login automatiquement et qu'il puisse se connecter. Deux problèmes à cette solution : 1. L'utilisateur doit avoir assez confiance en mon programme pour laisser ses identifiants en clair à l'intérieur. -2. Il est extrêment difficile de bypass la protection contre les bots de la page de login de la F1TV. +2. Il est extrêmement difficile de bypass la protection contre les bots de la page de login de la F1TV. -J'ai donc du trouver une autre solution : Utiliser les cookies ! +J'ai donc dû trouver une autre solution : Utiliser les cookies ! -Le seul soucis c'est que cela voulait dire que l'utilisateur devait aller chercher lui même ses cookies dans le navigateur en utilisant F12 et qu'il devait à nouveau me faire confiance pour que je n'en fasse rien. Je trouvais cette solution trop pénible pour l'utilisateur alors j'ai décidé d'en trouver une autre. +Le seul souci, c'est que cela voulait dire que l'utilisateur devait aller chercher lui-même ses cookies dans le navigateur en utilisant F12 et qu'il devait à nouveau me faire confiance pour que je n'en fasse rien. Je trouvais cette solution trop pénible pour l'utilisateur alors, j'ai décidé d'en trouver une autre. Utiliser les cookies MAIS, sans demander à l'utilisateur. Pour faire simple, mon programme va directement décoder les cookies encryptés dans la base de donnée SQLITE de Chrome, va les stocker dans un CSV en clair et va laisser mon programme C# aller piocher ceux qui l'intéressent. -Soucis, mon programme a accès à tous les cookies de l'utilisateur à son insu cela veut dire que je pourrais les utiliser à des fins peu scrupuleuses. +Soucis, mon programme a accès à tous les cookies de l'utilisateur à son insu, cela veut dire que je pourrais les utiliser à des fins peu scrupuleuses. -Et c'est la solution que j'ai décidé de choisir car elle permet à l'utilisateur de ne rien avoir à faire pour se connecter depuis l'application mais cela veut asusi dire qu'il doit me faire confiance pour ne pas utiliser tous ces cookies pour mon utilisation personnelle. +Et c'est la solution que j'ai décidé de choisir, car elle permet à l'utilisateur de ne rien avoir à faire pour se connecter depuis l'application, mais cela veut aussi dire qu'il doit me faire confiance pour ne pas utiliser tous ces cookies pour mon utilisation personnelle. -Sauf que contrairement aux autres solutions il ne sait pas qu'il est en train de me faire confiance donc ca va :D +Sauf que contrairement aux autres solutions, il ne sait pas qu'il est en train de me faire confiance donc ça va. :D -Non plus sérieusement, oui je pourrais faire nimporte quoi avec les cookies de l'utilisateur, non je ne vais pas le faire, et non je ne prévois jamais de le faire. +Non plus sérieusement, oui, je pourrais faire n'importe quoi avec les cookies de l'utilisateur, non, je ne vais pas le faire, et non, je ne prévois jamais de le faire. 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. @@ -2395,61 +2392,61 @@ Mais il est intéressant de mentionner que mon application met en péril la séc !["Logo chat Gpt"](./Images/Screens/GPTLogo.png) -Cette année ChatGPT est venu s'installer dans la liste des outils que j'utilise presque quotidiennement pour avancer sur mes projets. +Cette année, ChatGPT est venu s'installer dans la liste des outils que j'utilise presque quotidiennement pour avancer sur mes projets. -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. +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. Je l'ai surtout utilisé quand j'avais de soucis avec des librairies ou pour faire du troubleshooting. Ce que j'aime beaucoup avec ChatGPT c'est qu'il s'adapte à ce qu'on lui donne. -Par exemple il m'est souvent arrivé de vouloir utiliser des librairies comme Puppeteer sharp ou des exemples sont difficilement trouvables sur internet normalement. Et quand je voulais simplement faire fonctionner un exemple très rapide, il a presque toujours pu me fournir le code minimum. Cependant dès que l'on arrive sur des cas encore plus précis on atteint assez vite les limites du système. +Par exemple, il m'est souvent arrivé de vouloir utiliser des librairies comme Puppeteer sharp ou des exemples sont difficilement trouvables sur internet normalement. Et quand je voulais simplement faire fonctionner un exemple très rapide, il a quasiment toujours pu me fournir le code minimum. Cependant, dès que l'on arrive sur des cas encore plus précis, on atteint assez vite les limites du système. -J'ai souvent fait appel à cet outil pour diagnostiquer du code, que ce soit pour detecter un soucis ou même plus simplement pour voir si mon code avait du sens. En effet, si on donne une methode à chatGPT il va tenter de l'expliquer, et si il n'y arrive pas, c'est souvent que les variables sont mal nommées ou qu'il y a un soucis avec la logique du code. Et pour ce qui est de la détection des erreurs, l'exemple que je peux donner c'est quand je faisais des methodes asynchrones et paralelles, je pouvais lui donner la methode avec l'erreur que je ne comprends pas et il peut me donner cinq raisons de possibles soucis. +J'ai fréquemment fait appel à cet outil pour diagnostiquer du code, que ce soit pour détecter un souci ou même plus juste pour voir si mon code avait du sens. En effet, si on donne une méthode à chatGPT, il va tenter de l'expliquer, et s'il n'y arrive pas, c'est généralement que les variables sont mal nommées ou qu'il y a un souci avec la logique du code. Et pour ce qui est de la détection des erreurs, l'exemple que je peux donner c'est quand je faisais des méthodes asynchrones et parallèles, je pouvais lui donner la méthode avec l'erreur que je ne comprends pas et il peut me donner cinq raisons de possibles soucis. -Cependant je pensais utiliser beaucoup plus ChatGpt mais au final l'outil est assez limité et je ne l'utilisais que quand mes recherches internet étaient infructueuses. +Cependant, je pensais utiliser beaucoup plus ChatGpt mais à la fin l'outil est assez limité et je ne l'utilisais que quand mes recherches internet étaient infructueuses. -Le seul cas ou il m'a un peu sauvé c'est quand je travaillais avec Puppeteer et que j'essayais de règler un soucis qui faisait que le programme plantait à chaque fois que j'ouvrais une vidéo. Au bout de quelques heures de galère il m'a juste proposé d'utiliser une autre librairie comme selenium et il m'a convertit tout mon code puppeteer en code utilisable par selenium, et même si cela a demandé un peu plus de travail que de copier coller, au final j'ai pu avoir quelque chose qui marchait et je n'aurais peut-être pas eu le reflexe ou l'envie de le faire si je n'avais pas utilisé cet outil. +Le seul cas où il m'a un peu sauvé, c'est quand je travaillais avec Puppeteer et que j'essayais de régler un souci qui faisait que le programme plantait à chaque fois que j'ouvrais une vidéo. Au bout de quelques heures de galère, il m'a juste proposé d'utiliser une autre librairie comme sélénium et il m'a converti tout mon code puppeteer en code utilisable par Selenium, et même si cela a demandé un peu plus de travail que de copier-coller, pour finir, j'ai pu avoir quelque chose qui marchait et je n'aurais peut-être pas eu le réflexe ou l'envie de le faire si je n'avais pas utilisé cet outil. -En conclusion, certaines methodes de mon projet ont été faites avec l'aide de chatGPT mais c'est une minorité et je l'ai surtout utilisé pour comprendre des erreurs et pour avoir des pistes à explorer pour les fix. Rien de bien fou. +En conclusion, certaines méthodes de mon projet ont été faites avec l'aide de ChatGPT mais c'est une minorité et je l'ai surtout utilisé pour comprendre des erreurs et pour avoir des pistes à explorer pour les fix. Rien de bien fou. ## Améliorations futures ---- -Ici je vais parler de deux types d'améliorations. les améliorations à court terme, que j'aurais pu faire si je n'avais pas perdu autant de temps sur certains problèmes techniques ou si j'avais eu quelques semaines de plus pour travailler sur le projet. Et les idées qui seraient plus compliquées à mettre en place que je n'aurais jamais pu ajouter à ce travail dans le temps imparti mais qui sont maintenant possibles si je continue pendant quelques mois à travailler sur le projet. +Ici, je vais parler de deux types d'améliorations. Les améliorations à court terme, que j'aurais pu faire si je n'avais pas perdu autant de temps sur certains problèmes techniques ou si j'avais eu quelques semaines de plus pour travailler sur le projet. Et les idées qui seraient plus compliquées à mettre en place que je n'aurais jamais pu ajouter à ce travail dans le temps imparti, mais qui sont maintenant possibles si je continue pendant quelques mois à travailler sur le projet. ### Court terme Je vais commencer par les petites améliorations. -1. Chose que je regrette le plus je dirais, c'est tout ce qui est affichage. J'aurais vraiment aimé faire une magnifique interface mais il m'a manqué de temps pour en faire une plus jolie et plus facile d'utilisation. -2. Une amélioration vraiment nescessaire serait d'améliorer la détection des pneus pour qu'il soit possible de corretement détecter les arrêts aux stands. -3. En général si j'avais pu mettre plus de temps dans l'analyse des données que je recois de la F1TV j'aurais pu faire un système plus efficace de detection de dépassements car la version actuelle n'est vraiment pas bonne. -4. Trouver un moyen de faire des erreurs plus précises. En effet maintenant certaines erreurs ont des causes qui peuvent être multiples (qui peuvent être causées par un mauvais lien, ou une erreur de récupération des cookies ou même juste de connection internet). Ca demanderait simplement un peu plus de temps pour qu'au lieu de retourner juste une erreur, on tente de récupérer plus d'infos pour la rendre plus spcécifique. +1. Chose que je regrette le plus, je dirai, c'est tout ce qui est affichage. J'aurais vraiment aimé faire une magnifique interface, mais il m'a manqué de temps pour en faire une plus jolie et plus facile d'utilisation. +2. Une amélioration réellement nécessaire serait d'améliorer la détection des pneus pour qu'il soit possible de correctement détecter les arrêts aux stands. +3. En général, si j'avais pu mettre plus de temps dans l'analyse des données que je reçois de la F1TV, j'aurais pu faire un système plus efficace de détection de dépassements, car la version actuelle n'est vraiment pas bonne. +4. Trouver un moyen de faire des erreurs plus précises. En effet, maintenant, certaines erreurs ont des causes qui peuvent être multiples (qui peuvent être causées par un mauvais lien, ou une erreur de récupération des cookies ou même juste de connexion internet). Ça demanderait simplement un peu plus de temps pour qu'au lieu de retourner seulement une erreur, on tente de récupérer plus d'infos pour la rendre plus spécifique. -Et pour les améliorations un peu plus concrêtes : +Et pour les améliorations un peu plus concrètes : -1. Implémenter plus d'affichages calculés. J'aurais aimé ajouter des affichages comme le classement pondéré des pilotes en fonction des arrêts aux stands. Cela demanderait simplement un peu de temps et d'améliorer la detection des pitstops. -2. Implémenter des affichages prédictifs simples. On pourrait imaginer des algorythmes simple qui pourraient tenter de prédire quand un pilote va en rattraper un autre ou quand un pilote va devoir s'arrêter en fonction des temps aux tours. Ca me demanderait pas de nouvelle technologies mais simplement du temps pour mettre en place et tester les algorythmes. -3. Faire un système qui puisse tester les algroythmes prédictifs sur un pannel de Grand Prix. Si l'étape d'avant est faite, on peut facilement imaginer un bout de programme qui aille tester le programme sur différents Grand Prix pour voir si les prédictions sont bonnes. -4. Avoir une notion d'historique des courses pour avoir une page de comparaison des perfromances des équipes. Par exemple déterminer quelle voiture est la plus rapide et comparer avec les autres circuit. On peut même imaginer qu'après plusieurs Grand Prix on puisse tenter de determiner quelle équipe est forte sur quel circuit. -5. Avoir un système qui permet de trouver automatiquement tous les liens de Grand Prix comme ca l'utilisateur n'aie plus besoin d'aller chercher un URL. -6. Faire un installer pour qu'un utilisateur n'aie pas à se taper la procédure d'installation (qui est assez pénible) à la main. +1. Implémenter plus d'affichages calculés. J'aurais aimé ajouter des affichages comme le classement pondéré des pilotes en fonction des arrêts aux stands. Cela demanderait juste un peu de temps et d'améliorer la détection des pitstops. +2. Implémenter des affichages prédictifs simples. On pourrait imaginer des algorithmes simple qui pourraient tenter de prédire quand un pilote va en rattraper un autre ou quand un pilote va devoir s'arrêter en fonction des temps aux tours. Ça ne me demanderait pas de nouvelles technologies, mais simplement du temps pour mettre en place et tester les algorithmes. +3. Faire un système qui puisse tester les algorithmes prédictifs sur un panel de Grand Prix. Si l'étape d'avant est faite, on peut facilement imaginer un bout de programme qui aille tester le programme sur différents Grand Prix pour voir si les prédictions sont bonnes. +4. Avoir une notion d'historique des courses pour avoir une page de comparaison des performances des équipes. Par exemple, déterminer quelle voiture est la plus rapide et comparer avec les autres circuits. On peut même imaginer qu'après plusieurs Grands Prix, on puisse tenter de déterminer quelle équipe est forte sur quel circuit. +5. Avoir un système qui permet de trouver automatiquement tous les liens de Grand Prix comme ça l'utilisateur n'aie plus besoin d'aller chercher un URL. +6. Faire un installer pour qu'un utilisateur n'ait pas à se taper la procédure d'installation (qui est assez pénible) à la main. ### Long terme -La on va se pencher sur des features qui prendraient plus d'un mois à mettre en place correctement. +Là, on va se pencher sur des features qui prendraient plus d'un mois à mettre en place correctement. -1. On pourrait imaginer un système qui puisse regarder 50 Grand Prix et qui change automatiquement les variables des algorythmes en fonction de leurs performances (Un genre d'apprentissage machine rustique) -2. On pourrait imaginer un système qui puisse créer des infographies. Que ce soit au milieu de la course ou à la fin, le programme pourrait nous génèrer des images avec une stat intéressante (ex: x pilote a fait x dépassements ou x pilote gagnerait x points si il finissait dans cette position ce qui le ferait changer de position au classement général). Si c'est bien fait, cela pourrait être un outil extrêmement précieux car je pourrais utiliser ces infographies dans mes commentaires. +1. On pourrait imaginer un système qui puisse regarder 50 Grand Prix et qui change automatiquement les variables des algorithmes en fonction de leurs performances (Un genre d'apprentissage machine rustique). +2. On pourrait imaginer un système qui puisse créer des infographies. Que ce soit au milieu de la course ou à la fin, le programme pourrait nous générer des images avec une stat intéressante (ex : x pilote a fait x dépassements ou x pilote gagnerait x points s'il finissait dans cette position, ce qui le ferait changer de position au classement général). Si c'est bien fait, cela pourrait être un outil extrêmement précieux, car je pourrais utiliser ces infographies dans mes commentaires. 3. On pourrait avoir un système qui donne une note de performance pour chaque pilote en fonction de ses performances et en fonction de sa voiture pour faire un genre de classement des pilotes. -4. Il serait génial d'avoir une page de stats qui se souviennent de tous les anciens Grand Prix regardés qui permette d'afficher toutes les stats d'un pilote sur plusieurs courses. (Cela me permettrais, dans des moments ou la course stagne un peu, de pouvoir prendre nimporte quel pilote et d'avoir des choses à dire à son sujet) -5. On pourrait même imaginer un système qui utilise une base de données sur un serveur infomaniak et développer une extension de navigateur qui me donne des infos importantes directement sur la page ou je commente le Grand Prix ou qui au moins me fasse des notifications pour que je sache quand aller regarder car un truc important s'est passé. +4. Il serait génial d'avoir une page de stats qui se souviennent de tous les anciens Grand Prix regardés qui permettent d'afficher toutes les stats d'un pilote sur plusieurs courses. (Cela me permettrait, dans des moments où la course stagne un peu, de pouvoir prendre n'importe quel pilote et d'avoir des choses à dire à son sujet) +5. On pourrait même imaginer un système qui utilise une base de données sur un serveur Infomaniak et développer une extension de navigateur qui me donne des infos importantes directement sur la page où je commente le Grand Prix ou qui au moins me fasse des notifications pour que je sache quand aller regarder, car un truc important s'est passé. -Je vais m'arrêter la car les possibilités sont tout simplement infinies. A partir du moment ou je peux récupérer toutes les informations de la F1TV de manière fiable le champs des possibles est ouvert et la seule limite est notre imagination. +Je vais m'arrêter là parce que les possibilités sont tout simplement infinies. À partir du moment où je peux récupérer toutes les informations de la F1TV de manière fiable, les champs des possibles sont ouverts et la seule limite est notre imagination. Il n'est pas impossible que je refasse une version de ce projet dans le futur qui me permette d'appliquer tout ce que j'ai appris pour le faire plus proprement (avec de la TDD par exemple) et qui me permette d'implémenter toutes ces améliorations et plus. -Je pense vraiment que si je continue à commenter pour le 20 minutes dans les années qui viennent cela pourrait être intéressant de développer un outil du style qui pourrait grandement m'aider à faire des commentaires de qualité. +Je pense vraiment que si je continue à commenter pour le 20 minutes dans les années qui viennent, cela pourrait être intéressant de développer un outil du style qui pourrait grandement m'aider à faire des commentaires de qualité. ## Conclusion @@ -2457,35 +2454,35 @@ Je pense vraiment que si je continue à commenter pour le 20 minutes dans les an ### Bilan -Je vais faire un petit bilan de ce travail. Déja, je vous remercie chaleureusement d'avoir lu cette documentation (j'ai du la relire en entier une ou deux fois je sais que c'est pas facile). J'espère que j'ai pu parler de tout ce dont je voulais parler et que je l'ai fait de manière explicite et facile à lire pour vous. J'ai vraiment fait de mon mieux pour qu'elle soit la plus facile possible à lire mais c'est un exercice difficile dans un document de cette taille et je m'excuse des inévitables erreurs et coquilles que vous aurez peut-êter remarqué. +Je vais faire un petit bilan de ce travail. Déjà, je vous remercie chaleureusement d'avoir lu cette documentation (j'ai dû la relire en entier une ou deux fois, je sais que ce n'est pas facile). J'espère que j'ai pu parler de tout ce dont je voulais parler et que je l'ai fait de manière explicite et aisé à lire pour vous. J'ai réellement fait de mon mieux pour qu'elle soit la plus simple possible à lire, mais c'est un exercice difficile dans un document de cette taille et je m'excuse des inévitables erreurs et coquilles que vous aurez peut-être remarqué. -Je dois avouer que je suis quand même très content d'arriver au bout de ce travail. J'ai vraiment aimé cette expérience unique de pouvoir travailler à 100% sur un projet et voir de quoi je suis capable. Mais je suis aussi content d'arriver à la fin car je dois avouer que ca n'a pas été facile tous les jours et que de travailler presque seul sur un projet si long n'est pas facile. +Je dois avouer que je suis quand même très content d'arriver au bout de ce travail. J'ai vraiment aimé cette expérience unique de pouvoir travailler à 100 % sur un projet et voir de quoi je suis capable. Mais je suis aussi heureux d'arriver à la fin, car je dois avouer que ça n'a pas été simple tous les jours et que de travailler presque seul sur un projet si long n'est pas facile. -Pour être tout à fait honnête, je suis quand même fier de ce que j'ai fait (ce qui n'arrive pas souvemt). C'est un projet qui est à des années lumières de la perfection, mais c'était mon idée et en commenceant le projet je ne savais même pas si j'allais y arriver. Certes le résultat n'est pas exactement comme je l'aurais rêvé mais il est concrêt et il fonctionne ! +Pour être tout à fait honnête, je suis quand même fier de ce que j'ai fait (ce qui n'arrive pas souvent). C'est un projet qui est à des années lumières de la perfection, mais c'était mon idée et en commençant le projet, je ne savais même pas si j'allais y arriver. Certes le résultat n'est pas exactement comme je l'aurais rêvé, mais il est concret et il fonctionne ! -Il y a eu des moments ou en voyant la quantité de choses qu'il restait à faire je me sentais un peu découragé mais je suis arrivé au bout avec un projet fonctionnel et pour ca je suis assez fier. +Il y a eu des moments ou en voyant la quantité de choses qu'il restait à faire, je me sentais un peu découragé, mais je suis arrivé au bout avec un projet fonctionnel et pour ça, je suis assez fier. -Ce fut un projet difficile surtout sur le plan de la résolution de problèmes. Chaque étape du projet apportait une nouvelle problématique qu'il fallait résoudre et si parfois j'ai pu trouver des facon élégantes de le faire, pour d'autres il a fallu être un peu plus créatif et moins regardant sur la methode mais que sur le résultat. +Ce fut un projet difficile, surtout sur le plan de la résolution de problèmes. Chaque étape du projet apportait une nouvelle problématique qu'il fallait résoudre et si parfois, j'ai pu trouver des façons élégantes de le faire, pour d'autres, il a fallu être un peu plus créatif et moins regardant sur la méthode, mais que sur le résultat. -Je suis un peu frustré de rendre le projet alors que j'ai encore pleins d'idées pour le rendre meilleur. Mais je suis content de rendre quelque chose qui fonctionne et qui est déja techniquement utilisable sur le terrain. +Je suis un peu frustré de rendre le projet alors que j'ai encore pleins d'idées pour le rendre meilleur. Mais je suis content de rendre quelque chose qui fonctionne et qui est déjà techniquement utilisable sur le terrain. -Ce projet m'a également appris pas mal de chose sur ma facon de travailler et sur la gestion de projet et je sais que tous mes futurs projets bénéficieront de ces apprentissages. +Ce projet m'a également appris pas mal de chose sur ma manière de travailler et sur la gestion de projet et je sais que tous mes futurs projets bénéficieront de ces apprentissages. ### Résumé des épreuves -Ici je vais tenter de résumer très rapidement tout ce qui a du se passer pour en arriver là. +Ici, je vais tenter de résumer très rapidement tout ce qui a dû se passer pour en arriver là. -Pour commencer il a fallu trouver un moyen de récupérer des images de la F1TV automatiquement. Pour ce faire j'ai du trouver une librairie qui me permette de contrôler un navigateur Firefox. Il a ensuite fallu trouver un moyen de se connecter automatiquement, pour ce faire j'ai du écrire un bout de code Python qui est allé chercher les cookies dans la base de données de chrome. Ensuite il a fallu réussir à naviguer sur la page de la F1TV en tenant compte des chargements et de la protection anti bots. Puis finalement trouver un moyen de retourner une image en assez bonne résolution. +Pour commencer, il a fallu trouver un moyen de récupérer des images de la F1TV automatiquement. Pour ce faire, j'ai dû trouver une librairie qui me permette de contrôler un navigateur Firefox. Il a ensuite fallu trouver un moyen de se connecter automatiquement, pour ce faire, j'ai dû écrire un bout de code Python qui est allé chercher les cookies dans la base de données de chrome. Ensuite, il a fallu réussir à naviguer sur la page de la F1TV en tenant compte des chargements et de la protection anti bots. Puis finalement trouver un moyen de retourner une image en assez bonne résolution. -Avec ces images il a ensuite fallu développer un système qui permette à l'utilisateur d'indiquer au programme ou se trouvaient les informations. Il a ensuite fallu faire un sytème qui utilise ces informations pour découper l'image pour isoler les infos et les envoyer à la partie reconnaissance. +Avec ces images, il a ensuite fallu développer un système qui permette à l'utilisateur d'indiquer au programme où se trouvaient les informations. Il a ensuite fallu faire un système qui utilise ces informations pour découper l'image pour isoler les infos et les envoyer à la partie reconnaissance. -Cette partie reconnaissance a du être développée de manière quasi unique pour chaque type d'information reconnue et en plus de la partie reconnaissance qui était déja bien galère, il a fallu faire tout un sytème qui puisse detecter les anomalies de reconnaissances pour être sûr que les informations récupèrées étaient bonnes. +Cette partie reconnaissance a dû être développée de manière quasi unique pour chaque type d'information reconnue et en plus de la partie reconnaissance qui était déjà bien galère, il a fallu faire tout un système qui puisse détecter les anomalies de reconnaissances pour être sûr que les informations récupérées étaient bonnes. -Après tout ca il a fallut faire en sorte que ces données soient stockées et affichées correctement. Créer une facon de les afficher de manière utile et facile à l'utilisateur. +Après tout ça, il a fallu faire en sorte que ces données soient stockées et affichées correctement. Créer une façon de les afficher de manière utile et facile à l'utilisateur. -Et tout ce beau monde a du être optimisé pour que l'application ne prenne pas une minute pour récupérer des images et il a fallu raccorder ensembles toutes les parties du projet en un seul qui fonctionne correctement sans crasher. +Et tout ce beau monde a dû être optimisé pour que l'application ne prenne pas une minute pour récupérer des images et il a fallu raccorder ensembles toutes les parties du projet en un seul qui fonctionne correctement sans crasher. -C'est un résumé un peu barbarre qui oublie énormément de choses et qui ne parle pas des problèmes rencontrés mais cela peut donner une vague idée de la taille du projet et de pourquoi je suis déja si fier juste que tout fonctionne. +C'est un résumé un peu barbare qui oublie énormément de choses et qui ne parle pas des problèmes rencontrés, mais cela peut donner une vague idée de la taille du projet et de pourquoi je suis déjà si fier, juste que tout fonctionne. Merci d'avoir lu cette documentation, j'espère qu'elle a été instructive et je vous souhaite une excellente journée @@ -2493,136 +2490,136 @@ Merci d'avoir lu cette documentation, j'espère qu'elle a été instructive et j ---- -Ici je vais donner quelques petites infos qui pourraient vous être utiles si vous décidez d'aller vous aventurer dans mon code source. +Ici, je vais donner quelques petites infos qui pourraient vous être utiles si vous décidez d'aller vous aventurer dans mon code source. -Le programme n'est pas à proprement parlé un programme en MVC, le découpage général suit quand même cette philosophie, je vais donc les ranger de cette facon pour que ca soit plus simple pour vous de comprendre. +Le programme n'est pas à proprement parlé un programme en MVC, le découpage général suit quand même cette philosophie, je vais donc les ranger de cette façon pour que ça soit plus simple pour vous de comprendre. ### Vues -Comme le projet n'est pas un MVC parfait, les vues vont quand mêmes quelques actions mais les deux fichiers dont je vais parler ici sont à au moins 90% juste de la vue +Comme le projet n'est pas un MVC parfait, les vues font quand même quelques actions, mais les deux fichiers dont je vais parler ici sont à au moins 90 % juste de la vue #### Settings.cs -Ce fichier contient tout le code pour contrôler la vue des "Settings" qui est la vue qui se charge de la creation et édition des Prestets. Si vous voulez changer le comportement de la cette page il faut éditer ce fichier. +Ce fichier contient tout le code pour contrôler la vue des "Settings" qui est la vue qui se charge de la création et édition des Presets. Si vous voulez changer le comportement de cette page, il faut éditer ce fichier. Cette vue utilise deux contrôleurs : - F1TVEmulator - ConfigurationTool -Le premier pour pouvoir lancer une instance de Firefox qui permet de tester le système, le second pour effectuer toutes les actions de création,modification ou de lecture des "Presets" +Le premier pour pouvoir lancer une instance de Firefox qui permet de tester le système, le second pour effectuer toutes les actions de création, modification ou de lecture des "Presets" -Rien de bien fou à dire sur ce fichier. La seule chose un peu bizarre est la gestion de la création des zones et des fenêtres. Il y a tout un système qui peut être un peu bizarre à première vue qui sert à detecter quand l'utilisateur clique sur l'image pour créer une zone. Je suis sûr qu'il existe une manière plus propre de le faire que celle que j'ai utilisé mais j'ai fait en sorte que cela fonctionne. +Rien de bien fou à dire sur ce fichier. La seule chose un peu bizarre est la gestion de la création des zones et des fenêtres. Il y a tout un système qui peut être un peu bizarre à première vue qui sert à détecter quand l'utilisateur clique sur l'image pour créer une zone. Je suis sûr qu'il existe une manière plus propre de le faire que celle que j'ai utilisée, mais j'ai fait en sorte que cela fonctionne. Un truc qui serait bien à ajouter dans le futur serait un moyen de visualiser au moins les points que l'on ajoute au fur et à mesure plutôt que de tout voir à la fin. #### Form1.cs -Ce fichier contient tout le code pour contrôler la vue principale. Elle se charge de lancer le navigateur et d'afficher toutes les données récupèrées ou stockées. +Ce fichier contient tout le code pour contrôler la vue principale. Elle se charge de lancer le navigateur et d'afficher toutes les données récupérées ou stockées. Cette vue utilise deux contrôleurs : - F1TVEmulator - DataWrapper -Le premier pour contrôler le navigateur (le lancer le stopper, changer l'URL etc...) et le second pour accèder à des infos de la base de donnée sans avoir à l'appeler directement. +Le premier pour contrôler le navigateur (le lancer, le stopper, changer l'URL etc.) et le second pour accéder à des infos de la base de donnée sans avoir à l'appeler directement. ### Contrôleurs -Ces classes ne sont pas des contrôleurs à 100% car ils contiennent aussi un peu de calcul etc... mais ont comme but principal de servir d'interface entre la vue et les données +Ces classes ne sont pas des contrôleurs à 100 %, car ils contiennent aussi un peu de calcul, etc. mais ont comme but principal de servir d'interface entre la vue et les données. #### ConfigurationTool.cs -Cette classe sert à travailler avec la zone principale pour la contrôler et à contenir les methode qui servent à la création de Presets. +Cette classe sert à travailler avec la zone principale pour la contrôler et à contenir les méthode qui servent à la création de Presets. -Les deux grosses methodes que cette classe contient sont : +Les deux grosses méthodes que cette classe contient sont : - SaveToJson - AutoCalibrate -La première sert tout simplement à prendre la configuration actuelle et la sauvegarder en format JSON dans un fichier dans le dossier PRESETS. La seconde prend une zone, utilise de l'OCR pour localiser les endroits ou il y a du texte et fait une calibration auto pour créer automatiquement les zones de pilotes. +La première sert tout simplement à prendre la configuration actuelle et la sauvegarder en format JSON dans un fichier dans le dossier PRESETS. La seconde prend une zone, utilise de l'OCR pour localiser les endroits où il y a du texte et fait une calibration auto pour créer automatiquement les zones de pilotes. -Les autres methodes sont simplement des methodes qui appellent des methodes de modèles et servent juste d'interface. +Les autres méthodes sont juste des méthodes qui appellent des méthodes de modèles et servent seulement d'interface. #### DataWrapper.cs -Cette methode sert à faire l'intermédiaire entre la form principale et le contrôler "Reader" ainsi que la classe qui contrôle directement la base de données. +Cette méthode sert à faire l'intermédiaire entre la form principale et le contrôler "Reader" ainsi que la classe qui contrôle directement la base de données. Elle interface avec ces deux classes : - Reader - Storage -Reader est un genre d'hybride mais qui se veut être un genre de contrôler de la lecture des données sur les images et des fichiers JSON tandis que storage est le modèle qui interragis directement avec la base de données SQLITE. +Reader est un genre d'hybride, mais qui se veut être un genre de contrôler de la lecture des données sur les images et des fichiers JSON tandis que storage est le modèle qui interagis directement avec la base de données SQLITE. -Cette classe contient des methodes qui auraient très pu (et sûrement dûes) se retrouver directement dans la vue. La plupart des methodes sont la pour génèrer des contrôles qui contiennent des informations récupèrées par la base de données ou par l'OCR. +Cette classe contient des méthodes qui auraient très pu (et sûrement dûes) se retrouver directement dans la vue. La plupart des méthodes sont là pour générer des contrôles qui contiennent des informations récupérées par la base de données ou par l'OCR. #### Reader.cs -Cette methode est un genre d'hybride. Elle contient des calculs etc... mais sont but est de servir d'inteface entre le reste du programme et les zones/fenêtres de données. +Cette méthode est un genre d'hybride. Elle contient des calculs, etc. mais son but est de servir d'interface entre le reste du programme et les zones/fenêtres de données. -C'est cette methode qui va gèrer la classe Zone, qui va demander à la classe zone de modifier ajouter ou supprimer des fenêtres etc... +C'est cette méthode qui va gérer la classe Zone, qui va demander à la classe zone de modifier, ajouter ou supprimer des fenêtres etc. -Elle contient aussi des methodes pour charger un "Preset" et dessiner sur les Images quand une vue en a besoin. +Elle contient aussi des méthodes pour charger un "Preset" et dessiner sur les Images quand une vue en a besoin. #### Zone.cs -Cette methode est clairement la plus discutable en tant que contrôleur mais qui est en même temps la plus proche. +Cette méthode est clairement la plus discutable en tant que contrôleur, mais qui est en même temps la plus proche. -La raison est qu'elle peut être deux choses. Une zone principale ou une zone de pilote. Dans le cas ou c'est une zone de pilote c'est clairement une classe normale qui est utilisée par un contrôleur et qui retourne des infos. Mais quand elle est utilisée comme une zone principale c'est l'orchestre de toutes les zones et fenêtres. +La raison est qu'elle peut être deux choses. Une zone principale ou une zone de pilote. Dans le cas ou c'est une zone de pilote, c'est clairement une classe normale qui est utilisée par un contrôleur et qui retourne des infos. Mais quand elle est utilisée comme une zone principale, c'est l'orchestre de toutes les zones et fenêtres. Dans ce dernier cas, c'est un intermédiaire entre les zones et fenêtres. Elle ne sert qu'à contrôler des sous zones et leurs fenêtres. -Les seules methodes de cette classe servent à demander des informations aux sous zones/fenêtres. Il n'y a quasi aucun calculs. +Les seules méthodes de cette classe servent à demander des informations aux sous zones/fenêtres. Il n'y a quasi aucun calculs. ### Modèles -La on va parler des classes "classiques" (lol). +Là, on va parler des classes "classiques" (lol). Il y a deux types de classes dans cette liste : - Les classes normales - Les classes enfants de Window.cs -Les classes normales sont indépendantes et contiennent toutes des methodes et des infos très différentes, tandis que les classes dérivées de Window.cs ont toutes la même structure et ont comme seul et unique but de retourner ce qui est marqué dans leur image. +Les classes normales sont indépendantes et contiennent toutes des méthodes et des infos très différentes, tandis que les classes dérivées de Window.cs ont toutes la même structure et ont comme seul et unique but de retourner ce qui est marqué dans leur image. -Il est donc normal que ces dernière se ressemblent beaucoup. +Il est donc normal que ces dernières se ressemblent beaucoup. #### DriverDrsWindow.cs -Cette classe est prévue pour contenir une image dans laquelle on peut voir l'étât du DRS d'un pilote. +Cette classe est prévue pour contenir une image dans laquelle on peut voir l'état du DRS d'un pilote. -La methode qu'elle utilise pour savoir si le pilote a activé son DRS ou non est d'utiliser la moyenne de couleur de son image. +La méthode qu'elle utilise pour savoir si le pilote a activé son DRS ou non est d'utiliser la moyenne de couleur de son image. -Elle retourne true ou false et elle contient elle même toutes les methodes qui sont nescessaires pour donner une réponse (c'est un cas rare) +Elle retourne true ou false et elle contient elle-même toutes les méthodes qui sont nécessaires pour donner une réponse (c'est un cas rare). #### DriverGapToLeaderWindow.cs Cette classe est prévue pour contenir une image dans laquelle on peut voir combien de temps sépare le pilote actuel du pilote devant lui. -La methode qu'elle utilise pour le savoir utilise de l'OCR et fait appel à une methode contenue dans son parent Window. +La méthode qu'elle utilise pour le savoir utilise de l'OCR et fait appel à une méthode contenue dans son parent Window. -Elle est plutôt vide car tout le traitement est déporté dans son parent. +Elle est plutôt vide, car tout le traitement est déporté dans son parent. #### DriverLapTimeWindow.cs Cette classe est prévue pour contenir une image dans laquelle on peut voir quel était le dernier temps au tour enregistré du pilote. -La methode qu'elle utilise pour le savoir utilise de l'OCR et fait appel à une methode contenue dans son parent. +La méthode qu'elle utilise pour le savoir utilise de l'OCR et fait appel à une méthode contenue dans son parent. -Elle est plutôt vide car tout le traitement est déporté vers son parent. +Elle est plutôt vide, car tout le traitement est déporté vers son parent. #### DriverNameWindow.cs Cette classe est prévue pour contenir une image dans laquelle on peut voir le nom du pilote écrit en toutes lettres. -La methode qu'elle utilise une partie d'OCR qui est déportée dans le parent et utilise aussi une methode appellée IsADriver (qui aurait pu aussi être déportée dans la page principale) qui vérifie si le nom trouvé existe. +La méthode qu'elle utilise une partie d'OCR qui est déportée dans le parent et utilise aussi une méthode appelée IsADriver (qui aurait pu aussi être déportée dans la page principale) qui vérifie si le nom trouvé existe. #### DriverPositionWindow.cs Cette classe est prévue pour contenir une image dans laquelle on peut voir la position d'un pilote. -Cette methode est également un peu vide car pour décoder l'image le traitement est déporté dans son parent. +Cette méthode est également un peu vide, car pour décoder l'image le traitement est déporté dans son parent. #### DriverSectorWindow.cs @@ -2632,11 +2629,11 @@ Pareil que pour DriverPositionWindow.cs Cette classe est prévue pour contenir une image dans laquelle on peut voir l'infographique qui représente le pneu du pilote. -Cette methode est la seule fenêtre intéressante car elle utilise du code déporté dans le parent mais aussi une certaine proportion qu'elle contient elle même. +Cette méthode est la seule fenêtre intéressante, car elle utilise du code déporté dans le parent, mais aussi une certaine proportion qu'elle contient elle-même. -Elle contient des methodes qui permettent par exemple de trouver la zone intéressante dans l'image ou choisir quel pneu un pilote chausse en fonction de la couleur moyenne de l'image de la zone trouvée. +Elle contient des méthodes qui permettent par exemple de trouver la zone intéressante dans l'image ou choisir quel pneu un pilote chausse en fonction de la couleur moyenne de l'image de la zone trouvée. -Pour toutes les zones de type Window, ce qui est vraiment intéressant vous le trouverez dans le parent. +Pour toutes les zones de type Window, ce qui est vraiment intéressant, vous le trouverez dans le parent. #### F1TVEmulator.cs @@ -2644,41 +2641,41 @@ F1TVEmulator est la classe qui s'occupe de tout ce qui concerne le navigateur He Cette classe utilise la librairie Selenium et est la pour tout faire. -Elle s'occupe aussi bien d'envoyer la requète de cliquer sur un bouton après 34 secondes que de récupèrer les cookies qui permettront de se connecter ensuite. +Elle s'occupe aussi bien d'envoyer la requête, de cliquer sur un bouton après 34 secondes que de récupérer les cookies qui permettront de se connecter ensuite. -Voici les methodes qui s'occupent des cookies : +Voici les méthodes qui s'occupent des cookies : - StartCookieRecovering - GetCookie -Je déconseille de modifier ces deux methodes. Elles ont une utilité très claire et elles fonctionnent. (If its not broken dont fix it) +Je déconseille de modifier ces deux méthodes. Elles ont une utilité très claire et elles fonctionnent. (If its not broken dont fix it) -Ce qui peut être intéressant en revanche c'est la seule autre methode que cette classe propose, sobrement intitulée "Start". +Ce qui peut être intéressant en revanche, c'est la seule autre méthode que cette classe propose sobrement intitulée "Start". -Cette methode est codée de manière totalement procédurale et décrit exactement toutes les actions à faire à partir du moment ou le navigateur est démarré, dans quel ordre et si il faut les faire ou non. Si vous vouliez modifier quelque chose ici je pense que la bonne idée serait une meilleure gestion des erreurs. Pour le moment si le programme n'arrive pas à cliquer sur certains boutons, soit une erreur est lancée soit on attend un peu avant de réessayer. La vraie chose qui manque c'est la raison pour laquelle ces boutons n'ont pas pu être cliqués. Dans l'idéal il faudrait ajouter un système qui peut detecter la panne exacte pour que le message d'erreur soit plus personnalisé. +Cette méthode est codée de manière totalement procédurale et décrit exactement toutes les actions à faire à partir du moment ou le navigateur est démarré, dans quel ordre et s'il faut les faire ou non. Si vous vouliez modifier quelque chose ici, je pense que la bonne idée serait une meilleure gestion des erreurs. Pour le moment, si le programme n'arrive pas à cliquer sur certains boutons, soit une erreur est lancée, soit on attend un peu avant de réessayer. La vraie chose qui manque, c'est la raison pour laquelle ces boutons n'ont pas pu être cliqués. Dans l'idéal, il faudrait ajouter un système qui peut détecter la panne exacte pour que le message d'erreur soit plus personnalisé. -Sinon c'est une methode qui marche plutôt bien et qui est faite totalement sur mesure pour l'utilisation de la F1TV. +Sinon c'est une méthode qui marche plutôt bien et qui est faite complètement sur mesure pour l'utilisation de la F1TV. #### OcrImage.cs -La on attaque les classes un peu plus "bordéliques" +Là, on attaque les classes un peu plus "bordéliques". -Cette classe regroupe tous les actions de filtrage que l'on pourrait vouloir. Cette classe est pas mal utilisée pour l'OCR. Il n'y a que deux choses à savoir. +Cette classe regroupe toutes les actions de filtrage que l'on pourrait vouloir. Cette classe est pas mal utilisée pour l'OCR. Il n'y a que deux choses à savoir. -1. Presque toutes les methodes de filtres sont génériques et peuvent être utilisées à peu près nimporte ou et nimporte quand et devraient toujours fonctionner tant qu'on leur fournit ce qdnt elles ont besoin (la plupart sont en statique) -2. La seule methode qui vas vous intéresser si vous vouleuz changer le comportement de l'OCR est la methode "Enhance" +1. Presque toutes les méthodes de filtres sont génériques et peuvent être utilisées à peu près n'importe où et n'importe quand et devraient toujours fonctionner tant qu'on leur fournit ce dont elles ont besoin (la plupart sont en statique). +2. La seule méthode qui va vous intéresser si vous voulez changer le comportement de l'OCR est la méthode "Enhance". -La methode enhance est un genre de mode d'emploi. Selon le contexte de l'image (si c'est une image qui vient d'une fenêtre de DRS, de temps au tour, de pneu etc...) il y aura une combinaison de filtres différente. +La méthode enhance est un genre de mode d'emploi. Selon le contexte de l'image (si c'est une image qui vient d'une fenêtre de DRS, de temps au tour, de pneu etc.) il y aura une combinaison de filtres différente. -Plusieurs methodes dans cette classe ne sont pas utilisées mais sont gardées car elles pourraient être utiles. La plupart du temps l'utilisation de ces filtres est décidée avec des essais à tâtons. Vous comprendrez donc vite que c'est mieux de garder sous le code des methodes car certaines combinaisons marchent mieux que d'autres. +Plusieurs méthodes dans cette classe ne sont pas utilisées, mais sont gardées, car elles pourraient être utiles. La plupart du temps, l'utilisation de ces filtres est décidée avec des essais à tâtons. Vous comprendrez donc vite que c'est mieux de garder sous le code des méthodes car certaines combinaisons marchent mieux que d'autres. #### SqliteStorage.cs Cette classe est plutôt simple. -Ce sont simplement toutes les methodes qui permettent de créer, éditer et accèder à la base de données SQLITE. +Ce sont simplement toutes les méthodes qui permettent de créer, éditer et accéder à la base de données SQLITE. -Vous y trouverez des methodes qui sont simplement la pour créer la base comme d'autres plus spécifiques qui sont un peu plus spécifiques comme celles qui veulent récupèrer l'ID d'un pilote selon son nom ou celle qui veut récupèrer l'historique des temps au tour d'un pilote. +Vous y trouverez des méthodes qui sont juste là pour créer la base comme d'autres plus spécifiques qui sont un peu plus spécifiques comme celles qui veulent récupérer l'ID d'un pilote selon son nom ou celle qui veut récupérer l'historique des temps autour d'un pilote. Rien de spécial à dire sur cette classe. @@ -2686,31 +2683,31 @@ Rien de spécial à dire sur cette classe. Ahlala... je pense que c'est une des classes les plus longues de tout le projet. Du haut de ses presque 700 lignes, cette classe s'occupe de tout ce que les enfants fenêtres pourraient avoir besoin. -On retrouve des methodes pour calculer la différence entre deux strings qui peut servir pour aider à le reconnaissance de noms de pilotes ou bien une methode qui permet de convertir une image en tableau de bytes. +On retrouve des méthodes pour calculer la différence entre deux strings qui peut servir pour aider à la reconnaissance de noms de pilotes ou bien une méthode qui permet de convertir une image en tableau de bytes. -La methode la plus grosse cependant et de loin est la methode GetTimeFromPng qui doit implémenter un système qui permet de detecter quand un temps est anormal et detecter si la raison est la mauvaise compréhension d'une ponctuation ou le rajout d'un chiffre. Cela prend énormément de place car il y a beaucoup de cas particuliers et il a fallu tout coder à la main. Je déconseille à qui que ce soit de lire cette methode car elle pourrait causer de sévères dommages au cerveau humain. +La méthode la plus grosse cependant et de loin est la méthode GetTimeFromPng qui doit implémenter un système qui permet de détecter quand un temps est anormal et détecter si la raison est la mauvaise compréhension d'une ponctuation ou le rajout d'un chiffre. Cela prend énormément de place, car il y a beaucoup de cas particuliers et il a fallu tout coder à la main. Je déconseille à qui que ce soit de lire cette méthode, ainsi, elle pourrait causer de sévères dommages au cerveau humain. -A ecrire ce fut une horreur, à comprendre je n'ose pas imaginer. +À écrire, ce fut une horreur, à comprendre, je n'ose pas imaginer. -Sinon pas grand chose de plus à raconter. +Sinon pas grand-chose de plus à raconter. ### Structures -Les classes de structures sont des classes qui ne contiennent que peu ou pas de traitement et qui sont simplement la pour contenir des informations. Elles sont pratiques car elles permettent de rendre le code dans les autres classes beaucoup plus lisible et leur éviter d'utiliser des tuples bizarres. +Les classes de structures sont des classes qui ne contiennent que peu ou pas de traitement et qui sont simplement là pour contenir des informations. Elles sont pratiques, car elles permettent de rendre le code dans les autres classes beaucoup plus lisible et leur éviter d'utiliser des tuples bizarres. #### DriverData.cs Cette classe contient toutes les infos d'un pilote à un moment donné. -On peut voir cette classe comme une classe contenant une ligne de la F1TV. Toutes les données à propos d'un pilote que l'on peut detecter en une detection sont stockées la dedans. +On peut voir cette classe comme une classe contenant une ligne de la F1TV. Toutes les données à propos d'un pilote que l'on peut détecter en une détection sont stockées là-dedans. Il n'y a pas de notion d'historique ou quoi que ce soit. C'est simplement un moyen de stocker des données de pilotes dans d'autres classes en ayant un nom logique et aider à la lecture. Pas réellement de traitement. Ce fichier contient également un autre objet : Tyre. -Cet object contient les infos d'un pneu rien de plus. +Cet objet contient les infos d'un pneu, rien de plus. -Et voila ce fut un résumé extrêmement succint de tous les fichiers .CS de l'application pour que vous sachiez ce que vous regardez quand vous irez voir dans la partie code source de la documentation. Normalement il devrait y avoir aussi un certain nombre de commentaires dans ces fichiers pour expliquer certains choix un peu bizarres. C'est en anglais mais pas de l'anglais très difficile à comprendre. Bonne chance ! +Et voilà, ce fut un résumé extrêmement succinct de tous les fichiers .CS de l'application pour que vous sachiez ce que vous regardez quand vous irez voir dans la partie code source de la documentation. Normalement, il devrait y avoir aussi un certain nombre de commentaires dans ces fichiers pour expliquer certains choix un peu bizarres. C'est en anglais, mais pas de l'anglais très difficile à comprendre. Bonne chance ! ## Glossaire @@ -2719,11 +2716,11 @@ Et voila ce fut un résumé extrêmement succint de tous les fichiers .CS de l'a Vocabulaire F1 : 1. DRS : Drag Reduction System. : Système qui permet d'ouvrir l'aileron arrière de la monoplace quand elle se trouve à une seconde ou moins de la voiture devant elle. Cela permet de réduire la trainée que la voiture subit et lui permet d'avoir un petit boost qui aide à dépasser. -2. Pitstop : Arrêt aux stands : Pendant une course de F1, les pneus s'usent extrêment vite et tous les pilotes sont obligés de passer au moins une fois par les stands par course pour les changer. Et pour changer ces pneus ils font un arrêt aux stands que l'on appelle dans le milieu un Pitstop. -3. Pneus Hard,Medium,Soft,Inter,Wet : Types de pneus de F1. Hard est un pneu qui ne s'use pas beaucoup mais qui est lent, Soft est l'inverse et Medium est l'entre deux. Les pneus sont des outils stratégiques et il est très important de savoir lequel chaque pilote utilise. Les pneus Inter et Wet sont des pneus pluies, l'Inter étant pour les faibles pluies. -4. Secteur : Setion de circuit : Les circuits de F1 sont toujours découpés en trois parties qui sont mesurées séparément et qui permettent une meilleure granularité dans l'estimation des résultats. On est pas obligé d'attendre la fin d'un tour pour savoir si un pilote est rapide ou non et on peut voir dans quelle partie du circuit il est rapide ou lent. +2. Pitstop : Arrêt aux stands : Pendant une course de F1, les pneus s'usent extrêmement vite et tous les pilotes sont obligés de passer au moins une fois par les stands par course pour les changer. Et pour changer ces pneus, ils font un arrêt aux stands que l'on appelle dans le milieu un Pitstop. +3. Pneus Hard, Medium, Soft, Inter, Wet : Types de pneus de F1. Hard est un pneu qui ne s'use pas beaucoup, mais qui est lent, Soft est l'inverse et Medium est l'entre deux. Les pneus sont des outils stratégiques et il est très important de savoir lequel chaque pilote utilise. Les pneus Inter et Wet sont des pneus pluies, l'Inter étant pour les faibles pluies. +4. Secteur : Section de circuit : Les circuits de F1 sont toujours découpés en trois parties qui sont mesurées séparément et qui permettent une meilleure granularité dans l'estimation des résultats. On n'est pas obligé d'attendre la fin d'un tour pour savoir si un pilote est rapide ou non et on peut voir dans quelle partie du circuit, il est rapide ou lent. 5. Monoplace : Voiture à une seule place, terme utilisé souvent pour décrire les F1 dans le document. -6. Grand Prix : Course officielle de Formule 1. Evenement faisant partie du championnat du monde de Formule 1. +6. Grand Prix : Course officielle de Formule 1. Événement faisant partie du championnat du monde de Formule 1. Vocabulaire projet : @@ -2733,7 +2730,7 @@ Vocabulaire projet : 4. MVC : Modèle Vue Controlleur : Architecture de projet qui sépare le traitement de l'information, son affichage et sa gestion. 5. Preset : (dans ce projet) Set d'informations préparées à l'avance pour être utilisés ultérieurement. 6. DB : Data Base / Base de donnée -7. Cookie : Fichier créé par un site internet stocké sur la machine du client qui est utilisé en général pour conserver des informations de connection même après la fermeture du navigateur. +7. Cookie : Fichier créé par un site internet stocké sur la machine du client qui est utilisé en général pour conserver des informations de connexion même après la fermeture du navigateur. 8. Window : Fenêtre (dans ce projet) objet contenant une partie d'une image contenant une information précise. 9. Zone : (dans ce projet) objet contenant une partie d'une image qui peu être sous divisée en fenêtres de données. 10. Wrapper : Code qui s'occupe de faire l'interface entre une librairie ou une classe pour rendre l'utilisation plus simple ou plus propre @@ -2741,4 +2738,5 @@ Vocabulaire projet : 12. AWS : Amazon Web Service : Service d'hébergement d'Amazon 13. User Agent : Signature numérique du navigateur qui permet à un site de détecter le type d'appareil et de navigateur connecté (peut être changé manuellement) 14. CSV : Comma Separated Values : Format de fichier qui permet de stocker facilement des données sous forme de tableau -15. API : Application Programming Interface : Interface générique qui permet d'accèder à une ressource. \ No newline at end of file +15. API : Application Programming Interface : Interface générique qui permet d'accéder à une ressource. +