Passer au contenu principal
L’objectif de la classification de documents est d’attribuer les documents à différentes catégories prédéfinies. C’est très utile lorsque vous traitez un flux documentaire comprenant des documents de différents types et que vous devez identifier le type de chaque document. Par exemple, vous pouvez vouloir trier les contrats, les factures et les reçus dans des dossiers distincts, ou les renommer selon leur type. Cela peut se faire automatiquement à l’aide d’un système préentraîné. L’un des principaux aspects de la classification de documents est que vous connaissez à l’avance les types de documents à distinguer. ABBYY FineReader Engine peut classer les documents en fonction de leur contenu, des caractéristiques de l’image, ou en tenant compte à la fois des caractéristiques du texte reconnu et de l’image. Examinons le processus en détail. Il se compose de deux étapes principales :
  1. Création d’une base de données de classification
Pour chaque catégorie, choisissez plusieurs documents ou pages représentatifs. Ils serviront à créer la base de données de classification.
  1. Classification des documents
La base de données créée à l’étape précédente peut être utilisée pour classer les documents. Les documents entrants sont transmis à un système de classification préentraîné, qui s’appuie sur la base de données de classification pour déterminer leur catégorie. Vous pouvez également avoir besoin de classer les documents selon certains de leurs attributs, tels que l’auteur ou la valeur du code-barres. Cet article ne traite pas de ce type de classification. Si vous souhaitez classer des documents en fonction de leurs attributs, vous devrez implémenter vos propres algorithmes, qui peuvent utiliser les scénarios d’extraction de texte, de reconnaissance au niveau des champs ou de reconnaissance de codes-barres pour extraire les données. La procédure décrite ci-dessous est également illustrée par l’outil de démonstration Classification pour Windows et l’exemple de code Classification pour Linux et macOS.

Mise en œuvre du scénario

Les exemples de code fournis dans cette rubrique sont spécifiques à Windows.
Vous trouverez ci-dessous une description détaillée de la méthode recommandée pour utiliser ABBYY FineReader Engine afin de classer les documents.
Pour commencer à utiliser ABBYY FineReader Engine, vous devez créer l’objet Engine. L’objet Engine est l’objet de plus haut niveau dans la hiérarchie des objets d’ABBYY FineReader Engine et fournit différents paramètres globaux, certaines méthodes de traitement, ainsi que des méthodes permettant de créer les autres objets.Pour créer l’objet Engine, vous pouvez utiliser la fonction InitializeEngine. Voir également d’autres façons de charger l’objet Engine (Win).

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // Initialisez ces variables avec le chemin complet vers FREngine.dll, votre Customer Project ID,
        // et, le cas échéant, le chemin vers votre fichier de jeton de licence en ligne et le mot de passe de la licence en ligne
        string enginePath = "";
        string customerProjectId = "";
        string licensePath = "";
        string licensePassword = "";
        // Charger la bibliothèque FREngine.dll
        dllHandle = LoadLibraryEx(enginePath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
           
        try
        {
            if (dllHandle == IntPtr.Zero)
            {
                throw new Exception("Can't load " + enginePath);
            }
            IntPtr initializeEnginePtr = GetProcAddress(dllHandle, "InitializeEngine");
            if (initializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("Can't find InitializeEngine function");
            }
            IntPtr deinitializeEnginePtr = GetProcAddress(dllHandle, "DeinitializeEngine");
            if (deinitializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("Can't find DeinitializeEngine function");
            }
            IntPtr dllCanUnloadNowPtr = GetProcAddress(dllHandle, "DllCanUnloadNow");
            if (dllCanUnloadNowPtr == IntPtr.Zero)
            {
                throw new Exception("Can't find DllCanUnloadNow function");
            }
            // Convertir les pointeurs en délégués
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // Appeler la fonction InitializeEngine 
            // en transmettant le chemin vers le fichier de licence en ligne et le mot de passe de la licence en ligne
            int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, 
                "", "", false, ref engine);
            Marshal.ThrowExceptionForHR(hresult);
        }
        catch (Exception)
        {
            // Libérer la bibliothèque FREngine.dll
            engine = null;
            // Suppression de tous les objets avant l’appel à FreeLibrary
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            FreeLibrary(dllHandle);
            dllHandle = IntPtr.Zero;
            initializeEngine = null;
            deinitializeEngine = null;
            dllCanUnloadNow = null;
            throw;
        }
    }
    // Fonctions de Kernel32.dll
    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibraryEx(string dllToLoad, IntPtr reserved, uint flags);
    private const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
    [DllImport("kernel32.dll")]
    private static extern bool FreeLibrary(IntPtr hModule);
    // Fonctions de FREngine.dll
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    private delegate int InitializeEngine(string customerProjectId, string licensePath, 
        string licensePassword, string tempFolder, string dataFolder, bool isSharedCPUCoresMode, 
        ref FREngine.IEngine engine);
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DeinitializeEngine();
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DllCanUnloadNow();
    // Variables privées
    private FREngine.IEngine engine = null;
    // Handle de FREngine.dll
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}
Créez un objet ClassificationEngine, qui sert à créer les autres objets de l’API de classification. Utilisez la méthode CreateClassificationEngine de l’objet Engine.

