메인 콘텐츠로 건너뛰기
명함에는 회사나 개인에 관한 비즈니스 정보가 담겨 있습니다. 명함에는 이름, 회사명, 전화번호, 팩스, 이메일, 웹사이트 주소 등과 같은 정보가 포함될 수 있습니다. 종이 명함에서 이러한 정보를 추출해 전자 형식으로 저장해야 할 수 있습니다. 저장 대상은 휴대전화의 주소록, 이메일 클라이언트 또는 기타 데이터 저장 시스템일 수 있습니다. 예를 들어, 명함 정보는 vCard 형식으로 이메일이나 네트워크를 통해 자주 전달됩니다. 이 시나리오에서 수행해야 하는 주요 단계는 다음과 같습니다.
  1. 명함의 디지털 사본 확보
명함을 스캔하거나 사진으로 촬영합니다. 모바일 기기의 디지털 카메라로 촬영한 사진은 해상도와 품질이 낮을 수 있습니다. 따라서 이미지에 대한 추가 전처리가 필요할 수 있습니다.
  1. 명함 인식
스캔된 페이지에는 한 페이지에 여러 장의 명함이 포함될 수 있습니다. 인식 품질이 높아야 하며, 모든 정보를 정확하게 추출해야 합니다.
  1. 인식된 데이터를 적절한 형식으로 저장
인식된 데이터를 다양한 데이터 저장 시스템에 저장하거나 vCard 형식으로 내보내 이메일로 전송할 수 있습니다.

시나리오 구현

이 항목에서 제공하는 코드 샘플은 Windows 전용입니다.
아래에서는 이 시나리오에서 ABBYY FineReader Engine을 사용하는 권장 방식을 자세히 설명합니다.
ABBYY FineReader Engine을 사용하려면 먼저 Engine 객체를 생성해야 합니다. 엔진 객체는 ABBYY FineReader Engine 객체 계층 구조의 최상위 객체로, 다양한 전역 설정, 일부 처리 메서드, 그리고 다른 객체를 생성하는 메서드를 제공합니다.엔진 객체를 생성하려면 InitializeEngine 함수를 사용할 수 있습니다. Engine 객체를 로드하는 다른 방법 (Win)도 참조하세요.

C#

public class EngineLoader : IDisposable
{
    public EngineLoader()
    {
        // 이 변수들을 FREngine.dll의 전체 경로, Customer Project ID,
        // 그리고 필요한 경우 Online License 토큰 파일 경로와 Online License 비밀번호로 초기화합니다
        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 함수를 호출하고 
            // Online License 파일 경로와 Online License 비밀번호를 전달합니다
            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;
}
Engine 객체의 LoadPredefinedProfile 메서드를 사용하여 이 시나리오에 적합한 처리 설정을 로드할 수 있습니다. 이 메서드는 설정 프로필 이름을 입력 Parameter로 사용합니다. 자세한 내용은 프로필 작업을 참조하세요.이 시나리오에 필요한 설정은 사전 정의된 BusinessCardsProcessing 프로필에서 사용할 수 있습니다.
  • 명함만 감지합니다(SynthesisParamsForPage 객체의 SynthesizeBusinessCards 속성을 TRUE로 설정).
  • 품질이 낮은 작은 텍스트 영역까지 포함하여 이미지의 모든 텍스트를 감지하도록 설정합니다(그림과 표는 감지되지 않음).
  • 해상도 보정이 수행됩니다.
  • 문서의 논리 구조에 대한 전체 합성은 수행되지 않습니다.

C#

// 사전 정의된 프로필 로드
engine.LoadPredefinedProfile("BusinessCardsProcessing");
처리 설정을 변경하려면 적절한 Parameter 객체를 사용하세요. 자세한 내용은 아래의 특정 작업을 위한 추가 최적화를 참조하세요.
FineReader Engine에 이미지를 로드하려면 다음 객체의 메서드를 사용할 수 있습니다.
Linux 및 Windows 사용자는 ABBYY FineReader Engine을 사용한 병렬 처리에서 각 접근 방식의 장단점을 확인할 수 있습니다. 이 항목에서는 FRDocument를 중점적으로 다룹니다.
FRDocument 객체에 이미지를 로드하려면 다음 중 하나를 수행하세요.이 모든 메서드는 이미지 전처리의 다양한 매개변수를 지정할 수 있는 PrepareImageMode 객체를 Parameter로 사용합니다. IEngine::CreatePrepareImageMode 함수를 호출하여 이 객체를 만든 다음, 필요에 따라 속성을 변경하고, 이 객체가 필요한 함수에 전달합니다.

C#

FREngine.IEngine engine;
string imagePath;
FREngine.IPrepareImageMode pim = engine.CreatePrepareImageMode();
pim.DocumentType = FREngine.DocumentTypeEnum.DT_BusinessCard;
FREngine.IFRDocument frDoc = engine.CreateFRDocument();
frDoc.AddImageFile(imagePath, pim, null);
명함을 인식하려면 다음 단계를 수행합니다.
  1. RecognizerParams 객체의 SetPredefinedTextLanguage 메서드를 사용하여 명함의 언어를 지정합니다. 명함 인식에 사용할 수 있는 미리 정의된 언어 목록을 참조하세요.
  2. 필요한 경우 다른 처리 매개변수도 설정합니다. 페이지 전처리, 분석, 인식 및 합성 매개변수 조정을 참조하세요.
  3. 매개변수를 처리 메서드 중 하나에 전달합니다(예: FRDocument 객체의 Process 메서드). 그러면 이 메서드가 문서와 해당 페이지의 명함 컬렉션(IFRDocument::BusinessCards, IFRPage::BusinessCards)을 채웁니다.
FRPage 객체의 SynthesizeBusinessCard 또는 SynthesizeBusinessCardEx 메서드를 사용하여 전체 페이지 또는 각 페이지의 영역에서 명함을 합성할 수도 있습니다. 이 메서드는 BusinessCard 객체를 반환합니다. 이 경우 명함은 페이지의 명함 컬렉션에 추가되지 않습니다. 이 방식은 Batch Processor를 사용하는 처리 방식을 선택한 경우 특히 유용합니다.

C#

// 문서 처리 매개변수 생성
FREngine.IDocumentProcessingParams dpp = engine.CreateDocumentProcessingParams();
// 지정한 매개변수로 인식 수행
frDoc.Process( dpp );
// 명함에 액세스
FREngine.IBusinessCard card = frDoc.BusinessCards[0];
인식된 명함(BusinessCard 객체)에는 다음 field가 포함될 수 있습니다.

BusinessCard_pict

