跳转到主要内容
在此场景中,使用 ABBYY FineReader Engine 读取条码。例如,为了自动分隔文档、供文档管理系统处理文档,或对文档进行索引和分类,可能需要读取条码。 此场景也可作为其他场景的一部分使用。例如,使用高速生产型扫描仪扫描的文档可借助条码进行分隔;或者,为长期存储而准备的文档可根据其条码值放入归档文档管理系统。 提取条码时,系统既可检测所有条码,也可仅检测具有特定值的某一类型条码。系统可以获取条码值并计算其校验和。为了获得最快且质量最高的条码识别结果:
  1. 使用分辨率为 300 dpi 的彩色图像。
  2. 使用配置文件调整识别速度 (详见 使用配置文件) 。
识别出的条码值可保存为最便于后续处理的格式,例如 TXT。

场景实现

本主题中提供的代码示例仅适用于 Windows。
下面将详细介绍在此场景中使用 ABBYY FineReader Engine 12 的推荐方法。该方法采用了针对此场景最合适的处理设置。
要开始使用 ABBYY FineReader Engine,您需要创建 Engine 对象。Engine 对象是 ABBYY FineReader Engine 对象层次结构中的顶层对象,提供各种全局设置、部分处理方法以及用于创建其他对象的方法。要创建 Engine 对象,可以使用 InitializeEngine 函数。另请参阅加载 Engine 对象的其他方式 (Win) 。

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // 使用 FREngine.dll 的完整路径、您的 Customer Project ID,
        // 以及(如适用)在线许可证令牌文件的路径和在线许可证密码来初始化这些变量
        string enginePath = "";
        string customerProjectId = "";
        string licensePath = "";
        string licensePassword = "";
        // 加载 FREngine.dll 库
        dllHandle = LoadLibraryEx(enginePath, IntPtr.Zero, LOAD_WITH_ALTERED_SEARCH_PATH);
           
        try
        {
            if (dllHandle == IntPtr.Zero)
            {
                throw new Exception("无法加载 " + enginePath);
            }
            IntPtr initializeEnginePtr = GetProcAddress(dllHandle, "InitializeEngine");
            if (initializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("找不到 InitializeEngine 函数");
            }
            IntPtr deinitializeEnginePtr = GetProcAddress(dllHandle, "DeinitializeEngine");
            if (deinitializeEnginePtr == IntPtr.Zero)
            {
                throw new Exception("找不到 DeinitializeEngine 函数");
            }
            IntPtr dllCanUnloadNowPtr = GetProcAddress(dllHandle, "DllCanUnloadNow");
            if (dllCanUnloadNowPtr == IntPtr.Zero)
            {
                throw new Exception("找不到 DllCanUnloadNow 函数");
            }
            // 将指针转换为委托
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // 调用 InitializeEngine 函数
            // 传入在线许可证文件的路径和在线许可证密码
            int hresult = initializeEngine(customerProjectId, licensePath, licensePassword, 
                "", "", false, ref engine);
            Marshal.ThrowExceptionForHR(hresult);
        }
        catch (Exception)
        {
            // 释放 FREngine.dll 库
            engine = null;
            // 调用 FreeLibrary 前释放所有对象
            GC.Collect();
            GC.WaitForPendingFinalizers();
            GC.Collect();
            FreeLibrary(dllHandle);
            dllHandle = IntPtr.Zero;
            initializeEngine = null;
            deinitializeEngine = null;
            dllCanUnloadNow = null;
            throw;
        }
    }
    // 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);
    // 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();
    // 私有变量
    private FREngine.IEngine engine = null;
    // FREngine.dll 的句柄
    private IntPtr dllHandle = IntPtr.Zero;
    private InitializeEngine initializeEngine = null;
    private DeinitializeEngine deinitializeEngine = null;
    private DllCanUnloadNow dllCanUnloadNow = null;
}

C++ (COM)