C#

FREngine.IEngine engine;
FREngine.IClassificationEngine classEngine = engine.CreateClassificationEngine();
Les méthodes d’entraînement et de classification utilisent un type spécial d’objet créé à partir d’un document ou d’une page : ClassificationObject, qui contient toutes les informations utiles à la classification.Pour préparer un document en vue d’un scénario de classification, procédez comme suit :
  1. Chargez les images à traiter. Il existe plusieurs façons de procéder : par exemple, vous pouvez créer l’objet FRDocument à l’aide de la méthode CreateFRDocument de l’objet Engine, puis ajouter des images à l’objet FRDocument créé à partir d’un fichier à l’aide de la méthode AddImageFile.
  2. Si vous allez entraîner ou utiliser un classificateur du type qui prend en compte les caractéristiques textuelles (CT_Combined, CT_Text), commencez par reconnaître le document à l’aide de la méthode de votre choix. Nous utiliserons les méthodes Analyze et Recognize de l’objet FRDocument. La synthèse du document n’est pas nécessaire pour la classification.
Bien que le traitement parallèle ne soit pas pris en charge pour la classification elle-même, vous pouvez en avoir besoin pour la reconnaissance préparatoire des documents sous Windows et Linux. Si le nombre de documents que vous allez classer est important, nous vous recommandons d’utiliser Batch Processor ou d’autres méthodes de traitement parallèle décrites dans Parallel Processing with ABBYY FineReader Engine.
  1. Utilisez la méthode CreateObjectFromDocument de l’objet ClassificationEngine pour créer un ClassificationObject contenant les informations de la première page du document. Si vous devez utiliser une autre page du document, appelez la méthode CreateObjectFromPage.
  2. La propriété Description du ClassificationObject est vide par défaut. Renseignez cette propriété si vous avez besoin d’une description appropriée.
Il peut parfois arriver que le document ou la page, une fois reconnu, ne contienne néanmoins aucun texte reconnu (par exemple, si une page vide a été utilisée par erreur). Dans ce cas, le ClassificationObject ne peut pas être utilisé avec les classificateurs qui nécessitent des caractéristiques textuelles. Vous pouvez utiliser sa propriété SuitableClassifiers pour effectuer une vérification supplémentaire.

C#

// Créer l'objet FRDocument
FREngine.IFRDocument frDocument = engine.CreateFRDocument();
// Ajouter les images
frDocument.AddImageFile( "C:\\MyImage.tif", null, null );
// Facultatif : analyser et reconnaître le document
frDocument.Analyze( null, null, null );
frDocument.Recognize( null, null );
// Créer l'objet de classification
FREngine.IClassificationObject clObject = classEngine.CreateObjectFromDocument( frDocument );
// Indiquer dans la description la catégorie à laquelle l'objet appartient
clObject.Description = "CategoryA_Object1";
Pour entraîner un classificateur à distinguer plusieurs types de documents, vous avez besoin d’un jeu de données catégorisé contenant des échantillons de chaque type. Utilisez l’objet TrainingData pour constituer et gérer ce jeu de données :
  1. Créez un objet vide à l’aide de la méthode CreateTrainingData de l’objet ClassificationEngine.
  2. Accédez à la collection de catégories via sa propriété Categories.
  3. Utilisez plusieurs fois la méthode AddNew de l’objet Categories pour ajouter une catégorie pour chacun des types de documents que vous souhaitez classer. La méthode attend une string contenant le libellé de la catégorie en paramètre d’entrée. Ce libellé sera renvoyé par les méthodes de classification ; il doit donc être unique dans l’ensemble des catégories.
  4. Pour chaque objet Category nouvellement ajouté, ouvrez la collection d’objets de classification à l’aide de la propriété Objects. À l’aide de la méthode IClassificationObjects::Add, ajoutez les objets de classification correspondant à cette catégorie.
    Aucune catégorie ne peut rester vide. Pour des raisons évidentes, au moins deux catégories sont nécessaires pour l’entraînement.
  5. Une fois le jeu de données d’entraînement configuré, vous pouvez l’enregistrer dans un fichier sur disque pour une utilisation ultérieure : par exemple, si la précision du modèle entraîné s’avère insuffisante et que vous souhaitez ajouter ou corriger certaines données afin d’en améliorer la qualité. L’objet TrainingData fournit la méthode SaveToFile.

