.NET에서 OMR 버블 시트의 생년월일 인식

블로그 카테고리: 폼 처리.NET

2020/08/20

VintaSoft Imaging .NET SDKVintaSoft Forms Processing .NET Plug-in을 함께 사용하면 작성된 문서 양식에서 광학 마크(OMR)를 인식할 수 있습니다.

이 문서에서는 OMR 양식 이미지에서 생년월일을 인식하는 방법을 설명합니다.

다음은 생년월일 입력용 OMR 양식 템플릿 이미지입니다.
Image of OMR form template for filling date of birth

OMR 양식을 생성하기 전에 양식 페이지에 표시되는 모든 필드를 정의하는 양식 페이지 템플릿을 생성해야 합니다.
  1. 생년월일의 첫 번째 숫자를 입력하기 위한 OMR 마크를 통합하는 표 템플릿을 생성합니다.
  2. 생년월일의 두 번째 숫자를 입력하기 위한 OMR 마크를 통합하는 표 템플릿을 생성합니다.
  3. 생년월일의 첫 번째 및 두 번째 숫자에 대한 표 템플릿을 병합하여 생년월일 필드 그룹 템플릿을 생성합니다.
  4. 생년월일의 월을 입력하기 위한 OMR 마크를 통합하는 표 템플릿을 생성합니다.
  5. 생년월일의 처음 두 자리를 입력하기 위한 OMR 마크를 통합하는 표 템플릿을 생성합니다.
  6. 생년월일의 마지막 두 자리를 입력하기 위한 광학 마크를 통합하는 테이블 템플릿을 생성합니다.
  7. 생년월일의 첫 번째와 마지막 두 자리 숫자에 대한 테이블 템플릿을 병합하여 생년월일 필드 그룹 템플릿을 생성합니다.
  8. 일, 월, 연도에 대한 테이블 템플릿을 병합하여 생년월일 필드 그룹 템플릿을 생성합니다.
  9. 페이지 양식 템플릿을 생성하고 생년월일 필드 그룹 템플릿을 추가합니다.

다음은 생년월일 정보를 입력하는 OMR 필드가 있는 양식 페이지 템플릿을 생성하는 방법을 보여주는 C# 코드입니다.
/// <summary>
/// Creates a page template with birth date.
/// </summary>
/// <returns>A page template with birth date.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.FormPageTemplate CreatePageTemplateWithBirthDate()
{
    // create an OMR field template table for the first digit of day
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable dayPart1Template = CreateTemplateTableForFirstDigitInDay();
    // create an OMR field template table for the second digit of day
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable dayPart2Template = CreateTemplateTableForSecondDigitInDay();
    // create a form field template group for day
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup dayTemplate = CreateTemplateGroup(
        "Day", "{0}{1}", dayPart1Template, dayPart2Template);


    // create an OMR field template table for month
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable monthTemplate = CreateTemplateTableForMonth();


    // create an OMR field template table for the first 2 digits of year
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable yearPart1Template = CreateTemplateTableForFirstTwoDigitsInYear();
    // create an OMR field template table for the last 2 digits of year
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable yearPart2Template = CreateTemplateTableForLastTwoDigitsInYear();
    // create a form field template group for year
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup yearTemplate = CreateTemplateGroup(
        "Year", "{0}{1}", yearPart1Template, yearPart2Template);


    // create birth date template as a group of day, month and year templates
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup dateOfBirthTemplate = CreateTemplateGroup(
        "Date of Birth", "{0}.{1}.{2}", dayTemplate, monthTemplate, yearTemplate);


    // create an empty page template
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormPageTemplate pageTemplate =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.FormPageTemplate();

    // add birth date template to the page template
    pageTemplate.Items.Add(dateOfBirthTemplate);

    return pageTemplate;
}

