Saltar al contenido principal
En el caso del reconocimiento a nivel de campo, se reconocen fragmentos breves de texto para capturar datos de determinados campos. La calidad del reconocimiento es crucial en este escenario. Este escenario también puede utilizarse como parte de escenarios más complejos en los que es necesario extraer datos significativos de documentos (por ejemplo, para capturar datos de documentos en papel en sistemas de información y bases de datos, o para clasificar e indexar automáticamente documentos en sistemas de gestión documental). En este escenario, el sistema reconoce varias líneas de texto solo en algunos campos, o bien el texto completo de una imagen pequeña. El sistema calcula un nivel de confianza para cada carácter reconocido. Estos niveles de confianza pueden utilizarse después al comprobar los resultados del reconocimiento. Además, el sistema puede almacenar varias variantes de reconocimiento de palabras y caracteres del texto, que luego pueden utilizarse en algoritmos de votación para mejorar la calidad del reconocimiento. El procesamiento de pequeños fragmentos de texto en este escenario difiere en algunos aspectos de los mismos pasos en otros escenarios:
  1. Preprocesamiento de imágenes escaneadas o fotografías
Las imágenes que se van a reconocer pueden incluir marcas y ruido de fondo, ambos capaces de dificultar el reconocimiento. Por esta razón, en esta etapa se eliminan las marcas no deseadas y el ruido de fondo.
  1. Reconocimiento de pequeños fragmentos de texto
Al reconocer pequeños fragmentos de texto, el tipo de datos que se va a reconocer se conoce de antemano. Por lo tanto, la calidad del reconocimiento puede mejorarse mediante el uso de diccionarios externos, expresiones regulares, idiomas de reconocimiento personalizados y alfabetos, así como imponiendo restricciones al número de caracteres de una cadena. Los campos de texto pueden contener texto impreso, escrito a mano en letra de imprenta y manuscrito.
  1. Trabajo con los datos reconocidos
Este escenario requiere la máxima precisión de reconocimiento para reducir al mínimo el trabajo de verificación de datos. El sistema puede calcular un nivel de confianza para cada palabra o carácter reconocido y proporcionar varias variantes de reconocimiento, entre las que varios motores pueden elegir después la mejor opción aplicando algoritmos de votación.

Implementación del escenario

Los ejemplos de código proporcionados en este tema son específicos de Windows.
A continuación se presenta una descripción detallada del método recomendado para usar ABBYY FineReader Engine 12 en este escenario. El método sugerido utiliza la configuración de procesamiento que se considera más adecuada para este escenario.
Para comenzar a trabajar con ABBYY FineReader Engine, es necesario crear el objeto Engine. El objeto Engine es el objeto de nivel superior en la jerarquía de objetos de ABBYY FineReader Engine, y proporciona diversas configuraciones globales, algunos métodos de procesamiento y métodos para crear los demás objetos.Para crear el objeto Engine, puede usar la función InitializeEngine. Consulte también otras formas de cargar el objeto Engine (Win).

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // Inicialice estas variables con la ruta completa a FREngine.dll, su Customer Project ID,
        // y, si corresponde, la ruta al archivo de token de su licencia en línea y la contraseña de la licencia en línea
        string enginePath = "";
        string customerProjectId = "";
        string licensePath = "";
        string licensePassword = "";
        // Cargar la biblioteca FREngine.dll
        dllHandle = LoadLibraryEx(enginePath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
           
        try
        {
            if (dllHandle == IntPtr.Zero)
            {
                throw new Exception("No se puede cargar " + enginePath);
            }
            IntPtr initializeEnginePtr = GetProcAddress(dllHandle, "InitializeEngine");
            if (initializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("No se encuentra la función InitializeEngine");
            }
            IntPtr deinitializeEnginePtr = GetProcAddress(dllHandle, "DeinitializeEngine");
            if (deinitializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("No se encuentra la función DeinitializeEngine");
            }
            IntPtr dllCanUnloadNowPtr = GetProcAddress(dllHandle, "DllCanUnloadNow");
            if (dllCanUnloadNowPtr == IntPtr.Zero)
            {
                throw new Exception("No se encuentra la función DllCanUnloadNow");
            }
            // Convertir punteros en delegados
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // Llamar a la función InitializeEngine 
            // pasando la ruta al archivo de licencia en línea y la contraseña de la licencia en línea
            int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, 
                "", "", false, ref engine);
            Marshal.ThrowExceptionForHR(hresult);
        }
        catch (Exception)
        {
            // Liberar la biblioteca FREngine.dll
            engine = null;
            // Eliminar todos los objetos antes de llamar a FreeLibrary
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            FreeLibrary(dllHandle);
            dllHandle = IntPtr.Zero;
            initializeEngine = null;
            deinitializeEngine = null;
            dllCanUnloadNow = null;
            throw;
        }
    }
    // Funciones 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);
    // Funciones 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 privadas
    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;
}

