Les extractions de formes élémentaires (lignes, arcs) du caractère scanné s'étant avérées suffisamment stables, nous avons commencé à implémenter un module de reconnaissance proprement dit. Une série de caractères connus (16000 caractères issus de diverses fontes) est envoyée à l'extracteur, et les formes élémentaires ainsi obtenues sont stockées. Une fois cet apprentissage terminé, une autre série de caractères, issus d'une page scannée cette fois, est envoyée au programme, qui, en les comparant à ce qu'il a stocké lors de l'apprentissage, essaie de déterminer de quels caractères il s'agit. Premiers essais. Le programme n'est pas aveugle, mais un peu myope. Il commet des erreurs, mais donne généralement comme résultat un caractère assez proche (Q au lieu de O, c au lieu de e, etc.) Il faut maintenant essayer d'améliorer tout cela. |
|
|
by Olivier Guillion | | | |
|
Pour faire suite au dernier billet, nous avons amélioré la recherche de formes élémentaires dans les images scannées. En plus des segments de droites, nous avons ajouté des arcs de cercle. Voici ce que cela donne avec les caractères pris en exemple la dernière fois. A gauche, l'image originale du caractère scanné, au centre, les primitives graphiques qui en ont été extraites, dessinées en lignes fines, et à droite, les mêmes, dessinées en lignes épaisses: Certaines lignes dépassent, car les calculs prennent en compte les bords extérieurs de la forme d'origine. Les formes extraites sont donc généralement trop longues d'une demi-épaisseur du tracé du caractère scanné. Ce sera ajusté, si besoin est. Il nous reste maintenant à trouver une manière efficace de comparer ces données à un jeu de référence. Nous planchons toujours là-dessus. |
|
|
by Olivier Guillion | | |
| |
|
Pour reconnaître un caractère, il faut pouvoir le comparer à un ou plusieurs caractères de référence, afin d'en déduire un niveau de similarité. Mais quelles données comparer? La présence de pixels allumés ou éteints à tel ou tel endroit ? Cela est trop sensible à la fonte utilisé, la taille, le "bruit" dû aux imperfections du papier ou du scan... Il faut donc fournir à l'algorithme de classification des données sur le caractère scanné à reconnaître, qui soient à la fois peu nombreuses, pour faciliter et accélérer les comparaisons, mais également qui décrivent bien la forme du caractère, pour que l'algorithme ait suffisamment de matériel pour discriminer. Si l'extraction des caractéristiques de l'image du caractère scanné fournit des données qui, quelle que soit la manière dont on les représente, ne permettent pas à un observateur humain de savoir de quel caractère il s'agissait, il y a fort à parier qu'un algorithme ne le pourra pas non plus (ou mal). Dans cette optique, nous avons essayé de "vectoriser" l'image, c'est-à-dire, à partir du dessin du caractère, trouver le nombre minimal de formes graphiques (droites, arcs de cercle, etc) qui permettent de redessiner ce caractère, et suffisantes pour qu'un observateur humain puisse déterminer de quel caractère il s'agissait. Le travail est complexe, mais nous sommes arrivés à d'assez bon résultats. En voici quelques exemples, en utilisant seulement des lignes droites : A gauche un petit "a" extrait d'un texte scanné. A droite, l'image décomposée (vectorisée) par l'algorithme en seulement 5 lignes droites Avec un peu d'imagination, on peut aisément reconnaitre le "a" dans le dessin de droite. Cela ressemble à un petit "a" tracé à la main par un allergique aux courbes Même chose avec un petit "d" (4 lignes) : Un "M" donne ceci (5 lignes, dont une pour le serif à gauche): et enfin un grand A, décomposé en seulement trois lignes: Les premiers résultats sont donc encourageants, car il réduisent grandement la quantité d'information fournie à l'algorithme. Il faut maintenant vérifier la stabilité de l'extraction des vecteurs, puis trouver comment comparer deux jeux de vecteurs afin de reconnaître la lettre. Il n'est cependant pas encore certain que ce type de traitement sera retenu dans la version finale. Nous avons jusqu'ici développé une vingtaine d'algorithmes différents, avec plus ou moins de succès. Nous en conserverons, au final, un maximum de 3 ou 4. Tous les autres finiront à la poubelle |
|
|
by Olivier Guillion | | | |
|
Toujours à la recherche de l'algorithme parfait de reconnaissance de caractère, l'intuition rejoint les conclusions de la documentation disponible à ce sujet : un tel algorithme n'existe pas. Certains sont efficaces, d'autres un peu moins, mais les meilleurs résultats finaux sont produits par des programmes qui utilisent plusieurs algorithmes à la fois. Chacun analyse le dessin du caractère avec ses propres méthodes, s'attache plus précisément à tels ou tels aspects, le compare avec des caractères de référence qui lui sont propres. A la fin, les résultats de tous les algorithmes sont comparés, et l'issue finale de la reconnaissance de ce caractère est soumise au vote. Le gagnant est celui qui a été reconnu par le maximum d'algorithmes. Les taux globaux de reconnaissance sont, par ce principe, grandement améliorés. De là à généraliser, et avancer que l'union et la démocratie sont préférables à l'individualisme et la dictature... |
|
|
by Olivier Guillion | | | |
|
Nous sommes maintenant capables de faire à peu près ce que nous voulons sur l'aspect du caractère : en extraire un squelette, détecter les trous et les bosses, les parties indépendantes au sein d'un même caractère (par exemple les point et la virgule d'un point-virgule, ou le "e" et son accent dans "é") et diverses données statistiques. Il nous reste maintenant à choisir l'algorithme qui va déterminer la nature de ce caractère, par comparaison avec un jeu de référence (algorithme de discrimination). Nous avons déjà exploré plusieurs possibilités, allant de la simple comparaison de matrice à un filtre bayesien, un réseau de neurones, la construction d'un arbre de décision, ou les modèles de Markov cachés (HMM) Plusieurs de ces techniques s'avèrent efficaces, mais le résultat de l'apprentissage est difficile à vérifier à posteriori. On obtient une série de chiffres dont la signification n'est pas évidente pour l'observateur humain. En résumé, ça marche, mais c'est une boîte noire. Or la pertinence des données que nous extrayons de la forme du caractère et qui servent à alimenter l'algorithme de discrimination est cruciale. Il faut fournir à cet algorithme les données permettant de différencier le mieux possible chacun des caractères. Si nous envoyons ces données vers une boîte noire, nous ne pouvons pas savoir quel paramètre mériterait d'être affiné ou remplacé par un autre pour de meilleurs résultats. On peut simplement essayer, et voir si le résultat s'améliore. Cela revient un peu à tirer des flèches les yeux bandés en essayant de s'approcher du centre de la cible. Nous travaillons donc dans ce sens, en expérimentant et en recherchant de la documentation. Cela risque de prendre un peu de temps... |
|
|
by Olivier Guillion | | | |
|
Afin de simplifier les comparaisons de caractères , nous avons travaillé sur la squelettisation. Ce procédé permet de transformer des formes pleines en "fil de fer". Grâce à cela, on pourrait s'affranchir des épaisseurs de caractères, pour ne conserver que les données constituant effectivement la forme. A partir de notre texte d'exemple: nous avons appliqué l'algorithme de Zang-Suen, assorti d'un amincissement maximal. Sur un squelette, on pourrait appeler ça une décalcification : Un autre algorithme de squelettisation, morphologique, celui-là, suivi de la "décalcification", donne des résultats légèrement différents : Certains détails sont mieux conservés, mais de petites barres matérialisent l'épaisseur d'origine du caractère à certains endroits. Peut-être qu'avec un bon élagage de ces petites branches, nous pourrons nous en servir, en conjonction avec le squelette précédent. Nous nous attaquons maintenant aux méthodes de discrimination, c'est-à-dire le coeur de la reconnaissance proprement dite. Cela risque d'être plus difficile de montrer les résultats ici, de manière graphique. |
|
|
by Olivier Guillion | | | |
|
|