메인 콘텐츠로 건너뛰기
fields 수준 인식에서는 특정 fields의 데이터를 추출하기 위해 짧은 텍스트 단편을 인식합니다. 이 시나리오에서는 인식 품질이 매우 중요합니다. 이 시나리오는 문서에서 의미 있는 데이터를 추출해야 하는 더 복잡한 시나리오의 일부로도 사용할 수 있습니다(예: 종이 문서의 데이터를 정보 시스템과 데이터베이스로 가져오거나, 문서 관리 시스템(Document Management Systems)에서 문서를 자동으로 분류하고 인덱싱하는 경우). 이 시나리오에서 시스템은 일부 fields에 있는 여러 줄의 텍스트만 인식하거나 작은 이미지에 있는 전체 텍스트를 인식합니다. 시스템은 인식된 각 문자에 대해 신뢰도 점수를 계산합니다. 그런 다음 인식 결과를 확인할 때 이 신뢰도 점수를 사용할 수 있습니다. 또한 시스템은 텍스트의 단어와 문자에 대해 여러 인식 후보를 저장할 수 있으며, 이후 인식 품질을 높이기 위한 투표 알고리즘에 이를 사용할 수 있습니다. 이 시나리오에서 작은 텍스트 단편을 처리하는 방식은 몇 가지 측면에서 다른 시나리오의 동일한 단계와 다릅니다.
  1. 스캔한 이미지 또는 사진의 전처리
인식할 이미지에는 표시 요소와 배경 잡음이 포함될 수 있으며, 이 둘 모두 인식을 방해할 수 있습니다. 따라서 이 단계에서 불필요한 표시 요소와 배경 잡음을 제거합니다.
  1. 작은 텍스트 단편의 인식
작은 텍스트 단편을 인식할 때는 인식할 데이터 유형이 미리 알려져 있습니다. 따라서 외부 사전, 정규식, 사용자 지정 인식 언어와 알파벳을 사용하고 문자열의 문자 수를 제한함으로써 인식 품질을 향상시킬 수 있습니다. 텍스트 fields에는 인쇄체, 또박또박 쓴 손글씨, 흘려 쓴 손글씨가 포함될 수 있습니다.
  1. 인식된 데이터 처리
이 시나리오에서는 데이터 검증 작업을 최소화하기 위해 최대한 높은 인식 정확도가 필요합니다. 시스템은 인식된 각 단어 또는 문자에 대해 신뢰도 점수를 계산하고 여러 인식 후보를 제공할 수 있으며, 그러면 여러 엔진이 투표 알고리즘을 적용해 최적의 후보를 선택할 수 있습니다.

시나리오 구현

이 항목에서 제공되는 코드 예제는 Windows 전용입니다.
아래에서는 이 시나리오에서 ABBYY FineReader 엔진 12를 사용하는 권장 방법을 자세히 설명합니다. 이 방법은 이 시나리오에 가장 적합하다고 판단되는 처리 설정을 사용합니다.
ABBYY FineReader Engine를 사용하려면 먼저 Engine 객체를 생성해야 합니다. Engine 객체는 ABBYY FineReader Engine 객체 계층 구조의 최상위 객체로, 다양한 전역 설정과 일부 처리 메서드, 그리고 다른 객체를 생성하는 메서드를 제공합니다.엔진 객체를 생성하려면 InitializeEngine 함수를 사용하십시오. 엔진 객체를 로드하는 다른 방법(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 변수
    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를 사용하지 않는 경우, 이 변수들에 빈 string을 할당하십시오.
wchar_t* LicensePassword;
// FREngine.dll에 대한 HANDLE
static HMODULE libraryHandle = 0;
// 전역 FineReader 엔진 객체
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단계: 엔진 객체 가져오기
    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 객체를 생성한 다음 여기에 이미지를 추가해야 합니다. 다음 방법 중 하나를 사용할 수 있습니다.

C#

// 이미지 파일에서 FRDocument 객체 생성
FREngine.IFRDocument frDocument = engine.CreateFRDocumentFromImage( "C:\\MyImage.tif", null );

C++ (COM)

// 이미지 파일을 열고 FRDocument 객체 생성
FREngine::IFRDocumentPtr frDocument = Engine->CreateFRDocumentFromImage( L"C:\\MyImage.tif", 0 );
이제 fields를 포함하는 블록을 만들고, 각 블록의 유형과 내부 데이터의 알려진 특성을 지정해야 합니다.Analyze 메서드를 사용해 문서의 레이아웃을 분석하거나, 인식할 fields가 포함된 블록을 수동으로 추가합니다. 자세한 내용은 Working with Layout and Blocks를 참조하세요.이제 각 fields마다 개별 인식 매개변수를 지정할 수 있습니다. 예를 들어, fields에 텍스트가 포함된 경우 ITextBlock::RecognizerParams 속성을 사용합니다.
  • RecognizerParams 객체의 TextTypes 속성을 사용해 텍스트 유형을 설정합니다. 예를 들어 fields에 우편번호 형식의 숫자가 포함된 경우 TT_Index 텍스트 유형을 사용합니다.
  • SetPredefinedTextLanguage 메서드를 사용해 언어를 설정합니다. fields에 포함된 정보의 유형을 알고 있다면 special predefined languages(Windows 전용)를 사용하는 것이 도움이 될 수 있습니다. 예를 들어 fields에 미국 주소가 포함된 경우 English_US_Address 사전 정의 언어를 선택합니다. 이렇게 하면 텍스트를 더 정확하게 인식할 수 있습니다.
  • 아래 6단계에서 설명하는 것처럼 결과를 추가로 검증하기 위해 인식 후보를 사용해야 하는 경우, RecognizerParams 객체의 SaveCharacterRecognitionVariants 및 SaveWordRecognitionVariants 속성을 설정합니다. 이 설정은 손글씨 또는 필기체 텍스트에는 사용할 수 없습니다.
서로 다른 유형의 fields를 인식하는 방법에 대한 자세한 내용은 Recognizing Checkmarks, Recognizing Handwritten Texts, 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 속성을 통해 액세스할 수 있습니다.텍스트 작업에 대한 자세한 내용은 Working with Text를 참조하세요. 투표 알고리즘에서 엔진을 사용하는 방법에 대한 정보는 Using Voting API를 참조하세요.FRDocument 객체 작업을 마친 후에는 이 객체에서 사용한 모든 리소스를 해제하세요. IFRDocument::Close 메서드를 사용합니다.
ABBYY FineReader Engine 사용이 끝나면 Engine 객체를 언로드해야 합니다. 이렇게 하려면 export된 함수 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;
        // 정리 후 예외 throw
        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 변수
    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을 참조하십시오.

추가 최적화

다양한 처리 단계의 매개변수 설정에 대한 추가 정보는 도움말의 다음 섹션에서 확인할 수 있습니다.
  • 인식
  • 인식된 데이터 작업

참고 항목

기본 사용 시나리오 구현