C#

FREngine.ITrainingData trainingData = classEngine.CreateTrainingData();
FREngine.ICategories categories = trainingData.Categories;
// Ajouter la première catégorie
FREngine.ICategory category = categories.AddNew( "CategoryA" );
// Ajouter les objets de classification préparés à l’étape 3
category.Objects.Add( clObject ); // répéter pour tous les objets de cette catégorie
...
// Répéter pour toutes les catégories
...
// Une fois toutes les catégories ajoutées, enregistrer le jeu de données d’entraînement
trainingData.SaveToFile( "C:\\trainingData.dat" );
Les fonctionnalités d’entraînement de modèle sont fournies par l’objet Trainer. Utilisez la méthode CreateTrainer de l’objet ClassificationEngine pour le créer.Il contient tous les paramètres relatifs au type de classifieur et à la procédure d’entraînement, répartis dans deux sous-objets : TrainingParams et ValidationParams. Identifiez les paramètres dont vous avez besoin et modifiez les propriétés correspondantes :
  • Le type de classificateur (ITrainingParams::ClassifierType). Ce paramètre détermine quelles caractéristiques du document sont prises en compte lors de l’attribution d’une catégorie : les caractéristiques de l’image, le contenu du texte reconnu ou les deux. Pour sélectionner un type qui utilise le contenu du texte, vous devez vous assurer que tous les objets de classification du jeu de données d’entraînement ont été créés à partir de documents préalablement reconnus.
  • Le mode d’entraînement (ITrainingParams::TrainingMode). Ce paramètre détermine si le processus d’entraînement doit privilégier une précision élevée (combien d’éléments sélectionnés sont corrects), un rappel élevé (combien d’éléments corrects sont sélectionnés) ou un équilibre entre les deux.
  • Indique si la validation croisée k-fold doit être utilisée (IValidationParams::ShouldPerformValidation). Nous recommandons d’utiliser la validation croisée lorsque votre échantillon d’entraînement est de taille limitée, car elle permet d’entraîner plusieurs modèles sur différentes partitions d’un même échantillon et de sélectionner le meilleur. Si vous disposez d’un grand volume de données catégorisées, il peut être préférable de désactiver la validation, d’entraîner le modèle sur l’ensemble de l’échantillon d’entraînement, puis d’utiliser les méthodes de classification (étape 6) pour tester le modèle sur un autre échantillon, en calculant vous-même les scores de performance.
  • Les paramètres de la validation croisée k-fold : le nombre de sous-ensembles dans lesquels l’échantillon d’entraînement est divisé (IValidationParams::FoldsCount) et le nombre d’itérations (IValidationParams::RepeatCount). Notez que le nombre d’objets requis dans l’ensemble d’entraînement à chaque itération doit être d’au moins 4 pour le classificateur de texte et d’au moins 8 pour le classificateur combiné. Assurez-vous que votre échantillon d’entraînement contient suffisamment d’objets.
Vous êtes maintenant prêt à entraîner un modèle. Transmettez l’objet TrainingData que vous avez configuré à l’étape 4 à la méthode TrainModel de l’objet Trainer. Elle retourne une collection TrainingResults qui, avec les fonctionnalités actuellement disponibles, ne contient qu’un seul TrainingResult. Si vous avez choisi d’effectuer une validation croisée, consultez les scores de performance dans son sous-objet ValidationResult.
L’entraînement et la classification du modèle seront effectués en mode séquentiel sous Linux et Windows, quelle que soit la valeur de IMultiProcessingParams::MultiProcessingMode.
La propriété ITrainingResult::Model donne accès au modèle de classification entraîné. Vous pouvez l’enregistrer dans un fichier à l’aide de la méthode SaveToFile ou l’utiliser directement pour classer des documents (passez à l’étape 6).

C#

