在欄位層級辨識中,系統會辨識短小的文字片段,以擷取特定欄位中的資料。在這種情境下,辨識品質至關重要。
此情境也可作為更複雜情境的一部分,用於從文件中擷取有意義的資料 (例如,將紙本文件中的資料擷取到資訊系統和資料庫中,或在文件管理系統中自動對文件進行分類和建立索引) 。
在此情境中,系統只會辨識部分欄位中的幾行文字,或小型影像上的全部文字。系統會為每個已辨識的字元計算可信度評分。之後即可在檢查辨識結果時使用這些可信度評分。此外,系統還可能為文字中的單字和字元儲存多個辨識變體,之後可將其用於投票演算法,以提升辨識品質。
在此情境中,小型文字片段的處理方式在某些方面與其他情境中的相同步驟有所不同:
掃描影像或照片的預先處理
待辨識的影像可能包含標記和背景雜訊,兩者都可能妨礙辨識。因此,系統會在此階段移除不需要的標記和背景雜訊。
小型文字片段的辨識
辨識小型文字片段時,要辨識的資料類型已預先得知。因此,可透過使用外部字典、regular expression、自訂辨識語言和字母表,以及限制 string 中的字元數量,來提升辨識品質。文字欄位可包含印刷體、手寫印刷體和手寫文字。
處理已辨識的資料
此情境要求盡可能提高辨識準確度,以將資料驗證工作降到最低。系統可為每個已辨識的單字或字元計算可信度評分,並提供多個辨識變體,之後多個 Engine 即可套用投票演算法,從中選出最佳候選結果。
本主題中提供的程式碼範例僅適用於 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,
// 以及(如適用)線上授權權杖檔案的路徑和線上授權密碼
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 的 Handle
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,
// 以及(如適用)線上授權權杖的路徑和線上授權密碼來初始化這些變數
wchar_t * FreDllPath;
wchar_t * CustomerProjectId;
wchar_t * LicensePath; // 若不使用線上授權,請將這些變數設為空字串
wchar_t * LicensePassword;
// FREngine.dll 的 HANDLE
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 方法,選取最適合的設定。此方法會將設定檔名稱作為輸入參數。您可以使用名為 FieldLevelRecognition 的預先定義設定檔來選取最適合的設定。如需設定檔的詳細資訊,請參閱 Working with Profiles 。 // 載入預先定義的設定檔
engine . LoadPredefinedProfile ( "FieldLevelRecognition" );
// 載入預先定義的設定檔
Engine -> LoadPredefinedProfile ( L"FieldLevelRecognition" );
如果您想變更處理時使用的設定,請使用對應的 Parameter 物件。如需更多資訊,請參閱下方的 Additional optimization 一節。
ABBYY FineReader Engine 提供 FRDocument 物件,用於處理多頁文件。若要載入文件影像並進行預處理,您需要建立 FRDocument 物件,然後將影像加入其中。您可以採用下列其中一種方式: // 從影像檔建立 FRDocument 物件
FREngine . IFRDocument frDocument = engine . CreateFRDocumentFromImage ( "C: \\ MyImage.tif" , null );
// 開啟影像檔並建立 FRDocument 物件
FREngine ::IFRDocumentPtr frDocument = Engine -> CreateFRDocumentFromImage ( L"C: \\ MyImage.tif" , 0 );
現在,您需要建立包含欄位的區塊,並為每個區塊指定區塊類型以及其中資料的已知特性。 使用 Analyze 方法對文件執行版面分析,或手動新增包含所需辨識欄位的區塊。操作說明請參閱 Working with Layout and Blocks 。 現在,您也可以為每個欄位分別指定辨識參數。例如,如果欄位包含文字,請使用 ITextBlock::RecognizerParams 屬性:
使用 RecognizerParams 物件的 TextTypes 屬性設定文字類型。例如,如果欄位包含以郵遞區號格式書寫的數字,請使用 TT_Index 文字類型。
使用 SetPredefinedTextLanguage 方法設定語言。如果您知道欄位中包含的資訊類型,使用特殊預先定義語言 (僅限 Windows) 會很有幫助。例如,如果欄位包含美國地址,請選取 English_US_Address 預先定義語言。這可確保文字辨識更加可靠。
如果您需要使用辨識變體來進一步驗證結果 (如下方步驟 6 所述) ,請設定 RecognizerParams 物件的 SaveCharacterRecognitionVariants 和 SaveWordRecognitionVariants 屬性。請注意,此設定不適用於手寫或手寫印刷體文字。
如需辨識不同類型欄位的更多詳細資訊,請參閱 Recognizing Checkmarks 、Recognizing Handwritten Texts 、Recognizing Barcodes 和 Recognizing Words with Spaces 各節。 // 分析文件版面配置
frDocument . Analyze ( null , null , null );
// 假設我們知道版面配置中的第一個區塊
// 包含一個美國地址
FREngine . ITextBlock addressBlock = frDocument . Pages [ 0 ]. Layout . Blocks [ 0 ]. GetAsTextBlock ();
FREngine . IRecognizerParams paramsAddressBlock = addressBlock . RecognizerParams ;
paramsAddressBlock . SetPredefinedTextLanguage ( "English_US_Address" );
// 啟用收集辨識變體
paramsAddressBlock . SaveCharacterRecognitionVariants = true ;
paramsAddressBlock . SaveWordRecognitionVariants = true ;
// 以相同方式設定其他版面配置區塊的屬性
.. .
// 分析文件版面配置
frDocument -> Analyze ( 0 , 0 , 0 );
// 假設我們知道版面配置中的第一個區塊
// 包含一個美國地址
FREngine ::ILayoutBlocksPtr layoutBlocks = frDocument -> Pages -> Item ( 0 )-> Layout -> Blocks ;
FREngine ::IRecognizerParamsPtr paramsAddressBlock = layoutBlocks -> Item ( 0 )-> GetAsTextBlock ()-> RecognizerParams ;
paramsAddressBlock -> SetPredefinedTextLanguage ( L"English_US_Address" );
// 啟用收集辨識變體
paramsAddressBlock -> SaveCharacterRecognitionVariants = VARIANT_TRUE;
paramsAddressBlock -> SaveWordRecognitionVariants = VARIANT_TRUE;
// 以相同方式設定其他版面配置區塊的屬性
...
由於文件版面配置已經分析完畢,且您也已進一步修改,因此請勿再次呼叫分析方法。請使用 Recognize 方法,該方法會對文件中的所有頁面執行辨識和頁面合成。在此情境中,您需要從欄位擷取資料,而非匯出已辨識的文件,因此不需要進行文件合成。 // 辨識文件
// 不需要指定參數,因為這些參數已由處理設定檔設定完成
frDocument . Recognize ( null , null );
// 辨識文件
// 不需要指定參數,因為這些參數已由處理設定檔設定完成
frDocument -> Recognize ( 0 , 0 );
步驟 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 ;
}
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
如果您修改了標準情境,請據此調整所需的模組。您也需要指定介面語言、辨識語言,以及應用程式使用的任何其他功能 (例如,若您需要開啟 PDF 檔案,則為 Opening.PDF;若您需要辨識 CJK languages 的文字,則為 Processing.OCR.CJK) 。如需更多資訊,請參閱 Working with the FREngineDistribution.csv File 。
以下是說明檔中提供更多資訊的章節,說明如何為各個處理階段設定參數:
基本使用情境的實作