Dynamsoft C++ OCR SDK를 이용한 여권 MRZ 인식

34149 단어 cpppassportmrzocr
MRZ은 기계 판독 가능 영역을 나타냅니다. 여권에는 이름, 국적, 여권 번호, 생년월일, 성별 및 여권 만료일에 대한 정보가 포함된 기계 판독 영역이 있습니다. 이 글은 Dynamsoft OCR SDK를 사용하여 MRZ를 인식하고 해당 정보를 파싱하는 방법을 소개합니다.

Dynamsoft OCR SDK 정보


  • Windows 및 Linux를 지원하는 DynamsoftC++ OCR dev package를 다운로드합니다.
  • 30-day FREE Trial License을 가져옵니다.

  • 전제 조건



    윈도우
  • OpenCV
  • CMake

  • 리눅스

    sudo apt install libopencv-dev cmake
    


    C++에서 여권 MRZ 인식



    다음 단락에서는 먼저 Dynamsoft OCR SDK를 사용하여 여권의 기계 판독 가능 영역을 현지화하고 해당 텍스트 문자열을 인식한 다음 여권 소책자의 표준 형식에 따라 텍스트 문자열에서 모든 정보를 추출합니다.

    CMake 프로젝트 설정



    Windows 및 Linux용 CMake 프로젝트를 만들고 디버그하려면 Visual Studio Code에 CMake 확장을 설치하는 것이 좋습니다.

    CMakeLists에서 Dynamsoft OCR 및 OpenCV의 헤더 파일과 연결 라이브러리를 구성해 보겠습니다.

    cmake_minimum_required (VERSION 2.6)
    project (mrz)
    MESSAGE( STATUS "PROJECT_NAME: " ${PROJECT_NAME} )
    
    # Check platforms
    if (CMAKE_HOST_WIN32)
        set(WINDOWS 1)
    elseif(CMAKE_HOST_UNIX)
        set(LINUX 1)
    endif()
    
    # Add search path for include and lib files
    MESSAGE( STATUS "CPU architecture ${CMAKE_SYSTEM_PROCESSOR}" )
    if(WINDOWS)
        link_directories("${PROJECT_SOURCE_DIR}/platform/windows/lib/") 
    elseif(LINUX)
        link_directories("${PROJECT_SOURCE_DIR}/platform/linux/")
    endif()
    include_directories("${PROJECT_BINARY_DIR}" "${PROJECT_SOURCE_DIR}/include/")
    
    # Add the executable
    find_package(OpenCV REQUIRED)
        add_executable(${PROJECT_NAME} mrzcv.cpp)
        if(WINDOWS)
            target_link_libraries (${PROJECT_NAME} "DynamsoftLabelRecognitionx64" ${OpenCV_LIBS})
        else()
            target_link_libraries (${PROJECT_NAME} "DynamsoftLabelRecognition" ${OpenCV_LIBS})
        endif()
    
    # Copy DLLs
    if(WINDOWS)
        add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
            COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PROJECT_SOURCE_DIR}/platform/windows/bin/"      
            $<TARGET_FILE_DIR:${PROJECT_NAME}>)
    endif()
    


    DNN(심층 신경망)에서 훈련된 문자 모델은 C++ dev 패키지에서 찾을 수 있습니다. 전체 모델 폴더를 출력 디렉터리에 복사해야 하며 템플릿 파일도 마찬가지입니다.

    # Copy template
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
            COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PROJECT_SOURCE_DIR}/template/"      
            $<TARGET_FILE_DIR:${PROJECT_NAME}>)
    
    # Copy model files
    add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD 
            COMMAND ${CMAKE_COMMAND} -E copy_directory
            "${PROJECT_SOURCE_DIR}/CharacterModel"      
            $<TARGET_FILE_DIR:${PROJECT_NAME}>/CharacterModel)
    


    online documentation은 템플릿 매개변수가 작동하는 방식을 파악하는 데 도움이 될 수 있습니다.

    MRZ 감지 및 정보 구문 분석을 위한 코딩



    빌드 구성이 완료되면 코드 부분으로 이동할 수 있습니다.

  • OCR 개체를 초기화합니다. 유효한 라이센스 키가 필요합니다.

    CLabelRecognition dlr;
    dlr.InitLicense("LICENSE-KEY");
    


  • 템플릿 파일을 추가합니다.

    int ret = dlr.AppendSettingsFromFile("template-file");
    

    참고: 템플릿 파일에 구성된 DirectoryPath가 상대 경로인 경우 모델 폴더와 함께 템플릿 파일을 넣어야 합니다.

    "CharacterModelArray" : [
    {
      "DirectoryPath": "CharacterModel",
      "FilterFilePath": "",
      "Name": "NumberUppercase"
    }
    ],
    


  • OCR 인식 방법을 호출합니다. OpenCV의 내장 함수를 사용하여 통과 시간을 측정할 수 있습니다. TickMeter 클래스는 Windows 및 Linux의 시간 계산 코드를 단순화합니다.

    TickMeter tm;
    tm.start();
    errorCode = dlr.RecognizeByFile(pszImageFile, "locr");
    tm.stop();
    float costTime = tm.getTimeSec();
    


  • 텍스트 영역, 텍스트 라인 및 텍스트 문자열의 좌표를 포함하는 텍스트 인식 결과를 가져옵니다.

    DLRResultArray* pDLRResults = NULL;
        dlr.GetAllDLRResults(&pDLRResults);
        if (pDLRResults != NULL)
        {
            int rCount = pDLRResults->resultsCount;
            printf("\r\nRecognized %d results\r\n", rCount);
            for (int ri = 0; ri < rCount; ++ri)
            {
                printf("\r\nResult %d :\r\n", ri);
                int startX = 50, startY = 50;
                DLRResult* result = pDLRResults->results[ri];
                int lCount = result->lineResultsCount;
                for (int li = 0; li < lCount; ++li)
                {
                    printf("Line result %d: %s\r\n", li, result->lineResults[li]->text);
                    DLRPoint *points = result->lineResults[li]->location.points;
                    printf("x1: %d, y1: %d, x2: %d, y2: %d, x3: %d, y3: %d, x4: %d, y4: %d\r\n", points[0].x, 
                    points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, points[3].x, points[3].y);
                }
            }
        }
        else
        {
            printf("\r\nNo data detected.\r\n");
        }
        dlr.FreeDLRResults(&pDLRResults);
    


  • MRZ 문자열을 구문 분석하고 해당 정보를 추출합니다.

    string line1 = result->lineResults[0]->text;
    string line2 = result->lineResults[1]->text;
    // https://en.wikipedia.org/wiki/Machine-readable_passport
    // Type
    string tmp = "Type: ";
    tmp.insert(tmp.length(), 1, line1[0]);
    printf("%s\r\n", tmp.c_str());
    
    // Issuing country
    tmp = "Issuing country: "; line1.substr(2, 5);
    tmp += line1.substr(2, 3);      
    printf("%s\r\n", tmp.c_str());
    
    // Surname
    int index = 5;
    tmp = "Surname: ";
    for (; index < 44; index++)
    {
      if (line1[index] != '<')
      {
        tmp.insert(tmp.length(), 1, line1[index]);
      }
      else 
      {
        break;
      }
    }
    printf("%s\r\n", tmp.c_str());
    
    // Given names
    tmp = "Given Names: ";
    index += 2;
    for (; index < 44; index++)
    {
      if (line1[index] != '<')
      {
        tmp.insert(tmp.length(), 1, line1[index]);
      }
      else 
      {
        tmp.insert(tmp.length(), 1, ' ');
      }
    }
    printf("%s\r\n", tmp.c_str());
    
    // Passport number
    tmp = "Passport number: ";
    index = 0;
    for (; index < 9; index++)
    {
      if (line2[index] != '<')
      {
        tmp.insert(tmp.length(), 1, line2[index]);
      }
      else 
      {
        break;
      }
    }
    printf("%s\r\n", tmp.c_str());
    
    // Nationality
    tmp = "Nationality: ";
    tmp += line2.substr(10, 3);
    printf("%s\r\n", tmp.c_str());
    
    // Date of birth
    tmp = line2.substr(13, 6);
    tmp.insert(2, "/");
    tmp.insert(5, "/");
    tmp = "Date of birth (YYMMDD): " + tmp;
    printf("%s\r\n", tmp.c_str());
    
    // Sex
    tmp = "Sex: ";
    tmp.insert(tmp.length(), 1, line2[20]);
    printf("%s\r\n", tmp.c_str());
    
    // Expiration date of passport
    tmp = line2.substr(21, 6);
    tmp.insert(2, "/");
    tmp.insert(5, "/");
    tmp = "Expiration date of passport (YYMMDD): " + tmp;
    printf("%s\r\n", tmp.c_str());
    
    // Personal number
    if (line2[28] != '<')
    {
      tmp = "Personal number: ";
      for (index = 28; index < 42; index++)
      {
        if (line2[index] != '<')
        {
          tmp.insert(tmp.length(), 1, line2[index]);
        }
        else 
        {
          break;
        }
      }
      printf("%s\r\n", tmp.c_str());
    }
    


  • 프로그램을 사용자에게 친숙하게 만들기 위해 OpenCV를 사용하여 디스플레이 창을 표시하고 관련 정보를 그립니다.

    line( ori, Point(x1, y1), Point(x2, y2), lineColor, thickness);
    line( ori, Point(x2, y2), Point(x3, y3), lineColor, thickness);
    line( ori, Point(x3, y3), Point(x4, y4), lineColor, thickness);
    line( ori, Point(x4, y4), Point(x1, y1), lineColor, thickness);
    drawText(ori, result->lineResults[li]->text, minX, minY - scale * 10);
    
    imshow("Passport MRZ Recognition", ori);
    




    추가 개선 사항은 hconcat 기능을 사용하여 더 나은 비교를 위해 이미지를 연결하는 것입니다.

    hconcat(before, after, newMat);
    imshow("Comparison", newMat);
    




    소스 코드



    https://github.com/yushulx/passport-mrz-recognition

    좋은 웹페이지 즐겨찾기