C++ (COM)

// Inicialice estas variables con la ruta a FREngine.dll, el Customer Project ID de FineReader Engine,
// y, si corresponde, la ruta al token de licencia en línea y la contraseña de licencia en línea
wchar_t* FreDllPath;
wchar_t* CustomerProjectId;
wchar_t* LicensePath;  // si no utiliza una licencia en línea, asigne cadenas vacías a estas variables
wchar_t* LicensePassword;
// HANDLE de FREngine.dll
static HMODULE libraryHandle = 0;
// Objeto global de FineReader Engine
FREngine::IEnginePtr Engine;
void LoadFREngine()
{
    if( Engine != 0 ) {
    // Ya cargado
    return;
    }
    // Primer paso: cargar FREngine.dll
    if( libraryHandle == 0 ) {
        libraryHandle = LoadLibraryEx( FreDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
        if( libraryHandle == 0 ) {
            throw L"Error al cargar ABBYY FineReader Engine";
        }
    }
    // Segundo paso: obtener el objeto Engine
    typedef HRESULT ( STDAPICALLTYPE* InitializeEngineFunc )( BSTR, BSTR, BSTR, BSTR, 
        BSTR, VARIANT_BOOL, FREngine::IEngine** );
    InitializeEngineFunc pInitializeEngine =
    ( InitializeEngineFunc )GetProcAddress( libraryHandle, "InitializeEngine" );
    if( pInitializeEngine == 0 || pInitializeEngine( CustomerProjectId, LicensePath, 
        LicensePassword, L"", L"", VARIANT_FALSE, &Engine ) != S_OK ) {
    UnloadFREngine();
    throw L"Error al cargar ABBYY FineReader Engine";
    }
}
La configuración más adecuada puede seleccionarse mediante el método LoadPredefinedProfile del objeto Engine. Este método recibe el nombre del perfil como parámetro de entrada. La configuración más adecuada puede seleccionarse mediante el perfil predefinido denominado FieldLevelRecognition. Para obtener más información sobre los perfiles, consulte Trabajo con perfiles.

C#

// Cargar un perfil predefinido
engine.LoadPredefinedProfile("FieldLevelRecognition");

C++ (COM)

// Cargar un perfil predefinido
Engine->LoadPredefinedProfile( L"FieldLevelRecognition" );
Si desea cambiar la configuración utilizada para el procesamiento, use los objetos Parameter correspondientes. Consulte la sección Optimización adicional, más abajo, para obtener más información.
ABBYY FineReader Engine proporciona un objeto FRDocument para procesar documentos de varias páginas. Para cargar las imágenes de un documento y preprocesarlas, debe crear el objeto FRDocument y agregarle imágenes. Puede hacer una de las siguientes acciones:

C#

// Crear el objeto FRDocument a partir de un archivo de imagen
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );

C++ (COM)