// 请将以下变量初始化为 FREngine.dll 的路径、您的 FineReader Engine Customer Project ID,
// 以及(如适用)Online License 令牌路径和 Online License 密码
wchar_t* FreDllPath;
wchar_t* CustomerProjectId;
wchar_t* LicensePath;  // 如果不使用 Online License,请将这些变量赋值为空字符串
wchar_t* LicensePassword;
// FREngine.dll 的句柄
static HMODULE libraryHandle = 0;
// 全局 FineReader Engine 对象
FREngine::IEnginePtr Engine;
void LoadFREngine()
{
    if( Engine != 0 ) {
    // 已加载
    return;
    }
    // 第一步:加载 FREngine.dll
    if( libraryHandle == 0 ) {
        libraryHandle = LoadLibraryEx( FreDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
        if( libraryHandle == 0 ) {
            throw L"加载 ABBYY FineReader Engine 时出错";
        }
    }
    // 第二步:获取 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"加载 ABBYY FineReader Engine 时出错";
    }
}
可以使用 Engine 对象的 LoadPredefinedProfile 方法选择最适合的设置。此方法将所用设置配置文件的名称作为输入参数。有关配置文件的更多信息,请参阅使用配置文件对于此场景,ABBYY FineReader Engine 支持 2 种设置配置:
配置文件名称说明
BarcodeRecognition_Accuracy仅提取条码 (不会检测文本、图像或表格) 。这些设置已针对准确率进行了优化。 <Warning> 此配置文件要求许可证中包含 Barcode Autolocation 模块。 </Warning>
BarcodeRecognition_Speed仅提取条码 (不会检测文本、图像或表格) 。这些设置已针对处理速度进行了优化。 <Warning> 此配置文件要求许可证中包含 Barcode Autolocation 模块。 </Warning>

C#

// 加载预定义配置文件
engine.LoadPredefinedProfile("BarcodeRecognition_Speed");

C++ (COM)

// 加载预定义配置文件
Engine->LoadPredefinedProfile( L"BarcodeRecognition_Speed" );
如果您想更改处理时使用的设置,请使用相应的参数对象。有关更多信息,请参阅下方的其他优化部分。
ABBYY FineReader Engine 提供 FRDocument 对象来处理多页文档。要加载文档中的图像并进行预处理,您应创建一个 FRDocument 对象,并向其中添加图像。您可以采用以下任一方式:

C#

// 从图像文件创建 FRDocument 对象
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );

C++ (COM)

// 打开图像文件并创建 FRDocument 对象
FREngine::IFRDocumentPtr frDocument = Engine->CreateFRDocumentFromImage( L"C:\\MyImage.tif", 0 );
如果已加载 BarcodeRecognition 配置文件,则可以使用 FRDocument 对象的 Process 方法仅提取条码。在这种情况下,ABBYY FineReader Engine 只会检测包含条码的块,不会检测其他类型的块。可通过 Layout 对象访问已识别的条码块;该对象是 FRPage 对象的子对象,而 FRPage 表示文档中的一个页面。如果要读取特定类型的条码,请指定 BarcodeParams 对象中的相应参数,并将 BarcodeParams 对象作为上述某个函数的参数传入。

C#

// 加载 BarcodeRecognition 配置文件时,
// 如果条码符合规范,
// 则无需向处理方法传递任何额外参数
frDocument.Process( null );
// 如果需要读取特定类型的条码
// 创建一个 DocumentProcessingParams 对象
FREngine.IDocumentProcessingParams dpp = engine.CreateDocumentProcessingParams();
// 指定所需参数
dpp.PageProcessingParams.PageAnalysisParams.BarcodeParams.Type = ( int )FREngine.BarcodeTypeEnum.BT_Code39;
// 现在使用这些参数识别条码
frDocument.Process( dpp );

C++ (COM)

// 加载 BarcodeRecognition 配置文件时,
// 如果条码符合规范,
// 则无需向处理方法传递任何额外参数
frDocument->Process( 0 );
// 如果需要读取特定类型的条码
// 创建一个 DocumentProcessingParams 对象
FREngine::IDocumentProcessingParamsPtr params = Engine->CreateDocumentProcessingParams();
// 指定所需参数
params->PageProcessingParams->PageAnalysisParams->BarcodeParams->Type = FREngine::BT_Code39;
// 现在使用这些参数识别条码
frDocument->Process( params );
要将识别出的条码值保存到文件中,可以使用 FRDocument 对象的 Export 方法,并将 FileExportFormatEnum 常量作为其中一个参数来指定导出格式。例如,可导出为 TXT。你还可以使用相应的导出对象修改默认导出参数。更多信息,请参见下文的特定任务的附加优化完成 FRDocument 对象的使用后,请释放该对象占用的所有资源。请使用 IFRDocument::Close 方法。