/// <summary>
/// Creates an OMR field template table for the first digit of day.
/// </summary>
/// <returns>An OMR field template table for the first digit of day.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable CreateTemplateTableForFirstDigitInDay()
{
    // create template table
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable();

    // update table properties
    result.Name = "D1";
    result.ColumnCount = 1;
    result.RowCount = 4;
    result.Orientation = Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrTableOrientation.Vertical;
    result.DistanceBetweenColumns = 0.2f;
    result.DistanceBetweenRows = 0.2f;

    // update cell values

    result.CellValues[0, 0] = "0";
    result.CellValues[1, 0] = "1";
    result.CellValues[2, 0] = "2";
    result.CellValues[3, 0] = "3";

    // create table cell template
    result.CellTemplate = new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrEllipticalFieldTemplate();
    result.CellTemplate.FilledThreshold = 0.4f;

    // set table bounding box
    result.BoundingBox = new System.Drawing.RectangleF(6, 65, 20, 85);

    return result;
}

/// <summary>
/// Creates an OMR field template table for the second digit of day.
/// </summary>
/// <returns>An OMR field template table for the second digit of day.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable CreateTemplateTableForSecondDigitInDay()
{
    // create template table
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable();

    // update table properties
    result.Name = "D2";
    result.ColumnCount = 1;
    result.RowCount = 10;
    result.Orientation = Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrTableOrientation.Vertical;
    result.DistanceBetweenColumns = 0.2f;
    result.DistanceBetweenRows = 0.2f;

    // update cell values

    result.CellValues[0, 0] = "0";
    result.CellValues[1, 0] = "1";
    result.CellValues[2, 0] = "2";
    result.CellValues[3, 0] = "3";
    result.CellValues[4, 0] = "4";
    result.CellValues[5, 0] = "5";
    result.CellValues[6, 0] = "6";
    result.CellValues[7, 0] = "7";
    result.CellValues[8, 0] = "8";
    result.CellValues[9, 0] = "9";

    // create table cell template
    result.CellTemplate = new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrEllipticalFieldTemplate();
    result.CellTemplate.FilledThreshold = 0.4f;

    // set table bounding box
    result.BoundingBox = new System.Drawing.RectangleF(29, 65, 19, 216);

    return result;
}

/// <summary>
/// Creates an OMR field template table for the month.
/// </summary>
/// <returns>An OMR field template table for the month.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable CreateTemplateTableForMonth()
{
    // create template table
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable();

    // update table properties
    result.Name = "Month";
    result.ColumnCount = 1;
    result.RowCount = 12;
    result.Orientation = Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrTableOrientation.Vertical;
    result.DistanceBetweenColumns = 0.2f;
    result.DistanceBetweenRows = 0.2f;

    // update cell values

    result.CellValues[0, 0] = "1";
    result.CellValues[1, 0] = "2";
    result.CellValues[2, 0] = "3";
    result.CellValues[3, 0] = "4";
    result.CellValues[4, 0] = "5";
    result.CellValues[5, 0] = "6";
    result.CellValues[6, 0] = "7";
    result.CellValues[7, 0] = "8";
    result.CellValues[8, 0] = "9";
    result.CellValues[9, 0] = "10";
    result.CellValues[9, 0] = "11";
    result.CellValues[9, 0] = "12";

    // create table cell template
    result.CellTemplate = new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrEllipticalFieldTemplate();
    result.CellTemplate.FilledThreshold = 0.4f;

    // set table bounding box
    result.BoundingBox = new System.Drawing.RectangleF(59, 66, 15, 214);

    return result;
}

/// <summary>
/// Creates an OMR field template table for the first 2 digits of year.
/// </summary>
/// <returns>An OMR field template table for the first 2 digits of year.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable CreateTemplateTableForFirstTwoDigitsInYear()
{
    // create template table
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable();

    // update table properties
    result.Name = "Y1";
    result.ColumnCount = 2;
    result.RowCount = 2;
    result.Orientation = Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrTableOrientation.Vertical;
    result.DistanceBetweenColumns = 0.2f;
    result.DistanceBetweenRows = 0.2f;

    // update cell values

    result.CellValues[0, 0] = "1";
    result.CellValues[0, 1] = "9";
    result.CellValues[1, 0] = "2";
    result.CellValues[1, 1] = "0";

    // create table cell template
    result.CellTemplate = new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrEllipticalFieldTemplate();
    result.CellTemplate.FilledThreshold = 0.4f;

    // set table bounding box
    result.BoundingBox = new System.Drawing.RectangleF(154, 65, 42, 40);

    return result;
}

