メインコンテンツへスキップ
フィールドレベル認識では、特定のfieldsからデータを取得するために、短いテキスト断片を認識します。このシナリオでは、認識品質が極めて重要です。 このシナリオは、ドキュメントから意味のあるデータを抽出する、より複雑なシナリオの一部として使用されることもあります (たとえば、紙のドキュメントから情報システムやデータベースにデータを取り込む場合や、Document Management Systemsでドキュメントを自動的に分類して索引付けする場合など) 。 このシナリオでは、システムは一部のfields内の複数行のテキスト、または小さな画像全体のテキストを認識します。システムは、認識された各文字について確信度を算出します。これらの確信度は、認識結果を確認する際に使用できます。さらに、システムはテキスト内の単語や文字について複数の認識候補を保存でき、それらは認識品質を向上させるための投票アルゴリズムで使用される場合があります。 このシナリオにおける短いテキスト断片の処理は、他のシナリオにおける同様の手順とはいくつかの点で異なります。
  1. スキャン画像または写真の前処理
認識対象の画像には、マークや背景ノイズが含まれている場合があり、これらはいずれも認識を妨げる可能性があります。そのため、この段階で不要なマークや背景ノイズを除去します。
  1. 短いテキスト断片の認識
短いテキスト断片を認識する際は、認識対象のデータの種類があらかじめわかっています。そのため、外部辞書、正規表現、カスタム認識言語、アルファベットを使用し、さらに文字列内の文字数に制限を設けることで、認識品質を向上させることができます。テキストfieldsには、活字、手書き風文字、手書き文字のテキストを含めることができます。
  1. 認識されたデータの処理
このシナリオでは、データ確認作業を最小限に抑えるために、最大限の認識精度が求められます。システムは、認識された各単語または文字について確信度を算出し、複数の認識候補を提供できます。これらの候補の中から、複数のエンジンが投票アルゴリズムを適用して最適な候補を選択できます。

シナリオの実装

このトピックで提供されるコードサンプルは、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、
        // および該当する場合はオンラインライセンストークンファイルへのパスとオンラインライセンスパスワードを各変数に設定してください
        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 へのハンドル
    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 のハンドル
static HMODULE libraryHandle = 0;
// グローバル FineReader Engine オブジェクト
FREngine::IEnginePtr Engine;
void LoadFREngine()
{
    if( Engine != 0 ) {
    // 読み込み済み
    return;
    }
    // ステップ 1: FREngine.dll を読み込む
    if( libraryHandle == 0 ) {
        libraryHandle = LoadLibraryEx( FreDllPath, 0, LOAD_WITH_ALTERED_SEARCH_PATH );
        if( libraryHandle == 0 ) {
            throw L"ABBYY FineReader Engine の読み込み中にエラーが発生しました";
        }
    }
    // ステップ 2: 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 を参照してください。

C#

// 定義済みプロファイルを読み込む
engine.LoadPredefinedProfile("FieldLevelRecognition");

C++ (COM)

// 定義済みプロファイルを読み込む
Engine->LoadPredefinedProfile( L"FieldLevelRecognition" );
処理に使用する設定を変更する場合は、対応する Parameter オブジェクトを使用してください。詳細については、以下の Additional optimization セクションを参照してください。
ABBYY FineReader Engine には、複数ページのドキュメントを処理するための FRDocument オブジェクトがあります。ドキュメントの画像を読み込んで前処理するには、FRDocument オブジェクトを作成し、そこに画像を追加する必要があります。方法は次のいずれかです。
  • Engine オブジェクトの CreateFRDocumentFromImage メソッドを使用して FRDocument オブジェクトを作成します。このメソッドは FRDocument オブジェクトを作成し、指定したファイルから画像を読み込みます。
  • Engine オブジェクトの CreateFRDocument メソッドを使用して FRDocument オブジェクトを作成し、その後、作成した FRDocument オブジェクトにファイルから画像を追加します (FRDocument オブジェクトの AddImageFileAddImageFileWithPassword、または AddImageFileWithPasswordCallback メソッドを使用) 。

C#

// 画像ファイルから FRDocument オブジェクトを作成する
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );

C++ (COM)

// 画像ファイルを開いて FRDocument オブジェクトを作成する
FREngine::IFRDocumentPtr frDocument = Engine->CreateFRDocumentFromImage( L"C:\\MyImage.tif", 0 );
ここでは、fieldを含むブロックを作成し、各ブロックについて種類と内部データの既知の特性を指定する必要があります。Analyzeメソッドを使用して文書のレイアウト解析を実行するか、認識するfieldを含むブロックを手動で追加します。手順については、Working with Layout and Blocksを参照してください。各fieldには、認識用のパラメーターを個別に指定できます。たとえば、fieldにテキストが含まれている場合は、ITextBlock::RecognizerParamsプロパティを使用します。
  • RecognizerParamsobjectのTextTypesプロパティを使用して、テキストの種類を設定します。たとえば、fieldに郵便番号形式で書かれた数字が含まれている場合は、TT_Indexテキストタイプを使用します。
  • SetPredefinedTextLanguageメソッドを使用して言語を設定します。fieldに含まれる情報の種類がわかっている場合は、special predefined languages (Windows のみ) が役立つことがあります。たとえば、fieldに米国内の住所が含まれている場合は、English_US_Address定義済み言語を選択します。これにより、テキストをより確実に認識できるようになります。
  • 以下のステップ 6 で説明するように、認識結果をさらに検証するために認識候補を使用する必要がある場合は、RecognizerParamsobjectのSaveCharacterRecognitionVariantsプロパティとSaveWordRecognitionVariantsプロパティを設定します。この設定は、手書き文字または手書き風文字のテキストには使用できない点に注意してください。
さまざまな種類のfieldの認識に関する詳細は、チェックマークの認識手書き文字の認識Recognizing Barcodes、およびRecognizing Words with Spacesの各セクションを参照してください。

C#

// 文書のレイアウトを解析する
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;
// 他のレイアウトブロックのプロパティも同様に設定する
...

C++ (COM)

// 文書のレイアウトを解析する
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 メソッドを使用します。このシナリオでは、認識済み文書をエクスポートするのではなく fields からデータを抽出する必要があるため、文書合成は不要です。

C#

// 文書を認識します
// パラメーターは処理プロファイルで設定されているため、指定する必要はありません
frDocument.Recognize( null, null );

C++ (COM)

// 文書を認識します
// パラメーターは処理プロファイルで設定されているため、指定する必要はありません
frDocument->Recognize( 0, 0 );
認識されたテキストフラグメントにアクセスするには、Text オブジェクトを使用します (このオブジェクトは、テキストブロックに対して ITextBlock::Text プロパティ経由で取得できます) 。フラグメント内の段落のコレクションを取得するには Paragraphs プロパティを使用し、個々の段落にアクセスするには IParagraphs::Item メソッドを使用します。IParagraph::Text プロパティでは、段落の認識済みテキストにアクセスできます。段落内の単語のコレクションを取得するには IParagraph::Words を使用できます。コレクション内の個々の単語にアクセスするには IWords::Item メソッドを使用します。IWord::Text プロパティは、認識された単語を含む行を返します。単語の認識候補を取得するには、Word オブジェクトの GetRecognitionVariants メソッド、または Paragraph オブジェクトの GetWordRecognitionVariants メソッドを使用します。個々の文字の属性には、Paragraph オブジェクトの GetCharParams メソッドを介してアクセスできます。このメソッドでは、認識された文字のパラメーターを含む CharParams オブジェクトにアクセスできます。文字の認識候補には、ICharParams::CharacterRecognitionVariants プロパティからアクセスできます。テキストの操作に関する詳細は、Text の操作 を参照してください。投票アルゴリズムで Engine を使用する方法については、Voting API の使用 を参照してください。FRDocument オブジェクトの使用が完了したら、このオブジェクトが使用していたすべてのリソースを解放してください。IFRDocument::Close メソッドを使用します。
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;
}

C++ (COM)

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 を参照してください。

追加の最適化

以下は、各種処理段階のパラメーター設定に関する追加情報を参照できるヘルプファイルのセクションです。

関連項目

基本的な使用シナリオの実装方法