此情境可擷取文件的本文內容,以及標誌、印章和其他非本文元素上的文字。
文字會保留其自然順序 (也就是「人類閱讀時的順序」) 。接著,您可以在自己的環境中將這些文件交由自然語言處理 (NLP) 引擎處理,例如快速產生摘要、搜尋敏感資訊,或進行情感分析。
若要擷取文件的主要文字,透過掃描取得或以電子格式儲存的影像檔通常會經過數個處理階段,而每個階段各有其特點:
- 掃描影像或照片的預處理
掃描影像在辨識前可能需要進行一些預處理,例如當掃描文件包含背景雜訊、文字傾斜、色彩反轉、黑邊、方向錯誤或解析度問題時。
- 辨識文件影像中盡可能多的文字
影像辨識會使用可確保找出並擷取文件影像中所有可能文字的設定來執行。
本主題中提供的程式碼範例僅適用於 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("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 函式,
// 並傳入線上授權檔案的路徑和線上授權密碼
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 的 HANDLE
static HMODULE libraryHandle = 0;
// 全域 FineReader Engine object
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 object
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 方法,選取最適合此情境的設定。此方法會接收設定檔名稱作為輸入參數。如需詳細資訊,請參閱 Working with Profiles。ABBYY FineReader Engine 為此情境提供 2 種設定選項:設定檔名稱 | 說明 |
|---|
TextExtraction_Accuracy | 此設定已針對準確性最佳化: - 可偵測影像上的所有文字,包括品質較低的小型文字區域 (不會偵測圖片和表格) 。
- 不會執行文件邏輯結構的完整重建。
此設定檔不適用於將文件轉換為 RTF、DOCX 或純文字 PDF。若要進行這類轉換,請使用文件轉換設定檔。 |
TextExtraction_Speed | 此設定已針對處理速度最佳化: - 可偵測影像上的所有文字,包括品質較低的小型文字區域 (不會偵測圖片和表格) 。
- 不會執行文件邏輯結構的完整重建。
- 可加快文件分析與辨識處理。
此設定檔不適用於將文件轉換為 RTF、DOCX 或純文字 PDF。若要進行這類轉換,請使用文件轉換設定檔。 |
// 載入預先定義的設定檔
engine.LoadPredefinedProfile("TextExtraction_Accuracy");
// 載入預先定義的設定檔
Engine->LoadPredefinedProfile( L"TextExtraction_Accuracy" );
如果您想變更處理設定,請使用適當的參數物件。如需進一步資訊,請參閱下方的 Additional optimization for specific tasks。
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 );
在分析期間,ABBYY FineReader Engine 會選出包含文字、表格、圖片等內容的影像區塊。在辨識過程中,包含文字資料的區塊會填入辨識出的文字。在 ABBYY FineReader Engine 中,Layout 物件用於儲存區塊與辨識出的文字。文件處理的主要流程,是在代表待處理文件的 FRDocument 物件中操作 layout。若要存取文件頁面的 layout,請使用 IFRPage::Layout 屬性。若要搜尋關鍵字,您可以使用 Text 物件檢視辨識出的文字;此物件可透過文字、表格或條碼區塊的屬性存取。您找到的重要資料可依需求儲存或處理。請參閱下方的 針對特定任務的其他最佳化,以取得更詳細的資訊。
或者,您可能會想將擷取出的文字儲存為便於搜尋的格式,例如 TXT;或儲存為結構化格式,例如 JSON,以便日後輕鬆擷取所需資訊。請使用 FRDocument 物件的 Export 方法,並將對應的 FileExportFormatEnum 常數作為其中一個參數。您可以使用對應的匯出物件來變更匯出的預設參數。請參閱下方的 針對特定任務的其他最佳化,以取得更多資訊。完成 FRDocument 物件的使用後,請釋放此物件所使用的所有資源。請使用 IFRDocument::Close 方法。// 將已辨識的文件文字儲存為 TXT 格式
frDocument.Export( "C:\\MyText.txt", FREngine.FileExportFormatEnum.FEF_TextUnicodeDefaults, null );
// 釋放 FRDocument 物件
frDocument.Close();
// 將已辨識的文件文字儲存為 TXT 格式
frDocument->Export( L"C:\\MyText.txt", FREngine::FEF_TextUnicodeDefaults, 0 );
// 釋放 FRDocument 物件
frDocument->Close();
步驟 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 語言 的文字,則指定 Processing.OCR.CJK) 。如需進一步詳細資訊,請參閱 使用 FREngineDistribution.csv 檔案。
基本使用情境實作