/// <summary>
/// Creates an OMR field template table for the last 2 digits of year.
/// </summary>
/// <returns>An OMR field template table for the last 2 digits of year.</returns>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable CreateTemplateTableForLastTwoDigitsInYear()
{
    // create template table
    Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrFieldTemplateTable();

    // update table properties
    result.Name = "Y2";
    result.ColumnCount = 2;
    result.RowCount = 10;
    result.Orientation = Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrTableOrientation.Vertical;
    result.DistanceBetweenColumns = 0.2f;
    result.DistanceBetweenRows = 0.2f;

    // update cell values

    result.CellValues[0, 0] = "0";
    result.CellValues[0, 1] = "0";
    result.CellValues[1, 0] = "1";
    result.CellValues[1, 1] = "1";
    result.CellValues[2, 0] = "2";
    result.CellValues[2, 1] = "2";
    result.CellValues[3, 0] = "3";
    result.CellValues[3, 1] = "3";
    result.CellValues[4, 0] = "4";
    result.CellValues[4, 1] = "4";
    result.CellValues[5, 0] = "5";
    result.CellValues[5, 1] = "5";
    result.CellValues[6, 0] = "6";
    result.CellValues[6, 1] = "6";
    result.CellValues[7, 0] = "7";
    result.CellValues[7, 1] = "7";
    result.CellValues[8, 0] = "8";
    result.CellValues[8, 1] = "8";
    result.CellValues[9, 0] = "9";
    result.CellValues[9, 1] = "9";

    // create table cell template
    result.CellTemplate = new Vintasoft.Imaging.FormsProcessing.FormRecognition.Omr.OmrEllipticalFieldTemplate();
    result.CellTemplate.FilledThreshold = 0.4f;

    // set table bounding box
    result.BoundingBox = new System.Drawing.RectangleF(199, 65, 41, 216);

    return result;
}

/// <summary>
/// Creates the form field template group.
/// </summary>
/// <param name="name">The group name.</param>
/// <param name="valueFormat">The group value format.</param>
/// <param name="items">The group items.</param>
private static Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup CreateTemplateGroup(
    string name,
    string valueFormat,
    params Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplate[] items)
{
    // create a form field template group
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup result =
        new Vintasoft.Imaging.FormsProcessing.FormRecognition.FormFieldTemplateGroup();
    // add item to the form field template group
    result.Items.AddRange(items);

    // set name of form field template group
    result.Name = name;
    // set value format of form field template group
    result.ValueFormat = valueFormat;

    return result;
}


양식 페이지 템플릿이 준비되면 양식이 채워진 페이지에서 인식을 시작할 수 있습니다.

생년월일이 저장된, 회전되지 않은 OMR 양식의 이미지(100dpi 해상도)입니다.
An image (100dpi) of filled non-rotated OMR form, which stores the date of birth

생년월일이 저장된, 회전되지 않은 OMR 양식의 이미지(200dpi 해상도)입니다.
An image (200dpi) of filled non-rotated OMR form, which stores the date of birth

생년월일이 저장된, 회전되지 않은 OMR 양식의 이미지(300dpi 해상도)입니다.
An image (300dpi) of filled non-rotated OMR form, which stores the date of birth

생년월일이 저장된, 20도 회전된 OMR 양식의 이미지입니다.
An image of filled rotated (20 degrees) OMR form, which stores the date of birth

생년월일이 저장된, 150도 회전된 OMR 양식의 이미지입니다.
An image of filled rotated (150 degrees) OMR form, which stores the date of birth


생년월일이 저장된 OMR 양식을 인식하는 C# 코드입니다.
/// <summary>
/// Recognizes the birth date in filled OMR form.
/// </summary>
/// <param name="templateImagePath">A path to an image that represents a form template for filling the birth date.</param>
/// <param name="filledImagePath">A path to an image that represents filled form with the birth date.</param>
public static void RecognizeBirthDateInFilledOmrForm(string templateImagePath, string filledImagePath)
{
    // open an image that represents a form template for filling the birth date
    using (Vintasoft.Imaging.VintasoftImage templateImage = new Vintasoft.Imaging.VintasoftImage(templateImagePath))
    {
        // create a template manager
        Vintasoft.Imaging.FormsProcessing.FormRecognition.FormTemplateManager formTemplateManager =
            new Vintasoft.Imaging.FormsProcessing.FormRecognition.FormTemplateManager();
        // create a page template with birth date
        Vintasoft.Imaging.FormsProcessing.FormRecognition.FormPageTemplate formPageTemplate = CreatePageTemplateWithBirthDate();
        // add template image and page template to the template manager
        formTemplateManager.AddPageTemplate(templateImage, formPageTemplate);

        // open an image that represents filled form with the birth date
        using (Vintasoft.Imaging.VintasoftImage filledImage = new Vintasoft.Imaging.VintasoftImage(filledImagePath))
        {
            // recognize filled form with birth date
            RecognizeFilledFormInImage(formTemplateManager, filledImage);
        }
    }
}