// Abrir un archivo de imagen y crear el objeto FRDocument
FREngine::IFRDocumentPtr frDocument = Engine->CreateFRDocumentFromImage( L"C:\\MyImage.tif", 0 );
Ahora debe crear bloques que contengan sus campos y, para cada uno, especificar el tipo de bloque y las características conocidas de los datos que contiene.Realice el análisis de la estructura del documento mediante el método Analyze, o agregue manualmente bloques que contengan los campos que necesita reconocer. Consulte Trabajo con Layout y bloques para obtener instrucciones.Para cada campo, ahora puede especificar sus propios parámetros de reconocimiento. Por ejemplo, si un campo contiene texto, use la propiedad ITextBlock::RecognizerParams:
  • establezca el tipo de texto con ayuda de la propiedad TextTypes del objeto RecognizerParams. Por ejemplo, si el campo contiene dígitos escritos con el formato de un código postal, use el tipo de texto TT_Index.
  • establezca el idioma mediante el método SetPredefinedTextLanguage. El uso de idiomas predefinidos especiales (solo para Windows) puede resultar útil si conoce el tipo de información contenida en el campo. Por ejemplo, si el campo contiene una dirección de EE. UU., seleccione el idioma predefinido English_US_Address. Esto garantizará un reconocimiento más fiable del texto.
  • establezca las propiedades SaveCharacterRecognitionVariants y SaveWordRecognitionVariants del objeto RecognizerParams si necesita usar las variantes de reconocimiento para verificar posteriormente el resultado, como se describe más adelante en el paso 6. Tenga en cuenta que esta configuración no está disponible para textos manuscritos o escritos en letra de imprenta.
Para obtener más información sobre el reconocimiento de distintos tipos de campos, consulte las secciones Reconocimiento de marcas de verificación, Reconocimiento de textos manuscritos, Reconocimiento de códigos de barras y Reconocimiento de palabras con espacios.

C#

// Analizar la estructura del documento
frDocument.Analyze( null, null, null );
// Supongamos que sabemos que el primer bloque
// de la estructura contiene una dirección de EE. UU.
FREngine.ITextBlock addressBlock = frDocument.Pages[0].Layout.Blocks[0].GetAsTextBlock();
FREngine.IRecognizerParams paramsAddressBlock = addressBlock.RecognizerParams;
paramsAddressBlock.SetPredefinedTextLanguage( "English_US_Address" );
// Habilitar la recopilación de variantes de reconocimiento
paramsAddressBlock.SaveCharacterRecognitionVariants = true;
paramsAddressBlock.SaveWordRecognitionVariants = true;
// Configurar las propiedades de los demás bloques de la estructura de la misma manera
...

C++ (COM)

// Analizar la estructura del documento
frDocument->Analyze( 0, 0, 0 );
// Supongamos que sabemos que el primer bloque
// de la estructura contiene una dirección de EE. UU.
FREngine::ILayoutBlocksPtr layoutBlocks = frDocument->Pages->Item( 0 )->Layout->Blocks;
FREngine::IRecognizerParamsPtr paramsAddressBlock = layoutBlocks->Item( 0 )->GetAsTextBlock()->RecognizerParams;
paramsAddressBlock->SetPredefinedTextLanguage( L"English_US_Address" );
// Habilitar la recopilación de variantes de reconocimiento
paramsAddressBlock->SaveCharacterRecognitionVariants = VARIANT_TRUE;
paramsAddressBlock->SaveWordRecognitionVariants = VARIANT_TRUE;
// Configurar las propiedades de los demás bloques de la estructura de la misma manera
...
Como el diseño del documento ya se analizó y usted además lo modificó, no vuelva a llamar a los métodos de análisis. Use el método Recognize, que realiza el reconocimiento y la síntesis de páginas de todo el documento. En este escenario, debe extraer los datos de los campos y no exportar el documento reconocido; por lo tanto, no necesitará la síntesis del documento.

C#

// Reconocer el documento
// No es necesario especificar parámetros porque están configurados por el perfil de procesamiento
frDocument.Recognize( null, null );

C++ (COM)

