跳轉到主要內容
許多國家的官方旅行證件或身分證件都包含機器可讀區 (MRZ) ,有助於更準確地處理文件資料。MRZ 包含 2 或 3 行採用 OCR-B 字型的文字,並依據 ICAO Document 9303 編排 (規格請參閱 ICAO 網站) 。 此情境用於在客戶導入或驗證流程中,從身分證件上的機器可讀區擷取資料。系統會辨識文件影像中的 MRZ,並從中擷取資料。擷取出的資料包含多個欄位,內含文件及其持有人的個人資訊 (例如文件類型與到期日、持有人的名字與姓氏等) 。您可以搜尋這些欄位、驗證資料,並將其儲存到外部檔案中以供後續處理。 若要從 MRZ 擷取資料,透過掃描取得或以電子格式儲存的影像檔通常會經過數個處理階段,而每個階段各有其特性:
  1. 掃描影像或照片的預處理
您可以掃描或拍攝帶有 MRZ 的身分證件資料頁。使用行動裝置數位相機拍攝的照片,解析度和品質可能較低。此外,影像在辨識前也可能需要進行一些預處理。
  1. 從 MRZ 擷取資料
每張影像最多只能擷取一個 MRZ。系統會辨識 2 或 3 行中的每一行文字,並進行解析以擷取資料欄位。部分欄位以及整個 MRZ 都包含檢查碼,有助於您驗證資料。
  1. 匯出至外部檔案
您也可以將擷取的資料儲存為外部格式:支援 XML 和 JSON。 以下所述程序已在適用於 Linux 和 Windows 的 MRZExtraction 程式碼範例中實作。

情境實作

本主題中提供的程式碼範例僅適用於 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,
        // 以及(若適用)您的 Online License 權杖檔案路徑和 Online License 密碼初始化這些變數
        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("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");
            }
            // 將指標轉換成委派
            initializeEngine = (InitializeEngine)Marshal.GetDelegateForFunctionPointer(
                initializeEnginePtr, typeof(InitializeEngine));
            deinitializeEngine = (DeinitializeEngine)Marshal.GetDelegateForFunctionPointer(
                deinitializeEnginePtr, typeof(DeinitializeEngine));
            dllCanUnloadNow = (DllCanUnloadNow)Marshal.GetDelegateForFunctionPointer(
                dllCanUnloadNowPtr, typeof(DllCanUnloadNow));
            // 呼叫 InitializeEngine 函式 
            // 傳入 Online License 檔案路徑和 Online License 密碼
            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;
}
您可以使用 Engine 物件的 LoadPredefinedProfile 方法,載入適用於此情境的處理設定。此方法會使用設定檔名稱作為輸入參數。更多資訊請參閱使用設定檔此情境的設定可在預先定義的 MachineReadableZone 設定檔中取得:
  • 啟用影像上所有文字的偵測與擷取 (不會偵測圖片、向量圖形和表格) 。
  • 系統會自動執行解析度與幾何校正。

C#

// 載入預先定義的設定檔
engine.LoadPredefinedProfile("MachineReadableZone");
如果您想變更處理設定,請使用適當的 Parameter 物件。更多資訊請參閱下方的特定工作的其他最佳化只有在您的 ABBYY FineReader Engine 授權支援 MRZCapture 模組時,才能擷取 MRZ。
若要將影像載入 FineReader Engine,您可以使用下列物件的方法:
Linux 和 Windows 使用者可以在使用 ABBYY FineReader Engine 進行平行處理中了解各種方法的優缺點。本主題著重於 FRDocument。
若要將影像載入 FRDocument 物件,請執行下列其中一項操作:所有這些方法都會將 PrepareImageMode 物件作為輸入參數,讓您指定不同的影像預處理參數。請呼叫 IEngine::CreatePrepareImageMode 方法來建立此物件,然後視需要變更其屬性,並將其傳遞至影像開啟方法。

C#

// 建立文件
FREngine.IFRDocument frDoc = engine.CreateFRDocument();
// 將影像檔新增至文件
document.AddImageFile( imagePath, null, null );
若要從 MRZ 擷取資料:
  1. [選用] 使用 Engine 物件的 CreateMrzProcessingParams 方法建立 MrzProcessingParams 物件,並將其屬性設為所需的值。
  2. 呼叫 FRPage 物件的 ExtractMrz 方法,並將您在前一步設定好的 MrzProcessingParams 物件作為輸入參數傳入;若要使用預設的 MRZ 擷取設定,只要傳入 NULL 即可。系統會傳回一個 MrzData 物件,其中包含從擷取到的 MRZ 剖析出的資訊。

C#

// 擷取 MRZ
FREngine.IFRPage page = document.Pages.Item(0);
FREngine.IMrzData mrzData = page.ExtractMrz( null );
MrzData 物件包含從 MRZ 擷取的所有資料。您可以使用 GetLine 方法存取機器可讀文字的各行,並使用 GetFieldGetFieldByType 方法逐一查看欄位。可擷取下列類型的欄位:
  • 文件類型
  • 文件子類型
  • 簽發國家
  • 姓氏
  • 名字
  • 文件號碼
  • 國籍
  • 出生日期
  • 性別
  • 到期日
  • 個人號碼
  • 選用資料第 1 行
  • 選用資料第 2 行
MrzField 物件提供擷取欄位的完整資訊。使用其 Text 屬性取得欄位值,並使用 Region 屬性取得欄位在影像上的位置。若要驗證資料,請使用 MrzDataMrzField 物件中的 Checksum、HasChecksum 和 IsChecksumVerified 屬性提供的檢查碼資訊。並非所有欄位類型都支援檢查碼;提供 HasChecksum 屬性,是為了讓您在嘗試擷取檢查碼之前先檢查其值。您可以使用 MrzField 物件的 InsertRemove 方法,手動編輯欄位中辨識出的文字。

C#

// 驗證文件號碼的檢查碼
FREngine.IMrzField documentNumberField = mrzData.GetFieldByType(FREngine.MrzFieldTypeEnum.MFT_DocumentNumber);
bool isNumberVerified = documentNumberField.IsChecksumVerified;
擷取的資料可儲存為 XML 或 JSON 檔案。若要使用預設參數匯出資料,請呼叫 MrzData 物件的 ExportToFile 方法,並將檔案路徑作為輸入參數傳入。若要使用使用者自訂參數匯出資料,請呼叫 MrzData 物件的 ExportToFileEx 方法,並將指向 MrzJsonExportParams 物件或 MrzXmlExportParams 物件的指標作為輸入參數傳入。C#
// 儲存為 XML 格式
mrzData.ExportToFile("C:\\ExtractedData.xml", FREngine.MrzExportFormatEnum.MEF_Xml);
完成 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;
}

必要資源

您可以使用 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) 。如需詳細資訊,請參閱 Working with the FREngineDistribution.csv File

其他最佳化

以下是《說明》檔中的相關章節,您可以在其中找到有關為各個處理階段設定參數的其他資訊:

另請參閱

基本使用案例實作