C#

// 将识别出的条码保存为某种格式(例如 TXT)
frDocument.Export( "C:\\barcodes.txt", FREngine.FileExportFormatEnum.FEF_TextUnicodeDefaults, null );
// 释放 FRDocument 对象
frDocument.Close();

C++ (COM)

// 将识别出的条码保存为某种格式(例如 TXT)
frDocument->Export( L"C:\\barcodes.txt", FREngine::FEF_TextUnicodeDefaults, 0 );
// 释放 FRDocument 对象
frDocument->Close();
在使用完 ABBYY FineReader Engine 后,您需要卸载 Engine 对象。为此,请使用导出的 DeinitializeEngine 函数。

C#

public class EngineLoader : IDisposable
{
    // 卸载 FineReader Engine
    public void Dispose()
    {
        if (engine == null)
        {
            // Engine 尚未加载
            return;
        }
        engine = null;
        // 在调用 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;
        // 清理完成后抛出异常
        Marshal.ThrowExceptionForHR(hresult);
    }
    // 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);
    // 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();
    // 私有变量
    private FREngine.IEngine engine = null;
    // 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;
 }
 // 释放 Engine 对象
 Engine = 0;
 // 反初始化 FineReader Engine
 typedef HRESULT ( STDAPICALLTYPE* DeinitializeEngineFunc )();
 DeinitializeEngineFunc pDeinitializeEngine =
  ( DeinitializeEngineFunc )GetProcAddress( libraryHandle, "DeinitializeEngine" );
 if( pDeinitializeEngine == 0 || pDeinitializeEngine() != S_OK ) {
  throw L"卸载 ABBYY FineReader Engine 时出错";
 }
 // 现在可以安全释放 FREngine.dll 库
 FreeLibrary( libraryHandle );
 libraryHandle = 0;
}

所需资源

您可以使用 FREngineDistribution.csv 文件,自动生成应用程序正常运行所需的文件列表。若按此场景进行处理,请在第 5 列 (RequiredByModule) 中选择以下值: Core Core.Resources Opening Opening, Processing Processing Processing.OCR Processing.OCR, Processing.ICR Processing.OCR.NaturalLanguages Processing.OCR.NaturalLanguages, Processing.ICR.NaturalLanguages Export Export, Processing 如果您修改了标准场景,请相应调整所需模块。您还需要指定应用程序使用的界面语言、识别语言以及其他附加功能 (例如,如果需要打开 PDF 文件,则指定 Opening.PDF;如果需要识别 CJK 语言 文本,则指定 Processing.OCR.CJK) 。有关更多详细信息,请参阅 使用 FREngineDistribution.csv 文件

其他优化

以下是帮助文件中的相关章节,您可以在其中找到有关为各个处理阶段设置参数的更多信息:
  • 提取和读取条码
    • BarcodeParams Object
      此对象可用于设置条码分析和读取参数。
    • Recognizing Barcodes
      介绍条码识别中的特殊情况,并提供处理条码的相关建议。
    • Barcode Types
      ABBYY FineReader Engine 12 支持的条码列表及其简要说明。
    • FRDocument Object
      除了条码值外,您可能还需要提取文档中的其他信息。在这种情况下,可以使用 FRDocument 对象的方法。
    • PageProcessingParams Object
      此对象可用于为整个文档设置分析和识别参数。使用此对象,您可以指定是否识别条码值。可通过 PageAnalysisParams 子对象的 BarcodeParams 和 DetectBarcodes 属性访问条码读取参数。
    • Working with Layout and Blocks
      您还可以手动标记条码块,并指定其分析和读取参数。本节提供了有关处理块的详细信息。
  • 处理已识别的条码值
    • BarcodeBlock Object
      此对象的 Text 和 BarcodeText 属性包含通过识别获得的条码值。此对象的其他属性可用于获取条码类型、方向和其他参数。
  • 导出

另请参阅

基本使用场景的实现