// Reconocer el documento
// No es necesario especificar parámetros porque están configurados por el perfil de procesamiento
frDocument->Recognize( 0, 0 );
Use el objeto Text para acceder al fragmento de texto reconocido (puede obtener este objeto para un bloque de texto mediante la propiedad ITextBlock::Text). Use la propiedad Paragraphs para obtener la colección de párrafos del fragmento y el método IParagraphs::Item para acceder a cada párrafo. La propiedad IParagraph::Text permite acceder al texto reconocido de un párrafo.Puede usar IParagraph::Words para obtener la colección de palabras de un párrafo. Use el método IWords::Item para acceder a cada palabra de la colección. La propiedad IWord::Text devuelve la línea que contiene la palabra reconocida. Use el método GetRecognitionVariants del objeto Word o el método GetWordRecognitionVariants del objeto Paragraph para obtener las variantes de reconocimiento de una palabra.Puede acceder a los atributos de cada carácter mediante el método GetCharParams del objeto Paragraph. Este método proporciona acceso al objeto CharParams, que contiene los parámetros del carácter reconocido. Puede acceder a las variantes de reconocimiento de un carácter mediante la propiedad ICharParams::CharacterRecognitionVariants.Para obtener información detallada sobre cómo trabajar con texto, consulte Working with Text. Para obtener información sobre cómo usar Engine en algoritmos de votación, consulte Using Voting API.Cuando haya terminado de trabajar con el objeto FRDocument, libere todos los recursos utilizados por este objeto. Use el método IFRDocument::Close.
Después de terminar de trabajar con ABBYY FineReader Engine, debe descargar el objeto Engine. Para ello, use la función exportada DeinitializeEngine.

C#

public class EngineLoader : IDisposable
{
    // Descargar FineReader Engine
    public void Dispose()
    {
        if (engine == null)
        {
            // El Engine no se cargó
            return;
        }
        engine = null;
        // Eliminar todos los objetos antes de llamar a 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;
        // lanzar la excepción después de la limpieza
        Marshal.ThrowExceptionForHR(hresult);
    }
    // Funciones 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);
    // Funciones de 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 privadas
    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;
}

C++ (COM)

void UnloadFREngine()
{
 if( libraryHandle == 0 ) {
  return;
 }
 // Liberar el objeto Engine
 Engine = 0;
 // Desinicializar FineReader Engine
 typedef HRESULT ( STDAPICALLTYPE* DeinitializeEngineFunc )();
 DeinitializeEngineFunc pDeinitializeEngine =
  ( DeinitializeEngineFunc )GetProcAddress( libraryHandle, "DeinitializeEngine" );
 if( pDeinitializeEngine == 0 || pDeinitializeEngine() != S_OK ) {
  throw L"Error al descargar ABBYY FineReader Engine";
 }
 // Ahora se puede liberar con seguridad la biblioteca FREngine.dll
 FreeLibrary( libraryHandle );
 libraryHandle = 0;
}

Recursos necesarios

Puede usar el archivo FREngineDistribution.csv para crear automáticamente una lista de los archivos necesarios para que la aplicación funcione. Para el procesamiento en este escenario, seleccione en la columna 5 (RequiredByModule) los siguientes valores: Core Core.Resources Opening Opening, Processing Processing Processing.OCR Processing.OCR, Processing.ICR Processing.OCR.NaturalLanguages Processing.OCR.NaturalLanguages, Processing.ICR.NaturalLanguages Si modifica el escenario estándar, cambie los módulos necesarios según corresponda. También debe especificar los idiomas de la interfaz, los idiomas de reconocimiento y cualquier función adicional que use la aplicación (como, por ejemplo, Opening.PDF si necesita abrir archivos PDF, o Processing.OCR.CJK si necesita reconocer texto en idiomas CJK). Consulte Working with the FREngineDistribution.csv File para obtener más información.

Optimización adicional

Estas son las secciones del archivo de ayuda en las que puede encontrar información adicional sobre la configuración de los parámetros para las distintas etapas de procesamiento:

Consulte también

Implementación de escenarios de uso básicos