// Créer l'objet trainer et configurer les paramètres
FREngine.ITrainer trainer = classEngine.CreateTrainer();
trainer.TrainingParams.ClassifierType = (int)FREngine.ClassifierTypeEnum.CT_Image; // le classifieur utilisera uniquement les caractéristiques d'image
// Nous laisserons les autres paramètres par défaut et entraînerons le modèle directement
FREngine.ITrainingResults results = trainer.TrainModel ( trainingData );
// Vérifier le score F1 du modèle
double F1 = results[0].ValidationResult.FMeasure;
// Récupérer le modèle de classification
FREngine.IModel model = results[0].Model;
// Enregistrer le modèle pour une utilisation ultérieure
model.SaveToFile( "C:\\model.dat" );
Pour utiliser le modèle entraîné pour la classification :
  1. Si le modèle n’est pas actuellement chargé, appelez la méthode CreateModelFromFile de l’objet ClassificationEngine pour le charger à partir d’un fichier sur le disque.
  2. Préparez les objets de classification à partir des documents à classifier, comme décrit à l’étape 3.
  3. Pour chaque objet de classification, appelez la méthode Classify de l’objet Model en passant le ClassificationObject comme paramètre d’entrée. La méthode renvoie une collection d’objets ClassificationResult, chacun contenant le libellé de la catégorie et la probabilité correspondante. Les résultats sont triés par probabilité, du meilleur au moins bon. Récupérez le résultat et vérifiez que le niveau de probabilité vous convient.
    Si le classificateur n’a pas pu attribuer de catégorie, null est renvoyé à la place de la collection de résultats.
L’entraînement du modèle et la classification sont exécutés en mode séquentiel sous Linux et Windows, quelle que soit la valeur de IMultiProcessingParams::MultiProcessingMode.

C#

// Ouvrir le modèle entraîné
FREngine.IModel model = classEngine.CreateModelFromFile( "C:\\model.dat" );
// Classer l'objet
FREngine.IClassificationResults classResults = model.Classify( clObject );
// Accéder au meilleur résultat et à sa probabilité
string label = classResults[0].CategoryLabel;
double probability = classResults[0].Probability;
Après avoir terminé votre travail avec ABBYY FineReader Engine, vous devez décharger l’objet Engine. Pour ce faire, utilisez la fonction exportée DeinitializeEngine.

C#

public class EngineLoader : IDisposable
{
    // Décharger FineReader Engine
    public void Dispose()
    {
        if (engine == null)
        {
            // Engine n'a pas été chargé
            return;
        }
        engine = null;
        // Supprimer tous les objets avant l'appel à FreeLibrary
        GC.Collect();
        GC.WaitForPendingFinalizers();
        GC.Collect();
        int hresult = deinitializeEngine();
 
        hresult = dllCanUnloadNow();
        if (hresult == 0)
        {
            FreeLibrary(dllHandle);
        }
        dllHandle = IntPtr.Zero;
        initializeEngine = null;
        deinitializeEngine = null;
        dllCanUnloadNow = null;
        // Lever l'exception après le nettoyage
        Marshal.ThrowExceptionForHR(hresult);
    }
    // Fonctions Kernel32.dll
    [DllImport("kernel32.dll")]
    private static extern IntPtr LoadLibraryEx(string dllToLoad, IntPtr reserved, uint flags);
    private const uint LOAD_WITH_ALTERED_SEARCH_PATH = 0x00000008;
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetProcAddress(IntPtr hModule, string procedureName);
    [DllImport("kernel32.dll")]
    private static extern bool FreeLibrary(IntPtr hModule);
    // Fonctions FREngine.dll
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    private delegate int InitializeEngine( string customerProjectId, string LicensePath, string LicensePassword, , , , ref FREngine.IEngine engine);
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DeinitializeEngine();
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    private delegate int DllCanUnloadNow();
    // Variables privées
    private FREngine.IEngine engine = null;
    // Handle de FREngine.dll
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}

Ressources requises

Vous pouvez utiliser le fichier FREngineDistribution.csv pour créer automatiquement une liste des fichiers nécessaires au bon fonctionnement de votre application. Pour le traitement dans ce scénario, sélectionnez dans la colonne 5 (RequiredByModule) les valeurs suivantes : Core Core.Resources Opening Opening, Processing Processing Processing.Classification Processing.Classification.NaturalLanguages Processing.OCR Processing.OCR, Processing.ICR Processing.OCR.NaturalLanguages Processing.OCR.NaturalLanguages, Processing.ICR.NaturalLanguages Si vous modifiez le scénario standard, adaptez les modules requis en conséquence. Vous devez également spécifier les langues de l’interface, les langues de reconnaissance et toutes les fonctionnalités supplémentaires utilisées par votre application (par exemple, Opening.PDF si vous devez ouvrir des fichiers PDF, ou Processing.OCR.CJK si vous devez reconnaître des textes en langues CJK). Consultez Working with the FREngineDistribution.csv File pour plus de détails.

Optimisation supplémentaire

Vous trouverez plus d’informations sur la configuration des différentes étapes de traitement dans les articles suivants :

Voir aussi

Mise en œuvre des scénarios d’utilisation de base