  • 이름
  • 회사명
  • 직위
  • 회사 주소
  • 전화번호
  • 팩스
  • 휴대전화 번호
  • 이메일
  • 웹사이트
각 field에는 해당 유형으로 액세스하거나(FieldByType 속성), fields 컬렉션 내 인덱스로 액세스할 수 있습니다(Field 속성). 각 field에는 Value 속성이 있으며, 이를 통해 field 값에 string 형식으로 액세스할 수 있습니다. field의 각 문자에 대해서는 인식 후보를 확인할 수 있습니다(GetCharParams 메서드).일부 field는 여러 구성 요소로 이루어질 수 있습니다. 예를 들어 주소 field에는 우편번호, 국가, USA 주, 도시, 상세 주소가 포함될 수 있습니다. field 구성 요소에 액세스하려면 Component 속성 또는 FindComponent 메서드를 사용할 수 있습니다. 전자는 인덱스로 구성 요소에 액세스할 수 있게 해 주고, 후자는 유형으로 구성 요소를 찾습니다. 각 구성 요소에 대해 유형과 값을 확인하고, 각 문자에 대한 Parameter와 인식 후보를 가져올 수 있습니다(GetCharParams 메서드).

C#

// 이름 field 가져오기
FREngine.IBusinessCardField nameField = card.FieldByType( FREngine.BusinessCardFieldTypeEnum.BCFT_Name, 0 );
// 이름이 포함된 구성 요소 가져오기
FREngine.IBusinessCardFieldComponent firstNameComponent =
  nameField.FindComponent( FREngine.BusinessCardFieldComponentTypeEnum.BCFCT_FirstName );
// 인식된 이름
string firstName = firstNameComponent.Value;
BusinessCard 객체는 명함을 vCard 형식으로 저장하기 위한 전용 ExportToVCard 메서드를 제공합니다. 파일 경로는 Parameter로 전달됩니다.명함은 XML과 같이 지원되는 다른 내보내기 형식으로도 저장할 수 있습니다.

C#

// 인식된 데이터를 vCard 형식으로 저장
card.ExportToVCard("D:\\sample.vcf");
// XML로 저장
frDoc.Export("D:\\Demo.xml", FREngine.FileExportFormatEnum.FEF_XML, null);
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;
        // 정리 후 예외 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;
}

필수 리소스

애플리케이션 실행에 필요한 파일 목록을 자동으로 만들려면 FREngineDistribution.csv 파일을 사용할 수 있습니다. 이 시나리오로 처리하려면 5열(RequiredByModule)에서 다음 값을 선택합니다: Core Core.Resources Opening Opening, Processing Processing Processing.BCR Processing.OCR Processing.OCR, Processing.ICR Processing.OCR.NaturalLanguages Processing.OCR.NaturalLanguages, Processing.ICR.NaturalLanguages Export Export, Processing 표준 시나리오를 수정하는 경우 그에 맞게 필수 모듈도 변경해야 합니다. 또한 애플리케이션에서 사용하는 인터페이스 언어, 인식 언어 및 추가 기능도 지정해야 합니다(예: PDF 파일을 열어야 하는 경우 Opening.PDF, CJK languages 텍스트를 인식해야 하는 경우 Processing.OCR.CJK). 자세한 내용은 Working with the FREngineDistribution.csv File을 참조하십시오.

추가 최적화

다양한 처리 단계의 매개변수 설정에 관한 추가 정보는 도움말 파일의 다음 섹션에서 확인할 수 있습니다.

참고 항목

기본 사용 시나리오 구현