Added new Poster and improved PDF rendering

This commit is contained in:
2023-05-09 15:00:12 +02:00
parent 985d1bd71d
commit 5393e2d946
60 changed files with 54106 additions and 9538 deletions
+301 -81
View File
@@ -30,7 +30,7 @@
</div>
<header class="md-header" data-md-component="header">
<nav aria-label="Header" class="md-header__inner md-grid">
<a aria-label="Documentation Track Trends" class="md-header__button md-logo" data-md-component="logo" href="." title="Documentation Track Trends">
<a aria-label="Documentation Track Trends" class="md-header__button md-logo" data-md-component="logo" href="index.html" title="Documentation Track Trends">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"></path></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
@@ -56,6 +56,36 @@
<input aria-hidden="true" class="md-option" data-md-color-accent="" data-md-color-media="(prefers-color-scheme: light)" data-md-color-primary="" data-md-color-scheme="default" id="__palette_1" name="__palette" type="radio"/>
<input aria-hidden="true" class="md-option" data-md-color-accent="" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-primary="" data-md-color-scheme="slate" id="__palette_2" name="__palette" type="radio"/>
</form>
<label class="md-header__button md-icon" for="__search">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"></path></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input aria-label="Search" autocapitalize="off" autocomplete="off" autocorrect="off" class="md-search__input" data-md-component="search-query" name="query" placeholder="Search" required="" spellcheck="false" type="text"/>
<label class="md-search__icon md-icon" for="__search">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.516 6.516 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5Z"></path></svg>
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"></path></svg>
</label>
<nav aria-label="Search" class="md-search__options">
<button aria-label="Clear" class="md-search__icon md-icon" tabindex="-1" title="Clear" type="reset">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12 19 6.41Z"></path></svg>
</button>
</nav>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" data-md-scrollfix="">
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list"></ol>
</div>
</div>
</div>
</div>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
@@ -66,7 +96,7 @@
<div class="md-sidebar__inner">
<nav aria-label="Navigation" class="md-nav md-nav--primary" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a aria-label="Documentation Track Trends" class="md-nav__button md-logo" data-md-component="logo" href="." title="Documentation Track Trends">
<a aria-label="Documentation Track Trends" class="md-nav__button md-logo" data-md-component="logo" href="index.html" title="Documentation Track Trends">
<svg viewbox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M12 8a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3m0 3.54C9.64 9.35 6.5 8 3 8v11c3.5 0 6.64 1.35 9 3.54 2.36-2.19 5.5-3.54 9-3.54V8c-3.5 0-6.64 1.35-9 3.54Z"></path></svg>
</a>
Documentation Track Trends
@@ -78,7 +108,7 @@
Rapport Track Trends V1.0
<span class="md-nav__icon md-icon"></span>
</label>
<a class="md-nav__link md-nav__link--active" href=".">
<a class="md-nav__link md-nav__link--active" href="index.html">
Rapport Track Trends V1.0
</a>
<nav aria-label="Table of contents" class="md-nav md-nav--secondary">
@@ -418,12 +448,12 @@
</nav>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="CahierDesCharges/">
<a class="md-nav__link" href="CahierDesCharges.html">
Cahier des charges
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="jdb/">
<a class="md-nav__link" href="jdb.html">
Journal de bord
</a>
</li>
@@ -440,92 +470,92 @@
</label>
<ul class="md-nav__list" data-md-scrollfix="">
<li class="md-nav__item">
<a class="md-nav__link" href="Code/ConfigurationTool/">
<a class="md-nav__link" href="Code/ConfigurationTool.html">
ConfigurationTool.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverGapToLeaderWindow/">
<a class="md-nav__link" href="Code/DriverGapToLeaderWindow.html">
DriverGapToLeaderWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverPositionWindow/">
<a class="md-nav__link" href="Code/DriverPositionWindow.html">
DriverPositionWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/F1TVEmulator/">
<a class="md-nav__link" href="Code/F1TVEmulator.html">
F1TVEmulator.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Program/">
<a class="md-nav__link" href="Code/Program.html">
Program.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Window/">
<a class="md-nav__link" href="Code/Window.html">
Window.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverData/">
<a class="md-nav__link" href="Code/DriverData.html">
DriverData.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverLapTimeWindow/">
<a class="md-nav__link" href="Code/DriverLapTimeWindow.html">
DriverLapTimeWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverSectorWindow/">
<a class="md-nav__link" href="Code/DriverSectorWindow.html">
DriverSectorWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Form1/">
<a class="md-nav__link" href="Code/Form1.html">
Form1.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Reader/">
<a class="md-nav__link" href="Code/Reader.html">
Reader.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Zone/">
<a class="md-nav__link" href="Code/Zone.html">
Zone.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverDrsWindow/">
<a class="md-nav__link" href="Code/DriverDrsWindow.html">
DriverDrsWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverNameWindow/">
<a class="md-nav__link" href="Code/DriverNameWindow.html">
DriverNameWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/DriverTyresWindow/">
<a class="md-nav__link" href="Code/DriverTyresWindow.html">
DriverTyresWindow.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/OcrImage/">
<a class="md-nav__link" href="Code/OcrImage.html">
OcrImage.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/Settings/">
<a class="md-nav__link" href="Code/Settings.html">
Settings.cs
</a>
</li>
<li class="md-nav__item">
<a class="md-nav__link" href="Code/recoverCookiesCSV/">
<a class="md-nav__link" href="Code/recoverCookiesCSV.html">
recoverCookiesCSV.py
</a>
</li>
@@ -883,14 +913,20 @@
<h1 id="rapport-track-trends-v10">Rapport Track Trends V1.0</h1>
<hr/>
<p>Rohmer Maxime Travail de diplôme Technicien ES 2023</p>
<p><a class="glightbox" href="Images/Figma/PosterV7.png"><img alt='"Poster"' src="Images/Figma/PosterV7.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/PosterV7.png"><img alt="" src="./Images/Figma/PosterV7.png"/></a>
<figcaption></figcaption>
</figure>
<h2 id="introduction">Introduction</h2>
<hr/>
<h3 id="resume">Résumé</h3>
<p>Track Trends est un outil de récupération et d'analyse de données de courses de Formule 1.</p>
<p>Pour le contexte, en dehors des cours, j'exerce différentes activités dont celle de Live Ticker F1 pour le 20 minutes. Pour m'aider dans ce travail, j'utilise actuellement la F1TV à laquelle je suis abonné qui me propose non seulement un feed vidéo de meilleure qualité avec des commentaires plus pertinents que ceux de la RTS mais qui aussi me permet d'accéder à un feed vidéo très important : la chaine data.</p>
<p>Ce dernier ressemble à cela :</p>
<p><a class="glightbox" href="Images/Screens/ScreenF1TvData.png"><img alt='"Screenshot du feed data de la f1tv"' src="Images/Screens/ScreenF1TvData.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" data="" de="" du="" f1tv""="" feed="" la="" screenshot="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Screenshot du feed data de la f1tv"</figcaption>
</figure>
<p>(Attention ce n'est pas un joli tableau HTML, mais bien une vidéo qui contient un tableau.)</p>
<p>Sauf que toutes les informations sont étalées pêle-mêle sans hiérarchie ce qui fait que cela me prendrait trop de temps de tout déchiffrer à chaque fois, ce qui me fait rater des choses intéressantes.</p>
<p>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.</p>
@@ -949,7 +985,10 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Il existe des API "Pirates" faites par la communauté, le problème est qu'elles ne sont pas forcément des plus pratiques à utiliser.</p>
<p>Mais comme je possède un abonnement premium ++ à la F1TV, j'ai accès pour chaque grand prix à un flux vidéo nommé : DATA F1 CHANNEL</p>
<p>Qui ressemble à ça :</p>
<p><a class="glightbox" href="Images/Screens/Formula1DataChannel.png"><img alt='"Data channel exemple"' src="Images/Screens/Formula1DataChannel.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/Formula1DataChannel.png"><img alt="" channel="" data="" exemple""="" src="./Images/Screens/Formula1DataChannel.png"/></a>
<figcaption>"Data channel exemple"</figcaption>
</figure>
<p>Donc la seule façon que je vois de récupérer ces données est de les prendre directement sur ce feed.</p>
<p>Même si le but final de l'application est de faire pleins de choses super avec les datas, le gros du projet va surtout être la récupération des données et leur stockage.</p>
<p>Les données viennent du flux vidéo et ainsi dans un premier temps, il va falloir récupérer d'une manière ou d'une autre des images qui viennent d'un grand prix en direct ou en rediffusion.</p>
@@ -977,7 +1016,10 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<li>Prédire les temps au tour de chaque pilote selon l'usure des pneus</li>
</ul>
<p>Voici un exemple d'interface possible pour une page :</p>
<p><a class="glightbox" href="Images/Figma/Prototype.png"><img alt='"Proto"' src="Images/Figma/Prototype.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Prototype.png"><img alt="" proto""="" src="./Images/Figma/Prototype.png"/></a>
<figcaption>"Proto"</figcaption>
</figure>
<h3 id="cas-dutilisation">Cas d'utilisation</h3>
<hr/>
<p>'*'On va considérer que tous les user ont un abonnement F1 TV PRO</p>
@@ -1094,14 +1136,23 @@ La raison la plus probable étant qu'Amazon avec son service AWS propose exactem
<p>Voici la première grande étape du projet.</p>
<p>Pour rappel, Amazon héberge directement le site de la F1TV et possède les droits sur les données de la F1. C'est sous le nom de AWS (le service d'hébergement d'Amazon) que la firme apparait en tant que sponsor.</p>
<p>On peut voir ce nom apparaître assez souvent quand on regarde un Grand Prix car comme ils ont la 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)</p>
<p><a class="glightbox" href="Images/Screens/AWSExample1.jpg"><img alt='"AWS example 1"' src="Images/Screens/AWSExample1.jpg"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/AWSExample1.jpg"><img 1""="" alt="" aws="" example="" src="./Images/Screens/AWSExample1.jpg"/></a>
<figcaption>"AWS example 1"</figcaption>
</figure>
<p>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</p>
<p><a class="glightbox" href="Images/Screens/AWSExample2.jpg"><img alt='"AWS example 2"' src="Images/Screens/AWSExample2.jpg"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/AWSExample2.jpg"><img 2""="" alt="" aws="" example="" src="./Images/Screens/AWSExample2.jpg"/></a>
<figcaption>"AWS example 2"</figcaption>
</figure>
<p>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.</p>
<p>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.</p>
<p>On pourrait croire que c'est impossible car cela n'existe pas comme je l'ai dit MAIS ! Ce n'est pas complêtement vrai. En effet depuis que je possède un abonnement à la F1TV, il existe une source d'informations très précieuse qui m'aide énormément dans mon quotidien de commentateur de Formule 1. La "DATA CHANNEL".</p>
<p>La Data Channel est une page de la F1TV qui permet, pour chaque Grand Prix, de visualiser, sous la forme d'un flux vidéo, différentes informations capitales sur la course.</p>
<p><a class="glightbox" href="Images/Screens/ScreenF1TvData.png"><img alt='"Data channel example"' src="Images/Screens/ScreenF1TvData.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" channel="" data="" example""="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Data channel example"</figcaption>
</figure>
<p>Le problème, c'est que comme je viens de le dire, ces données ne sont pas accessibles comme un tableau HTML ou un flux RSS ou un tableau JSON. C'est un flux vidéo.
Il faut savoir qu'entretenir une diffusion de flux vidéo en 1080P pendant deux heures accessible par des milliers d'abonnés est EXTRÊMENT cher surtout quand on le compare à simplement afficher les données dans un tableau. Ce qui veut dire que ce choix est délibéré et a un sens au niveau économique.
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)</p>
@@ -1129,14 +1180,22 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent si
<p>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.</p>
<h4 id="simuler-un-navigateur">Simuler un navigateur ?</h4>
<p>Simuler un navigateur internet n'est pas forcément très difficile. Chromium par exemple offre une panoplie d'outils natifs et énormément de librairies existent permettant de facilement et en quelques lignes simuler un Google Chrome et le contrôler sans afficher son UI.</p>
<p><a class="glightbox" href="Images/Screens/ChromiumLogo.png"><img alt='"Chromium logo"' src="Images/Screens/ChromiumLogo.png" style="height:150px;width:150px"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ChromiumLogo.png"><img alt="" chromium="" logo""="" src="./Images/Screens/ChromiumLogo.png"/></a>
<figcaption>"Chromium logo"</figcaption>
</figure>
<p>{: style="height:150px;width:150px"}</p>
<p>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)</p>
<p>Cela veut dire que quand on ouvre un flux de la F1TV sur chrome et que l'on essaie de prendre une capture d'écran, le player se met en noir et ne permet pas de voir quoi que ce soit (Certaines 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.</p>
<p>L'explication sans trop rentrer dans les détails est la suivante :</p>
<p>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.</p>
<p>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.</p>
<p>Sauf que Firefox n'est pas aussi facilement émulé que chrome et cela réduit notre choix de librairies à ... Une seule... Qui est Selenium. (Il existe aussi Pupetteer C# mais j'ai rencontré énormément de soucis avec cette dernière dès que je voulais lancer une vidéo)</p>
<p><a class="glightbox" href="Images/Screens/FirefoxLogo.png"><img alt='"Firefox Developper logo"' src="Images/Screens/FirefoxLogo.png" style="height:150px;width:150px"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/FirefoxLogo.png"><img alt="" developper="" firefox="" logo""="" src="./Images/Screens/FirefoxLogo.png"/></a>
<figcaption>"Firefox Developper logo"</figcaption>
</figure>
<p>{: style="height:150px;width:150px"}</p>
<p>Mais même si la documentation est plutôt maigre parfois, c'est une bonne librairie qui permet de très bien contrôler une instance de chrome ou de Firefox.</p>
<h4 id="controler-le-navigateur">Contrôler le navigateur</h4>
<p>Maintenant que l'on sait quel navigateur simuler et avec quelle technologie, on peut passer à la réalisation.</p>
@@ -1165,7 +1224,24 @@ Je pense donc que c'est justement pour éviter que des petits malins puissent si
<pre><code class="language-Csharp">IWebElement fullScreenButton = Driver.FindElement(By.ClassName("bmpui-ui-fullscreentogglebutton"));
fullScreenButton.Click();
</code></pre>
<p>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.</p>
<p>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</p>
<p>On peut utiliser différntes techniques pour passer outre ces restrictions comme :</p>
<ul>
<li>Changer son UserAgent</li>
<li>Changer sa résolution</li>
<li>Ne pas avoir des patterns trop prévisibles</li>
<li>Avoir un historique</li>
<li>Ne pas cliquer pile sur le milieu des boutons</li>
<li>Ne pas cliquer trop vite</li>
<li>Passer par un proxy pour ne pas se faire flag</li>
<li>Utiliser des librairies plus discrètes</li>
</ul>
<p>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.</p>
<p>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.</p>
<p>J'ai donc été obligé de faire appel à la connexion par Cookies pour pouvoir accèder au reste du site internet.</p>
<h4 id="recuperer-les-cookies">Récupèrer les cookies ?</h4>
<p>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.</p>
<p>[FINIR CETTE EXPLICATIOn]</p>
<h4 id="calibration">Calibration</h4>
<p>[AJOUTER EXPLICATION]</p>
@@ -1177,10 +1253,16 @@ fullScreenButton.Click();
<p>Mais avant ca je dois expliquer certains concepts qui seront importants.</p>
<h4 id="fonctionnement-general">Fonctionnement général</h4>
<p>Voici un screenshot de la page DATA de la F1TV que le programme va recevoir :</p>
<p><a class="glightbox" href="Images/Screens/ScreenF1TvData.png"><img alt='"Screen F1TV"' src="Images/Screens/ScreenF1TvData.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ScreenF1TvData.png"><img alt="" f1tv""="" screen="" src="./Images/Screens/ScreenF1TvData.png"/></a>
<figcaption>"Screen F1TV"</figcaption>
</figure>
<p>Si on regarde de loin on peut se dire que la structure est plutôt simple mais c'est loin d'être le cas.
On peut y voir au moins 4 zones contenant de l'information dans un format différent.</p>
<p><a class="glightbox" href="Images/Figma/WindowZoneExplanation1.png"><img alt='"Main zones"' src="Images/Figma/WindowZoneExplanation1.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/WindowZoneExplanation1.png"><img alt="" main="" src="./Images/Figma/WindowZoneExplanation1.png" zones""=""/></a>
<figcaption>"Main zones"</figcaption>
</figure>
<p>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.</p>
<p>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.</p>
<p>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.</p>
@@ -1206,20 +1288,41 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<li>L'objet Window n'est quasi jamais utilisé, c'est presque tout le temps des enfants de Window plus spécifiques qui sont utilisés, le but est que chaque type d'information sur l'image aie son type de window.</li>
</ul>
<p>Voila donc un petit diagramme qui montre le découpage du programme :</p>
<p><a class="glightbox" href="Images/Figma/WindowZoneExplanationDiagram.png"><img alt='"Diagramme zones"' src="Images/Figma/WindowZoneExplanationDiagram.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/WindowZoneExplanationDiagram.png"><img alt="" diagramme="" src="./Images/Figma/WindowZoneExplanationDiagram.png" zones""=""/></a>
<figcaption>"Diagramme zones"</figcaption>
</figure>
<p>Pour visualiser encore un peu mieux comment ce découpage prend forme voici ce que chaque zone et Window contient.</p>
<p>Main Zone :</p>
<p><a class="glightbox" href="Images/Screens/MainZoneExample.png"><img alt='"Main zone"' src="Images/Screens/MainZoneExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/MainZoneExample.png"><img alt="" main="" src="./Images/Screens/MainZoneExample.png" zone""=""/></a>
<figcaption>"Main zone"</figcaption>
</figure>
<p>Driver Zone :</p>
<p><a class="glightbox" href="Images/Screens/DriverZoneExample.png"><img alt='"Driver zone"' src="Images/Screens/DriverZoneExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/DriverZoneExample.png"><img alt="" driver="" src="./Images/Screens/DriverZoneExample.png" zone""=""/></a>
<figcaption>"Driver zone"</figcaption>
</figure>
<p>Driver Position Window :</p>
<p><a class="glightbox" href="Images/Screens/DriverPositionExample.png"><img alt='"Driver position Window"' src="Images/Screens/DriverPositionExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/DriverPositionExample.png"><img alt="" driver="" position="" src="./Images/Screens/DriverPositionExample.png" window""=""/></a>
<figcaption>"Driver position Window"</figcaption>
</figure>
<p>Driver name Window :</p>
<p><a class="glightbox" href="Images/Screens/DriverNameExample.png"><img alt='"Driver name window"' src="Images/Screens/DriverNameExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/DriverNameExample.png"><img alt="" driver="" name="" src="./Images/Screens/DriverNameExample.png" window""=""/></a>
<figcaption>"Driver name window"</figcaption>
</figure>
<p>Driver LapTime Window :</p>
<p><a class="glightbox" href="Images/Screens/DriverLapTimeExample.png"><img alt='"Driver Laptime window"' src="Images/Screens/DriverLapTimeExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/DriverLapTimeExample.png"><img alt="" driver="" laptime="" src="./Images/Screens/DriverLapTimeExample.png" window""=""/></a>
<figcaption>"Driver Laptime window"</figcaption>
</figure>
<p>Driver Tyre Window :</p>
<p><a class="glightbox" href="Images/Screens/DriverTyreWindowExample.png"><img alt='"Driver tyre window"' src="Images/Screens/DriverTyreWindowExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/DriverTyreWindowExample.png"><img alt="" driver="" src="./Images/Screens/DriverTyreWindowExample.png" tyre="" window""=""/></a>
<figcaption>"Driver tyre window"</figcaption>
</figure>
<p>Il existe d'autres types de Window mais ce sont les principaux.</p>
<p>On se rend assez facilement compte que chacunes de ces windows va avoir besoin d'un traitement spécifique car la manière de reconnaitre le pneu utilisé et le temps au tour ne peut pas être la même.</p>
<p>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.</p>
@@ -1234,16 +1337,31 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<p>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.</p>
<p>Exemple :</p>
<p>Prenons le chiffre 9. Dans l'image il peut être représenté de cette manière :</p>
<p><a class="glightbox" href="Images/Figma/Bad9Example.png"><img alt='"Bad9Exemple"' src="Images/Figma/Bad9Example.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Bad9Example.png"><img alt="" bad9exemple""="" src="./Images/Figma/Bad9Example.png"/></a>
<figcaption>"Bad9Exemple"</figcaption>
</figure>
<p>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.</p>
<p>Cependant comme les contours sont flous et même si on essaie de retirer le background :</p>
<p><a class="glightbox" href="Images/Figma/Aliased9.png"><img alt='"Aliased 9"' src="Images/Figma/Aliased9.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Aliased9.png"><img 9""="" aliased="" alt="" src="./Images/Figma/Aliased9.png"/></a>
<figcaption>"Aliased 9"</figcaption>
</figure>
<p>On voit que le 9 n'est pas clairement définit. En effet on pourrait le comprendre comme :</p>
<p><a class="glightbox" href="Images/Figma/Horrible9.png"><img alt='"First contour"' src="Images/Figma/Horrible9.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Horrible9.png"><img alt="" contour""="" first="" src="./Images/Figma/Horrible9.png"/></a>
<figcaption>"First contour"</figcaption>
</figure>
<p>Ou comme :</p>
<p><a class="glightbox" href="Images/Figma/Clean9Example.png"><img alt='"Second contour"' src="Images/Figma/Clean9Example.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Clean9Example.png"><img alt="" contour""="" second="" src="./Images/Figma/Clean9Example.png"/></a>
<figcaption>"Second contour"</figcaption>
</figure>
<p>Voire même simplement comme :</p>
<p><a class="glightbox" href="Images/Figma/Filled9.png"><img alt='"Big contour"' src="Images/Figma/Filled9.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Figma/Filled9.png"><img alt="" big="" contour""="" src="./Images/Figma/Filled9.png"/></a>
<figcaption>"Big contour"</figcaption>
</figure>
<p>Et on se rend bien compte que les performances de detection ne sont pas les mêmes dans ces trois cas.</p>
<p>Il faut donc faire un certain post traitement des images pour supprimer les éléments parasites, les couleurs, et augmenter la visibilité des contours importants.</p>
<p>Mais chaque type de donnée va avoir des methodes de post traitement différents.</p>
@@ -1253,17 +1371,32 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<p>C'est je pense la plus simple de toutes car Tesseract est particulièrement bien entrainé pour.</p>
<p>Cette reconnaissance concerne donc des lettres qui font des mots ou des noms.</p>
<p>Voici un exemple de la WINDOW nom de pilote en entrée :</p>
<p><a class="glightbox" href="Images/Screens/ExempleTextRaw.png"><img alt='"Exemple raw"' src="Images/Screens/ExempleTextRaw.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleTextRaw.png"><img alt="" exemple="" raw""="" src="./Images/Screens/ExempleTextRaw.png"/></a>
<figcaption>"Exemple raw"</figcaption>
</figure>
<p>Ce texte peut paraitre bon, cependant quand on le lance dans Tesseract, il ne va pas toujours donner un résultat parfait. Il faut aussi savoir qu'il y a des noms pas mal plus pénibles que Tesseract 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).</p>
<p>Donc pour le rendre plus facilement lisible et augmenter les chances que toutes les lettres soient découvertes, voici les étapes que j'ai mis en place.</p>
<p>1 : J'inverse les couleurs. Je me suis rendu compte 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.</p>
<p><a class="glightbox" href="Images/Screens/ExempleTextINvertColor.png"><img alt='"Texte inversé"' src="Images/Screens/ExempleTextINvertColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleTextINvertColor.png"><img alt="" inversé""="" src="./Images/Screens/ExempleTextINvertColor.png" texte=""/></a>
<figcaption>"Texte inversé"</figcaption>
</figure>
<p>2 : Je fais un <em>Treshhold</em> de 165 car avec moins le texte parfois prend trop du background et avec plus les lettres sont trop fines.</p>
<p><a class="glightbox" href="Images/Screens/ExempleTextTresholding.png"><img alt='"Treshold"' src="Images/Screens/ExempleTextTresholding.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleTextTresholding.png"><img alt="" src="./Images/Screens/ExempleTextTresholding.png" treshold""=""/></a>
<figcaption>"Treshold"</figcaption>
</figure>
<p>3 : Je fais un <em>Resize</em> de l'image pour avoir une meilleure résolution et permettre une meilleure détection. J'augmente la hauteur et la largeur par un facteur 2. J'ai trouvé cette valeur suffisante et aller plus haut consomme beaucoup de ressources.</p>
<p><a class="glightbox" href="Images/Screens/ExempleTextResize.png"><img alt='"Resize"' src="Images/Screens/ExempleTextResize.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleTextResize.png"><img alt="" resize""="" src="./Images/Screens/ExempleTextResize.png"/></a>
<figcaption>"Resize"</figcaption>
</figure>
<p>4: Je fais une très rapide <em>Dilatation</em> 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.</p>
<p><a class="glightbox" href="Images/Screens/ExempleTextDilatation.png"><img alt='"Dilatation"' src="Images/Screens/ExempleTextDilatation.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleTextDilatation.png"><img alt="" dilatation""="" src="./Images/Screens/ExempleTextDilatation.png"/></a>
<figcaption>"Dilatation"</figcaption>
</figure>
<p><em>Explication des methodes précises plus bas</em></p>
<p>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.</p>
<p>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.</p>
@@ -1290,20 +1423,38 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<p>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.</p>
<p>Cependant, tous ces temps possèdent le même type de post-traitement avant d'être envoyés à Tesseract.</p>
<p>Voici un exemple de temps au tour avant toute transformation :</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeBefore.png"><img alt='"Lap time"' src="Images/Screens/ExempleLapTimeBefore.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeBefore.png"><img alt="" lap="" src="./Images/Screens/ExempleLapTimeBefore.png" time""=""/></a>
<figcaption>"Lap time"</figcaption>
</figure>
<p>On peut avoir l'impression que ce texte est tout à fait lisible et facile à décoder surtout quand on le voit de loin comme 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.</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeBeforeUpscaled.png"><img alt='"Lap time"' src="Images/Screens/ExempleLapTimeBeforeUpscaled.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeBeforeUpscaled.png"><img alt="" lap="" src="./Images/Screens/ExempleLapTimeBeforeUpscaled.png" time""=""/></a>
<figcaption>"Lap time"</figcaption>
</figure>
<p>Si on donne cette image à Tesseract, les '3' deviennent des '9', des '9' deviennent des '8', des '2' deviennent eux aussi des '9', le tout parfois inversement et de manière complêtement imprévisible. Ca n'est simplement pas utilisable.</p>
<p>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.</p>
<p>Voici donc les étapes de post-traitement que j'ai mis en place pour leur détection :</p>
<p>1: J'applique un <em>Treshold</em> de 185 pour enlever les 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.</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeTreshold.png"><img alt='"Treshold"' src="Images/Screens/ExempleLapTimeTreshold.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeTreshold.png"><img alt="" src="./Images/Screens/ExempleLapTimeTreshold.png" treshold""=""/></a>
<figcaption>"Treshold"</figcaption>
</figure>
<p>2: J'applique un <em>Resize</em> de 2 pour augmenter la résolution des chiffres et permettre une meilleure détection. Le but est d'avoir plus de pixels et donc de permettre à Tesseract de mieux utiliser ses matrices de convolution.</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeResize.png"><img alt='"Resize"' src="Images/Screens/ExempleLapTimeResize.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeResize.png"><img alt="" resize""="" src="./Images/Screens/ExempleLapTimeResize.png"/></a>
<figcaption>"Resize"</figcaption>
</figure>
<p>3: Comme le <em>Resize</em> amène du flou, j'utilise une methode de Dilatation<em> qui me permet de retirer ce flou et de remplir un peu plus certaines parties qui ont été un peu laissée par le </em>Resize*;</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeDilatation.png"><img alt='"Dilatation"' src="Images/Screens/ExempleLapTimeDilatation.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeDilatation.png"><img alt="" dilatation""="" src="./Images/Screens/ExempleLapTimeDilatation.png"/></a>
<figcaption>"Dilatation"</figcaption>
</figure>
<p>4: Contrairement aux mots plus haut, la rondeur ajoutée par la dilatation n'est pas vraiment désirée. En effet, elle peut rendre confuse certains chiffres et empêcher Tesseract de bien trouver le chiffre. Alors j'applique une <em>Erosion</em> qui me permet de contrecarrer en partie les rondeurs ajoutées par la dilatation et retrouver des chiffres bien formées. Pour l'<em>Erosion</em> et la <em>Dilatation</em> j'ai utilisé une valeur de 1 car je ne voulais pas trop changer les chiffres.</p>
<p><a class="glightbox" href="Images/Screens/ExempleLapTimeErode.png"><img alt='"Erode"' src="Images/Screens/ExempleLapTimeErode.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/ExempleLapTimeErode.png"><img alt="" erode""="" src="./Images/Screens/ExempleLapTimeErode.png"/></a>
<figcaption>"Erode"</figcaption>
</figure>
<p><em>Explication des methodes précises plus bas</em></p>
<p>Et avec ce post processing on retrouve de plutôts bon résultats qui demandent peu de traitement.</p>
<p>Le traitement dépend du type de WINDOW cependant.</p>
@@ -1333,18 +1484,33 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<li>Les pneus intermédiaires</li>
<li>Les pneus pluie</li>
</ul>
<p><a class="glightbox" href="Images/Photos/Tyres.png"><img alt='"Tyres"' src="Images/Photos/Tyres.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/Tyres.png"><img alt="" src="./Images/Photos/Tyres.png" tyres""=""/></a>
<figcaption>"Tyres"</figcaption>
</figure>
<p>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.</p>
<p>Chaque pneu a sa durée de vie et son niveau de performance propre mais je ne vais pas rentrer dans le détail ici. Tout ce qu'il faut savoir ce que savoir sur quel pneu chaque pilote est et depuis combien de temps il les chausse est une information très importante.</p>
<p>Chaque pneu a une couleur donnée qui permet de les différencier.</p>
<p>Voici un exemple de ce à quoi une WINDOW de pneus peut ressembler :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneExemple3.png"><img alt='"Exemple 1"' src="Images/Screens/TyreZoneExemple3.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple3.png"><img 1""="" alt="" exemple="" src="./Images/Screens/TyreZoneExemple3.png"/></a>
<figcaption>"Exemple 1"</figcaption>
</figure>
<p>Mais cette zone peut aussi ressembler à ca :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneExemple2.png"><img alt='"Exemple 2"' src="Images/Screens/TyreZoneExemple2.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple2.png"><img 2""="" alt="" exemple="" src="./Images/Screens/TyreZoneExemple2.png"/></a>
<figcaption>"Exemple 2"</figcaption>
</figure>
<p>Mais aussi à ca :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneExemple1.png"><img alt='"Exemple 3"' src="Images/Screens/TyreZoneExemple1.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple1.png"><img 3""="" alt="" exemple="" src="./Images/Screens/TyreZoneExemple1.png"/></a>
<figcaption>"Exemple 3"</figcaption>
</figure>
<p>Voire même ca :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneExemple4.png"><img alt='"Exemple 4"' src="Images/Screens/TyreZoneExemple4.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneExemple4.png"><img 4""="" alt="" exemple="" src="./Images/Screens/TyreZoneExemple4.png"/></a>
<figcaption>"Exemple 4"</figcaption>
</figure>
<p>Je pense que vous pouvez tout de suite comprendre la difficulté que représente la tâche de récupèration de données à partir de cette image.</p>
<p>En gros le fonctionnement de cette zone d'information est assez simple.</p>
<ul>
@@ -1359,28 +1525,55 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<p>Le programme va tirer un trait depuis le bord droit de la zone, et il va avancer vers la gauche jusqu'à trouver un obstacle. Je détecte un obstacle si le pixel sur lequel est mon trait possède une valeur de plus de 0x50 dans le channel R,G ou B. J'ai trouvé en faisant des tests que les couleurs de background de la F1TV ne dépassaient jamais ces valeurs.</p>
<p>Ensuite après avoir trouvé le premier obstacle, je récupère une zone qui doit englober le cercle.</p>
<p>Voici un exemple avec cette image en entrée :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneFull.png"><img alt='"Full zone"' src="Images/Screens/TyreZoneFull.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneFull.png"><img alt="" full="" src="./Images/Screens/TyreZoneFull.png" zone""=""/></a>
<figcaption>"Full zone"</figcaption>
</figure>
<p>Elle est automatiquement coupée de cette facon :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneCropped.png"><img alt='"Cropped zone"' src="Images/Screens/TyreZoneCropped.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneCropped.png"><img alt="" cropped="" src="./Images/Screens/TyreZoneCropped.png" zone""=""/></a>
<figcaption>"Cropped zone"</figcaption>
</figure>
<p>Cela me permet d'isoler uniquement ce qui m'intéresse ce qui est très pratique pour Tesseract et pour la detection de couleur.</p>
<p>Ensuite avec cette image je peux commencer le processus de reconnaissance.</p>
<p>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.</p>
<p>Ensuite j'utilise une methode qui calcule la différence entre la couleur obbtenue et la liste de couleurs possible.</p>
<p>Il y a cinq couleurs des pneus possibles :</p>
<p>"#ff0000" pneu tendre/soft</p>
<p><a class="glightbox" href="Images/Photos/SoftTyreColor.png"><img alt='"Soft tyre color"' src="Images/Photos/SoftTyreColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/SoftTyreColor.png"><img alt="" color""="" soft="" src="./Images/Photos/SoftTyreColor.png" tyre=""/></a>
<figcaption>"Soft tyre color"</figcaption>
</figure>
<p>"#f5bf00" pneu medium</p>
<p><a class="glightbox" href="Images/Photos/MediumTyreColor.png"><img alt='"medium tyre color"' src="Images/Photos/MediumTyreColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/MediumTyreColor.png"><img alt="" color""="" medium="" src="./Images/Photos/MediumTyreColor.png" tyre=""/></a>
<figcaption>"medium tyre color"</figcaption>
</figure>
<p>"#a4a5a8" pneu dur/hard</p>
<p><a class="glightbox" href="Images/Photos/HardTyreColor.png"><img alt='"Hard tyre color"' src="Images/Photos/HardTyreColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/HardTyreColor.png"><img alt="" color""="" hard="" src="./Images/Photos/HardTyreColor.png" tyre=""/></a>
<figcaption>"Hard tyre color"</figcaption>
</figure>
<p>"#00a42e" pneu inter</p>
<p><a class="glightbox" href="Images/Photos/IntermediateTyreColor.png"><img alt='"Inter tyre color"' src="Images/Photos/IntermediateTyreColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/IntermediateTyreColor.png"><img alt="" color""="" inter="" src="./Images/Photos/IntermediateTyreColor.png" tyre=""/></a>
<figcaption>"Inter tyre color"</figcaption>
</figure>
<p>"#2760a6" pneu pluie/wet</p>
<p><a class="glightbox" href="Images/Photos/WetTyreColor.png"><img alt='"Wet tyre color"' src="Images/Photos/WetTyreColor.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/WetTyreColor.png"><img alt="" color""="" src="./Images/Photos/WetTyreColor.png" tyre="" wet=""/></a>
<figcaption>"Wet tyre color"</figcaption>
</figure>
<p>Ce qui est pratique c'est que même dans les cas ou il n'y a pas beaucoup de couleur comme celui la :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneHard.png"><img alt='"Hard tyre but only the letter"' src="Images/Screens/TyreZoneHard.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneHard.png"><img alt="" but="" hard="" letter""="" only="" src="./Images/Screens/TyreZoneHard.png" the="" tyre=""/></a>
<figcaption>"Hard tyre but only the letter"</figcaption>
</figure>
<p>On arrive à une couleur moyenne de :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneHardAVG.png"><img alt='"The average color from the picture above"' src="Images/Screens/TyreZoneHardAVG.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneHardAVG.png"><img above""="" alt="" average="" color="" from="" picture="" src="./Images/Screens/TyreZoneHardAVG.png" the=""/></a>
<figcaption>"The average color from the picture above"</figcaption>
</figure>
<p>Et il est donc assez facile de determiner le type de pneu en question.</p>
<p>Attention, les résultats peuvent être très vite dérangés par la couleur du pneu précédent si le découpage de la fenêtre n'a pas été assez précis.</p>
<p>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.</p>
@@ -1388,15 +1581,27 @@ On peut y voir au moins 4 zones contenant de l'information dans un format diffé
<p>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.</p>
<p>Il faut donc retirer le background et ensuite la couleur. Sauf que comme le chiffre est de la couleur du background, si on retire le background et ensuite la couleur il ne reste plus rien. Il faut donc retirer le background AUTOUR du rond, et ensuite si on retire la couleur il devrait rester le chiffre sur fond blanc.</p>
<p>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 :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneCropedWithoutBackGround.png"><img alt='"No outer background"' src="Images/Screens/TyreZoneCropedWithoutBackGround.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneCropedWithoutBackGround.png"><img alt="" background""="" no="" outer="" src="./Images/Screens/TyreZoneCropedWithoutBackGround.png"/></a>
<figcaption>"No outer background"</figcaption>
</figure>
<p>Ensuite on peu retirer les pixels qui ont une valeur dans un channel RGB plus haute qu'un certain seuil :</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneFilter1.png"><img alt='"Only digit"' src="Images/Screens/TyreZoneFilter1.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneFilter1.png"><img alt="" digit""="" only="" src="./Images/Screens/TyreZoneFilter1.png"/></a>
<figcaption>"Only digit"</figcaption>
</figure>
<p>Et la on a ce que l'on veut !</p>
<p>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.</p>
<p>1 : On effectue un <em>Resize</em> de facteur 4 (oui c'est beaucoup mais en même temps le chiffre est vraiment petit à la base) qui permet d'avoir une image d'une bien meilleure résolution.</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneFilter2.png"><img alt='"Filter 1"' src="Images/Screens/TyreZoneFilter2.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneFilter2.png"><img 1""="" alt="" filter="" src="./Images/Screens/TyreZoneFilter2.png"/></a>
<figcaption>"Filter 1"</figcaption>
</figure>
<p>2: On fait une <em>Dilatation</em> de facteur 1 pour retirer tout le flou de l'image pour aider Tesseract</p>
<p><a class="glightbox" href="Images/Screens/TyreZoneAfter.png"><img alt='"Result"' src="Images/Screens/TyreZoneAfter.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Screens/TyreZoneAfter.png"><img alt="" result""="" src="./Images/Screens/TyreZoneAfter.png"/></a>
<figcaption>"Result"</figcaption>
</figure>
<p>Et on a un chiffre qui est utilisable par Tesseract !</p>
<p><em>Explication des methodes précises plus bas</em></p>
<p>Pour résumer :</p>
@@ -1419,7 +1624,10 @@ Voici un sommaire des methodes utilisées et comment elles fonctionnent.</p>
<p>Cette methode sert à passer d'une image en couleurs à une image binaire noir blanc.
C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'isoler du texte de son background.</p>
<p>Un exemple ici :</p>
<p><a class="glightbox" href="Images/Photos/TresholdExemple1.webp"><img alt='"Exemple treshold"' src="Images/Photos/TresholdExemple1.webp"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/TresholdExemple1.webp"><img alt="" exemple="" src="./Images/Photos/TresholdExemple1.webp" treshold""=""/></a>
<figcaption>"Exemple treshold"</figcaption>
</figure>
<p>Le fonctionnement est assez simple mais il peut être fait de différentes manières mais dans mon cas voici comment l'algorythme fonctionne sachant qu'il demande en entrée la Bitmap que l'on veut modifier ainsi que la valeur de Treshold :</p>
<ol>
<li>On parcours chaque pixel de l'image</li>
@@ -1431,13 +1639,25 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
<p><em>Resize</em></p>
<p>Cette 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.</p>
<p>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 :</p>
<p><a class="glightbox" href="Images/Photos/InterpolationExemple.png"><img alt='"Interpolation exemple"' src="Images/Photos/InterpolationExemple.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/InterpolationExemple.png"><img alt="" exemple""="" interpolation="" src="./Images/Photos/InterpolationExemple.png"/></a>
<figcaption>"Interpolation exemple"</figcaption>
</figure>
<p>Dans mon projet j'utilise de l'interpolation bicubique qui va créer de l'information pour tenter de combler le vide et produire une image réellement plus grande et avec plus de details mais en ajoutant du flou.</p>
<p><a class="glightbox" href="Images/Photos/BicubicExample.png"><img alt='"bicubic exemple"' src="Images/Photos/BicubicExample.png"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/BicubicExample.png"><img alt="" bicubic="" exemple""="" src="./Images/Photos/BicubicExample.png"/></a>
<figcaption>"bicubic exemple"</figcaption>
</figure>
<p>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.</p>
<p>Voici un exemple assez parlant :</p>
<p><a class="glightbox" href="Images/Photos/BicubicExample1.webp"><img alt='"bicubic demonstration"' src="Images/Photos/BicubicExample1.webp"/></a></p>
<p><a class="glightbox" href="Images/Photos/BicubicExample2.webp"><img alt='"bicubic demonstration"' src="Images/Photos/BicubicExample2.webp"/></a></p>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/BicubicExample1.webp"><img alt="" bicubic="" demonstration""="" src="./Images/Photos/BicubicExample1.webp"/></a>
<figcaption>"bicubic demonstration"</figcaption>
</figure>
<figure class="figure-image">
<a class="glightbox" href="./Images/Photos/BicubicExample2.webp"><img alt="" bicubic="" demonstration""="" src="./Images/Photos/BicubicExample2.webp"/></a>
<figcaption>"bicubic demonstration"</figcaption>
</figure>
<p>On pourrait croire que c'est inutile mais dans le contexte de Tesseract ajouter des détails pour tenter de simuler une meilleure résolution même en créant du flou est intéressant pour mieux remplir la matrice de convolution.</p>
<p>Mais il est possible de réduire ce flou avec d'autres méthodes également.</p>
<p>(Dans mon code je n'ai pas utilisé du code fait main mais j'utilise une librairie qui me permet de le faire)</p>
@@ -1472,7 +1692,7 @@ C'est une étape très importante pour l'OCR car elle permet (si bien faite) d'i
</main>
<footer class="md-footer">
<nav aria-label="Footer" class="md-footer__inner md-grid">
<a aria-label="Next: Cahier des charges" class="md-footer__link md-footer__link--next" href="CahierDesCharges/" rel="next">
<a aria-label="Next: Cahier des charges" class="md-footer__link md-footer__link--next" href="CahierDesCharges.html" rel="next">
<div class="md-footer__title">
<div class="md-ellipsis">
<span class="md-footer__direction">