/// <summary>
/// Recognizes filled form in an image.
/// </summary>
/// <param name="templateManager">The template manager that contains information about form template.</param>
/// <param name="image">An image that represents filled form.</param>
private static void RecognizeFilledFormInImage(
    Vintasoft.Imaging.FormsProcessing.FormRecognition.FormTemplateManager templateManager,
    Vintasoft.Imaging.VintasoftImage image)
{
    // create the template matching command
    Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateMatchingCommand templateMatchingCommand =
        new Vintasoft.Imaging.FormsProcessing.TemplateMatching.TemplateMatchingCommand();
    // set the minimum confidence
    templateMatchingCommand.MinConfidence = 0.5f;
    // set template images
    templateMatchingCommand.TemplateImages = templateManager.TemplateImages;

    // create the form recognition manager
    Vintasoft.Imaging.FormsProcessing.FormRecognitionManager formRecognitionManager =
        new Vintasoft.Imaging.FormsProcessing.FormRecognitionManager(templateMatchingCommand, templateManager);

    // subscribe to the FormRecognitionResult.ImageRecognitionError event to output recognition errors
    formRecognitionManager.ImageRecognitionError += RecognitionManager_ImageRecognitionError;

    // recognize form in image
    Vintasoft.Imaging.FormsProcessing.FormRecognitionResult formRecognitionResult = formRecognitionManager.Recognize(image);

    // unsubscribe from FormRecognitionResult.ImageRecognitionError event
    formRecognitionManager.ImageRecognitionError -= RecognitionManager_ImageRecognitionError;

    // if recognition is failed
    if (formRecognitionResult == null)
        return;

    // get the result of image comparison
    Vintasoft.Imaging.FormsProcessing.TemplateMatching.ImageImprintCompareResult imageImprintCompareResult =
        formRecognitionResult.TemplateMatchingResult.ImageCompareResult;
    // if image comparison result is NOT reliable
    if (!imageImprintCompareResult.IsReliable)
    {
        // matching template is not found
        System.Console.WriteLine("Matching template is not found.");
    }
    // if image comparison result is reliable
    else
    {
        // get recognized form page
        Vintasoft.Imaging.FormsProcessing.FormRecognition.FormPage recognizedPage = formRecognitionResult.RecognizedPage;
        // write page info
        System.Console.WriteLine(string.Format(
            "Matching template: {0}; confidence: {1:F1}%.",
            recognizedPage.Name,
            imageImprintCompareResult.Confidence * 100));

        // get form field count
        if (recognizedPage.Items.Count == 0)
        {
            System.Console.WriteLine("No form fields were recognized.");
        }
        else
        {
            System.Console.WriteLine(string.Format(
                "Recognized form field count: {0}",
                recognizedPage.Items.Count));
            // for each recognized form field
            foreach (Vintasoft.Imaging.FormsProcessing.FormRecognition.FormField recognizedField in recognizedPage.Items)
            {
                // write field info to the console
                System.Console.WriteLine(string.Format(
                    "  Name: {0}; value: {1}; confidence: {2:F1}%",
                    recognizedField.Name,
                    recognizedField.Value,
                    recognizedField.Confidence * 100));
            }
        }
    }
}

/// <summary>
/// Handles the ImageRecognitionError event of the FormRecognitionManager.
/// </summary>
private static void RecognitionManager_ImageRecognitionError(
    object sender,
    Vintasoft.Imaging.FormsProcessing.FormRecognitionErrorEventArgs e)
{
    // writes information about form recognition error to the console
    System.Console.WriteLine(e.Exception.Message);
}