此情境用於從文件中擷取所有可能的資料,並以結構化方式儲存。
結果會產生一個 JSON 檔案,用來呈現文件結構。其中包含所有文件物件:印刷文字與手寫文字、表格、條碼、核取記號,以及影像及其位置和屬性。此格式最適合用於後續處理、將資料儲存至資料庫,或與其他應用程式整合。
在此情境中,文件會經過數個處理步驟:
- 掃描影像或照片的預處理
透過掃描器或數位相機取得的影像,在進行光學辨識前可能需要先做一些調整。例如,帶有雜訊的影像或文字行扭曲的影像,都需要先加以校正,才能成功進行光學辨識。
- 以結構化方式擷取文件中的所有資料
在版面分析期間,系統會偵測影像中的各種物件,並將其歸類至對應類型的區塊中。接著,系統會依各區塊類型的最佳設定進行辨識。在合成過程中,文件的邏輯結構會以一致的方式重建。即使是複雜的版面配置,文字順序也會盡可能貼近人類的閱讀方式。這可確保對同一份文件重新辨識時,文字順序仍然一致。
- 匯出為結構化格式
辨識後的文件會儲存為 JSON 或 XML。
本主題中提供的程式碼範例僅適用於 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 時發生錯誤";
}
}
ABBYY FineReader Engine 可讓您使用 Engine 物件的 LoadPredefinedProfile 方法,載入最適合此情境的所有處理設定。此方法會接受設定檔名稱作為輸入參數。更多資訊請參閱使用設定檔。此情境的設定可在預先定義的 DataExtraction 設定檔中取得:
- 版面分析與辨識會優先考量準確性,而非速度。
- 偵測影像上的所有文字,包括手寫文字及品質較差的小型文字區域。
- 偵測表格、核取記號和條碼。
- 會完整重建文件的邏輯結構。
// 載入預先定義的設定檔
engine.LoadPredefinedProfile("DataExtraction");
// 載入預先定義的設定檔
Engine->LoadPredefinedProfile( L"DataExtraction" );
如果您想變更處理設定,請使用對應的參數物件。更多資訊請參閱下方的進一步最佳化章節。
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 );
若要辨識文件,我們建議您使用 FRDocument 物件的分析與辨識方法。此物件提供完整的方法集合,可用於文件分析、辨識與合成。若要一次完成文件分析、辨識與合成,最方便的方法是 Process 方法。此方法也能以最有效率的方式運用多處理器與多核心系統的平行處理功能。不過,您也可以使用 Preprocess、Analyze、Recognize 和 Synthesize 方法,依序執行預處理、分析、辨識與合成。// 分析、辨識並合成文件
// 不需要其他參數,因為這些參數已由處理設定檔設定
frDocument.Process( null );
// 分析、辨識並合成文件
// 不需要其他參數,因為這些參數已由處理設定檔設定
frDocument->Process( 0 );
若要儲存已辨識的文件,您可以使用 FRDocument 物件的 Export 方法,並將 FileExportFormatEnum 常數作為其中一個參數。您可以使用對應的匯出物件來變更預設的匯出參數。如需更多資訊,請參閱下方的 針對特定任務的其他最佳化。完成 FRDocument 物件的操作後,請釋放此物件使用的所有資源。請使用 IFRDocument::Close 方法。// 以結構化格式儲存已辨識的文件
frDocument.Export( "C:\\Data.json", FREngine.FileExportFormatEnum.FEF_JSON, null );
// 釋放 FRDocument 物件
frDocument.Close();
// 以結構化格式儲存已辨識的文件
frDocument->Export( L"C:\\Data.json", FREngine::FEF_JSON, 0 );
// 釋放 FRDocument 物件
frDocument->Close();
步驟 6. 解除載入 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
Export
Export, Processing
如果您修改標準情境,請據此調整所需模組。您也需要指定介面語言、辨識語言,以及應用程式使用的任何其他功能 (例如,若您需要開啟 PDF 檔案,則使用 Opening.PDF;若您需要辨識 CJK 語言中的文字,則使用 Processing.OCR.CJK) 。如需詳細資訊,請參閱 Working with the FREngineDistribution.csv File。
以下為說明主題概覽,提供有關在將文件轉換為可編輯格式的不同階段自訂設定的其他資訊:
- 掃描 - 僅限 Windows
- 掃描
說明 ABBYY FineReader Engine 的文件掃描情境。
- 辨識
- 匯出
基本使用案例實作