Passer au contenu principal
Par souci de simplicité, un document d’une seule page est utilisé dans cet exemple.
Dans le traitement de documents, il arrive souvent qu’il ne suffise pas de décrire l’emplacement des éléments les uns par rapport aux autres en termes du type « au-dessus - en dessous - à droite - à gauche ». Cela peut se produire, par exemple, si, dans la zone de recherche, plusieurs objets correspondent aux contraintes de recherche. Dans ce type de situation, des propriétés distinctives supplémentaires sont nécessaires, notamment la distance entre les objets. À cette fin, FlexiLayout Studio propose la fonction FuzzyQuality, ainsi que les fonctions du groupe Nearest (Nearest, NearestX, NearestY). Les applications de ces fonctions sont différentes. La fonction Nearest ne peut être utilisée que dans le champ relations avancées de pré-recherche. Elle indique que, parmi les différentes hypothèses de l’élément, le programme doit rechercher celle qui est la plus proche d’un certain élément ou point de l’ensemble d’images défini dans les propriétés de la fonction Nearest. Dans le champ relations avancées de pré-recherche de l’élément, une seule fonction du groupe Nearest peut être utilisée. Après son exécution, il ne reste qu’une seule hypothèse, et cela se produit à l’étape de génération des hypothèses, c’est-à-dire avant l’exécution du code spécifié dans le champ Advanced post-search relations. Le paramètre Minimum quality, qui spécifie la qualité minimale des hypothèses pour l’élément, peut être défini pour les éléments StaticText, CharacterString, Paragraph, Date et Separator. Rien ne garantit que l’hypothèse restante soit la meilleure (et corresponde à l’objet recherché dans l’image), car la section Advanced post-search relations joue un rôle très important dans l’attribution d’une valeur de qualité à une hypothèse. Lors de l’utilisation de la fonction Nearest, le choix de l’hypothèse est effectué à l’étape de génération des hypothèses et repose sur la proximité avec un certain point, et non sur la qualité de l’hypothèse. Il faut toujours garder à l’esprit que, si les propriétés spécifiées dans la section Advanced post-search relations sont importantes pour sélectionner correctement l’hypothèse, vous devez utiliser la fonction FuzzyQuality au lieu des fonctions du groupe Nearest. La fonction FuzzyQuality ne peut être utilisée que dans la section Advanced post-search relations. Contrairement aux fonctions du groupe Nearest, elle ne sélectionne pas une seule hypothèse, mais influe sur la qualité globale de toutes les hypothèses générées en fonction des propriétés de ces hypothèses et des paramètres de la fonction FuzzyQuality. En outre, la fonction FuzzyQuality peut être utilisée plusieurs fois pour un même élément dans le champ Advanced post-search relations. Cela signifie que plusieurs contraintes différentes, associées à différentes valeurs de qualité, peuvent être appliquées à une hypothèse. Toutes les valeurs seront multipliées pour déterminer la qualité après recherche de l’hypothèse. La fonction FuzzyQuality se présente comme suit : FuzzyQuality: x, {f1, f2, f3, f4}; Son algorithme est le suivant : la fonction vérifie si la valeur du paramètre x appartient à l’intervalle défini par les paramètres f1, f2, f3, f4. La signification de cet intervalle flou est similaire à celle des intervalles flous spécifiés pour certains paramètres de l’élément Character String. Voyons comment les fonctions Nearest et FuzzyQuality peuvent être utilisées sur les images suivantes.
Comme on peut le voir sur les images, la facture est semi-structurée, car la disposition des champs diffère d’une image à l’autre. Nous allons détecter les champs « Numéro de facture » et « Date de la facture ». Pour ce faire, nous avons créé le projet 1.fsp (dossier %public%\ABBYY\FlexiCapture\12.0\Samples\FLS\Tips and Tricks\FuzzyAndNearest \Project1). Pour optimiser la structure du FlexiLayout et respecter la logique d’agencement des champs recherchés dans le document, nous avons regroupé tous les éléments recherchés dans un élément composé, InvoiceGroup. Nous pouvons commencer la création du FlexiLayout par celle d’un élément décrivant les contraintes de recherche du nom du champ “Numéro de facture”. Mais l’analyse des images montre que le mot “Invoice”, qui compose ce nom, apparaît plusieurs fois dans le document. Comme la position relative des champs change à chaque fois, nous ne pouvons pas définir de contraintes garantissant une détection correcte du mot “Invoice”. Il peut, par exemple, apparaître dans le nom “Date de la facture”. Pour éviter cette ambiguïté, nous avons commencé par décrire le nom du champ de date à l’aide d’un élément de type Static Text, nommé DateHeader. Dans le champ Search text, nous avons indiqué deux valeurs pour ce nom : Invoicedate:|Invoicedate (en listant les variantes telles qu’elles apparaissent sur les images). La casse du nom n’a pas d’importance. Nous allons rechercher le champ de date en nous appuyant sur son nom. Dans le projet, nous avons créé un groupe DateAlternative, composé de deux éléments : un élément Date pour rechercher le champ de date dans l’un des formats spécifiés, et un élément de type Character String au cas où le format du champ recherché serait différent.
Voir Détection des dates en cas de pré-reconnaissance de faible qualité pour une description détaillée de la création d’un FlexiLayout pour la recherche de dates.
Comme on le voit sur les images, le champ de date peut se trouver soit à droite du nom “Date de la facture”, soit en dessous. Si nous définissons des contraintes de recherche standard dans le champ Relations (elles sont affichées dans le projet, mais désactivées), la zone de recherche sera trop grande et pourra inclure certains champs susceptibles d’être pris à tort pour le champ de date (un exemple est montré sur l’image). Cela peut se produire, par exemple, si la date ne correspond pas au format spécifié pour l’élément Date.
Capture d’écran dans ABBYY FlexiLayout Studio montrant comment les contraintes Relations standard rendent la zone de recherche du champ de date trop grande, en englobant d’autres champs qui peuvent être pris par erreur pour le champ Date de la facture.
Pour éviter que le programme n’analyse une zone indésirable, nous avons utilisé une autre méthode. Dans le champ Relations avancées avant recherche, nous avons écrit le code suivant : let Header = InvoiceGroup.DateHeader; if not Header.IsNull then { let rect1 = Rect (Header.Rect.Right, Header.Rect.Top-20dt, PageRect.Right, Header.Rect.Bottom+20dt); let rect2 = Rect (Header.Rect.Left - 200dt, Header.Rect.Bottom, Header.Rect.Right + 150dt, Header.Rect.Bottom+200dt); RectArray ar; ar = RectArray ( rect1 ); ar.Add ( rect2 ); RestrictSearchArea( ar ); } else { Above: PageRect.Top + PageRect.Height/2; } Le code vérifie si le nom du champ de date a été trouvé. Si c’est le cas, nous définissons la zone de recherche comme un tableau de rectangles (dans l’exemple, 2 rectangles). Un rectangle recherche la date à droite du nom, l’autre en dessous. Si le nom n’est pas trouvé, la recherche sera effectuée dans la moitié supérieure de l’image. Pour une page dans laquelle les contraintes de recherche ont été définies dans la section Relations, la forme de la zone de recherche après l’exécution de ce code ne sera plus rectangulaire. Comme on le voit sur l’image, tous les objets indésirables en ont été retirés.
La première ligne du code (let Header = InvoiceGroup.DateHeader;) simplifie le code en définissant la variable Header et en lui affectant la valeur de l’élément DateHeader.
Capture d’écran dans ABBYY FlexiLayout Studio montrant la zone de recherche non rectangulaire du champ de date produite par le code RestrictSearchArea, avec tous les objets indésirables retirés.
Nous n’avons pas dupliqué le code ci-dessus pour l’élément DateAsString, mais avons écrit la contrainte de recherche suivante dans la section Relations avancées avant recherche : if not Date.IsNull then Dontfind(); else RestrictSearchArea (Date.Rect); Cela signifie que si l’élément Date n’est pas détecté, la recherche s’effectuera dans le rectangle englobant la zone de recherche de l’élément Date.
Pour définir la zone de recherche de l’élément DateAsString comme un tableau de rectangles, au lieu d’appeler RestrictSearchArea (Date.Rect), dupliquez le code correspondant de la section relations avancées de pré-recherche de l’élément Date.
Nous avons ensuite créé un élément de type Static Text (nommé InvoiceHeader) pour détecter l’intitulé du champ « Numéro de facture », et spécifié la valeur recherchée : « Invoice ». Comme le document n’est pas structuré, nous ne pouvons définir aucune contrainte de recherche spécifique. Une fois la procédure de mise en correspondance de FlexiLayout terminée, nous constatons que l’intitulé n’a été correctement détecté que sur la première page. Sur les pages 2 et 4, le mot « Invoice » a été détecté à tort dans l’intitulé du champ de date. Sur la page 3, il a été trouvé en bas de la page et, conformément à l’algorithme d’optimisation, les autres hypothèses de l’intitulé n’ont pas été générées, même si le mot « Invoice » apparaît trois fois dans l’image.
Voir Optimizing Group element search pour plus d’informations sur la recherche optimale des éléments du groupe.
Pour résoudre ces problèmes, nous avons utilisé la méthode suivante. Pour exclure de la zone de recherche du nom de champ « Invoice » la région correspondant à l’intitulé du champ de date, nous avons ajouté l’élément DateHeader à la section Exclude regions of elements (voir l’image ci-dessous).
Si nous avions commencé à créer le FlexiLayout non pas avec le nom DateHeader mais avec le nom InvoiceHeader, nous n’aurions pas pu utiliser la fonction Exclude, car cette fonction ne peut exclure que des éléments situés plus haut que l’élément actuel dans l’arborescence du projet.
Pour éviter la détection indésirable du mot « Invoice » en bas de la page, nous avons écrit le code suivant dans la section relations avancées de pré-recherche. NearestY: PageRect.Top; Ce code indique au programme de rechercher l’élément le plus proche du bord supérieur de la page. Une fois le FlexiLayout mis en correspondance, nous constatons que notre méthode a échoué sur la page 2, car l’intitulé du champ de date y est très parasité et n’a pas été détecté. Sur cette page, la contrainte spécifiée dans la fonction Nearest est vraie pour les deux chaînes « Invoice », car elles se trouvent au même niveau. Et comme la qualité de reconnaissance des chaînes « Invoice » est bonne dans les deux cas, l’algorithme d’optimisation a généré une seule hypothèse au lieu de deux hypothèses distinctes. Malheureusement, cette hypothèse n’est pas correcte. Pour détecter le champ « Numéro de facture », nous avons créé un élément de type Character String, nommé InvoiceNumber. Comme pour l’élément du champ de date, nous spécifions les contraintes de recherche du champ « Numéro de facture » dans la section relations avancées de pré-recherche. La zone de recherche de cet élément est un tableau de rectangles. let Header = InvoiceGroup.InvoiceHeader; if not Header.IsNull then { let rect1 = Rect (Header.Rect.Right, Header.Rect.Top-20dt, PageRect.Right, Header.Rect.Bottom+20dt); let rect2 = Rect (Header.Rect.Left - 200dt, Header.Rect.Bottom, Header.Rect.Right + 150dt, Header.Rect.Bottom+200dt); RectArray ar; ar = RectArray( rect1 ); ar.Add( rect2 ); RestrictSearchArea( ar ); } else { Above: PageRect.Top + PageRect.Height/2; } Nearest: Header; Nous avons en outre ajouté une contrainte supplémentaire au code. Nous avons indiqué au programme que l’élément InvoiceNumber est le plus proche de l’élément correspondant à l’intitulé. Après avoir exécuté la procédure de mise en correspondance, nous constatons que le champ « Numéro de facture » a été détecté incorrectement sur les pages 2 et 4. Il a également été détecté incorrectement sur la page 4, alors même que l’intitulé du champ avait été détecté correctement.
Comme autre possibilité (pour les images du projet actuel) au lieu de Nearest: Header;, nous pourrions écrire NearestY: Header.Rect.YCenter;, afin d’indiquer au programme que le champ recherché est, verticalement, le plus proche du centre de l’intitulé. Cela pourrait résoudre le problème de détection incorrecte du champ « Numéro de facture » sur la page 4. Mais cela n’aide pas sur la page 5, car le champ recherché est détecté dans le champ de date après la détection incorrecte de l’intitulé « Numéro de facture ».
Voyons maintenant comment nous pouvons utiliser la fonction FuzzyQuality dans une telle situation. Pour le démontrer, nous avons créé le projet 2.fsp (dossier FuzzyAndNearest\Project2). Les paramètres de ce projet sont presque identiques à ceux du projet décrit ci-dessus. Mais il y a une différence importante. Nous n’avons pas utilisé la fonction Nearest dans la section des relations avancées de pré-recherche. À la place, nous avons écrit le code suivant dans la section Advanced post-search relations : if not IsNull then { FuzzyQuality: Rect.Top - PageRect.Top, {0,0,0,50000} * dt; FuzzyQuality: 500dt-Width, {0,0,0,100000} * dt; if not InvoiceHeader.IsNull then { FuzzyQuality: Rect.XCenter - InvoiceHeader.Rect.XCenter, {-10000,0,0,50000} *dt; FuzzyQuality: Rect.YCenter - InvoiceHeader.Rect.YCenter, {-10000,0,0,10000} *dt; } } Avec cette méthode, nous pouvons agir sur la qualité de toutes les hypothèses sans en exclure aucune. Le choix de la meilleure chaîne sera effectué individuellement pour chaque chaîne, en multipliant les valeurs de qualité de toutes les hypothèses qui composent les éléments. La ligne FuzzyQuality: Rect.Top - PageRect.Top, {0,0,0,50000} * dt; signifie que, si une hypothèse non nulle est générée (la vérification if not IsNull est d’abord exécutée), la distance entre la position de l’élément et le bord supérieur de la page est déterminée. Autrement dit, la différence (Rect.Top - PageRect.Top) est calculée, puis le programme vérifie si cette différence appartient à l’intervalle {0, 0, 0, 50000}*dt. Cette définition de l’intervalle signifie qu’il existe une dépendance directe entre la pénalité de qualité et la distance entre l’élément et le bord supérieur de la page : plus la distance est grande, plus la pénalité est élevée. Comme le montre l’image (a), avec les valeurs de paramètres indiquées, la pénalité maximale (1) correspond à une distance de 50000dt, tandis qu’une distance de 1000 dots (1 dot = 1/300 de pouce) correspond à une pénalité de 0,02, et une distance de 100dt à une pénalité de 0,002.
Lorsque vous choisissez les paramètres qui définissent les limites de l’intervalle, vous devez veiller à ce qu’ils (en particulier lorsqu’il y a plusieurs vérifications d’éléments avec la fonction FuzzyQuality) ne pénalisent pas l’hypothèse correcte au point que sa qualité finale devienne inférieure à celle d’une hypothèse nulle. Si la qualité de toutes les hypothèses (y compris la bonne) est inférieure à la valeur de qualité d’une hypothèse nulle, l’hypothèse nulle peut être sélectionnée, c’est-à-dire que l’élément ne sera pas détecté.
(a) La ligne *FuzzyQuality: 500dt - Width, {0,0,0,100000}dt; signifie que le programme prend en compte l’écart entre la largeur de l’objet détecté et la valeur hypothétique de 500dt. Autrement dit, la différence (500dt - Width) est calculée, puis le programme vérifie si cette différence appartient à l’intervalle {0, 0, 0, 100000}*dt. Plus l’objet est étroit, plus la pénalité est élevée ; ainsi, les numéros de facture plus longs seront privilégiés. Cette contrainte peut être utilisée si l’image contient du bruit. Si le bruit est reconnu comme un caractère de l’alphabet spécifié (comme on peut le voir, par exemple, à la page 2), son hypothèse doit être pénalisée afin de l’exclure de l’analyse ultérieure.
La valeur de 500dt est choisie par examen visuel, en supposant que la longueur de la string dans le champ “Numéro de facture” ne dépasse pas cette valeur. Les paramètres indiqués ici définissent que la pénalité maximale (0,005) correspondrait à une largeur nulle du champ “Numéro de facture”. Pour toute autre largeur comprise entre 0 et 500dt, les pénalités de qualité seraient plus faibles.
La ligne *FuzzyQuality: Rect.XCenter - InvoiceHeader.Rect.XCenter, {-10000,0,0,50000} dt; signifie que si une hypothèse non nulle est générée pour l’élément correspondant au nom du champ « Numéro de facture » (la condition if not InvoiceHeader.IsNull est d’abord vérifiée), la distance entre le centre de l’élément détecté InvoiceNumber et le centre du nom InvoiceHeader est alors déterminée. La différence (Rect.XCenter - InvoiceHeader.Rect.XCenter) est calculée, puis le programme vérifie si cette différence appartient à l’intervalle {-10000, 0, 0, 50000}*dt. Cette description prend également en compte la possibilité que le champ « Numéro de facture » soit situé sous le nom. Dans ce cas, plus les éléments sont éloignés l’un de l’autre, plus la pénalité appliquée à l’hypothèse correspondante est élevée. Les hypothèses selon lesquelles le numéro se trouve à droite du nom seront moins pénalisées que celles selon lesquelles le numéro se trouve sous le nom, puisqu’il est évident que la disposition « à droite » du champ « Numéro de facture » par rapport à son nom est bien plus courante. Comme le montre l’image (b), avec les paramètres spécifiés pour les limites gauche et droite de l’intervalle, la pénalité maximale (1) correspondra à un décalage du champ « Numéro de facture » par rapport au champ du nom de 10000dt vers la gauche ou de 50000dt vers la droite. Un décalage de 1000 dot sera pénalisé de 0.1 s’il s’agit d’un décalage vers la gauche, ou de 0.02 s’il s’agit d’un décalage vers la droite. De même, un décalage de 100 dot sera pénalisé de 0.01 s’il s’agit d’un décalage vers la gauche, ou de 0.002 s’il s’agit d’un décalage vers la droite. (b) La ligne *FuzzyQuality: Rect.YCenter - InvoiceHeader.Rect.YCenter, {-10000,0,0,10000} dt; est identique à la précédente. Mais elle est réservée aux cas où le champ « Numéro de facture » se trouve au même niveau horizontal, voire légèrement au-dessus du champ du nom. Les pénalités y sont les mêmes pour tout décalage vertical. Les limites de l’intervalle sont définies selon la même logique, afin de privilégier les hypothèses qui trouvent le champ de données à droite de son nom. Cependant, le projet montre que ces paramètres n’ont pas empêché la détection correcte du numéro de facture même lorsqu’il était situé sous le nom (page 3). Après la mise en correspondance de FlexiLayout avec toutes les pages, nous constatons que les deux champs recherchés ont bien été détectés. En conclusion, nous pouvons dire que la fonction FuzzyQuality est plus efficace et plus souple que les fonctions du groupe Nearest, ce qui est particulièrement important pour le traitement de documents semi-structurés.