許多國家的官方旅行證件或身分證件都包含機器可讀區 (MRZ) ,有助於更準確地處理文件資料。MRZ 包含 2 或 3 行採用 OCR-B 字型的文字,並依據 ICAO Document 9303 編排 (規格請參閱 ICAO 網站) 。
此情境用於在客戶導入或驗證流程中,從身分證件上的機器可讀區擷取資料。系統會辨識文件影像中的 MRZ,並從中擷取資料。擷取出的資料包含多個欄位,內含文件及其持有人的個人資訊 (例如文件類型與到期日、持有人的名字與姓氏等) 。您可以搜尋這些欄位、驗證資料,並將其儲存到外部檔案中以供後續處理。
若要從 MRZ 擷取資料,透過掃描取得或以電子格式儲存的影像檔通常會經過數個處理階段,而每個階段各有其特性:
- 掃描影像或照片的預處理
您可以掃描或拍攝帶有 MRZ 的身分證件資料頁。使用行動裝置數位相機拍攝的照片,解析度和品質可能較低。此外,影像在辨識前也可能需要進行一些預處理。
- 從 MRZ 擷取資料
每張影像最多只能擷取一個 MRZ。系統會辨識 2 或 3 行中的每一行文字,並進行解析以擷取資料欄位。部分欄位以及整個 MRZ 都包含檢查碼,有助於您驗證資料。
- 匯出至外部檔案
您也可以將擷取的資料儲存為外部格式:支援 XML 和 JSON。
以下所述程序已在適用於 Linux 和 Windows 的 MRZExtraction 程式碼範例中實作。
本主題中提供的程式碼範例僅適用於 Windows。
以下將詳細說明在此情境中使用 ABBYY FineReader Engine 12 的建議方式。此方式採用最適合此情境的處理設定。
步驟 1. 載入 ABBYY FineReader Engine
若要開始使用 ABBYY FineReader Engine,您需要建立 Engine 物件。Engine 物件是 ABBYY FineReader Engine 物件階層中的最上層物件,提供各種全域設定、一些處理方法,以及建立其他物件的方法。若要建立 Engine 物件,您可以使用 InitializeEngine 函式。另請參閱 載入 Engine 物件的其他方式 (Win) 。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 設定檔中取得:
- 啟用影像上所有文字的偵測與擷取 (不會偵測圖片、向量圖形和表格) 。
- 系統會自動執行解析度與幾何校正。
// 載入預先定義的設定檔
engine.LoadPredefinedProfile("MachineReadableZone");
如果您想變更處理設定,請使用適當的 Parameter 物件。更多資訊請參閱下方的特定工作的其他最佳化。只有在您的 ABBYY FineReader Engine 授權支援 MRZCapture 模組時,才能擷取 MRZ。
若要將影像載入 FineReader Engine,您可以使用下列物件的方法:若要將影像載入 FRDocument 物件,請執行下列其中一項操作:所有這些方法都會將 PrepareImageMode 物件作為輸入參數,讓您指定不同的影像預處理參數。請呼叫 IEngine::CreatePrepareImageMode 方法來建立此物件,然後視需要變更其屬性,並將其傳遞至影像開啟方法。// 建立文件
FREngine.IFRDocument frDoc = engine.CreateFRDocument();
// 將影像檔新增至文件
document.AddImageFile( imagePath, null, null );
MrzData 物件包含從 MRZ 擷取的所有資料。您可以使用 GetLine 方法存取機器可讀文字的各行,並使用 GetField 和 GetFieldByType 方法逐一查看欄位。可擷取下列類型的欄位:
- 文件類型
- 文件子類型
- 簽發國家
- 姓氏
- 名字
- 文件號碼
- 國籍
- 出生日期
- 性別
- 到期日
- 個人號碼
- 選用資料第 1 行
- 選用資料第 2 行
MrzField 物件提供擷取欄位的完整資訊。使用其 Text 屬性取得欄位值,並使用 Region 屬性取得欄位在影像上的位置。若要驗證資料,請使用 MrzData 和 MrzField 物件中的 Checksum、HasChecksum 和 IsChecksumVerified 屬性提供的檢查碼資訊。並非所有欄位類型都支援檢查碼;提供 HasChecksum 屬性,是為了讓您在嘗試擷取檢查碼之前先檢查其值。您可以使用 MrzField 物件的 Insert 和 Remove 方法,手動編輯欄位中辨識出的文字。// 驗證文件號碼的檢查碼
FREngine.IMrzField documentNumberField = mrzData.GetFieldByType(FREngine.MrzFieldTypeEnum.MFT_DocumentNumber);
bool isNumberVerified = documentNumberField.IsChecksumVerified;
步驟 7. 卸載 ABBYY FineReader Engine
完成 ABBYY FineReader Engine 的工作後,您需要卸載 Engine 物件。若要這麼做,請使用匯出的 DeinitializeEngine 函式。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。
以下是《說明》檔中的相關章節,您可以在其中找到有關為各個處理階段設定參數的其他資訊:
基本使用案例實作