C#을 사용하여 문서의 표를 읽는 방법

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronOCR는 ReadDocumentAdvanced 메서드를 사용하여 병합된 셀을 포함한 인보이스와 같은 복잡한 구조와 기본 셀을 가진 간단한 테이블 모두를 처리하면서 고급 머신 러닝 모델을 사용하여 PDF 및 이미지에서 테이블 데이터를 추출할 수 있도록 C# 개발자에게 제공합니다.

일반 Tesseract를 사용하여 표에서 데이터를 추출하는 것은 텍스트가 셀에 존재하고 문서 전체에 드문드문 흩어져 있는 경우가 많기 때문에 어려울 수 있습니다. 하지만 저희 라이브러리에는 테이블 데이터를 정확하게 감지하고 추출하도록 학습 및 미세 조정된 머신 러닝 모델이 포함되어 있습니다. IronOCR은 재무 보고서, 재고 목록 또는 송장 데이터를 처리하든 관계없이 구조화된 데이터를 효율적으로 분석하는 도구를 제공합니다.

간단한 테이블의 경우, 표준 OcrInput 클래스를 사용하여 간단한 테이블 감지에 의존하세요. 보다 복잡한 구조의 경우, 당사의 독점 ReadDocumentAdvanced 메서드는 표를 효과적으로 구문 분석하고 데이터를 제공하여 견고한 결과를 제공합니다. 이 고급 방법은 머신 러닝을 활용하여 기존 OCR이 종종 어려움을 겪는 표 레이아웃, 병합된 셀 및 복잡한 서식을 이해합니다.

빠른 시작: 한 번의 호출로 복잡한 테이블 셀 추출

몇 분 안에 시작하세요. 이 예제는 복잡한 문서에서 세부적인 테이블 셀 데이터를 제공하는 ReadDocumentAdvanced을 사용하는 단일 IronOCR 호출 방법을 보여줍니다. PDF 파일을 불러와 고급 표 감지 기능을 적용하고 셀 정보 목록을 직접 반환함으로써 사용 편의성을 보여줍니다.

  1. NuGet 패키지 관리자를 사용하여 https://www.nuget.org/packages/IronOcr 설치하기

    PM > Install-Package IronOcr
  2. 다음 코드 조각을 복사하여 실행하세요.

    var cells = new IronTesseract().ReadDocumentAdvanced(new OcrInput().LoadPdf("invoiceTable.pdf")).Tables.First().CellInfos;
  3. 실제 운영 환경에서 테스트할 수 있도록 배포하세요.

    무료 체험판으로 오늘 프로젝트에서 IronOCR 사용 시작하기

    arrow pointer

다음 단계는 IronOCR을 사용하여 표를 읽는 방법을 안내합니다.


간단한 표에서 데이터를 추출하는 방법은 무엇인가요?

ReadDataTables 속성을 true로 설정하면 Tesseract를 사용하여 표 감지를 사용할 수 있습니다. 이 방법은 셀 경계가 명확하고 병합된 셀이 없는 기본적인 표에 효과적입니다. 이 기능을 테스트하기 위해 간단한 표 형식의 PDF 파일을 만들었습니다. 여기에서 다운로드하실 수 있습니다: ' simple-table.pdf '. 이 방법을 사용하면 셀 병합이 없는 단순 테이블을 감지할 수 있습니다. 더 복잡한 표의 경우 아래에 설명된 방법을 참조하십시오.

표준 테이블 감지 방법은 특히 다음과 같은 경우에 효과적입니다.

  • 스프레드시트 내보내기
  • 일관된 행/열 구조를 가진 기본 데이터 테이블
  • 표 형식 데이터가 포함된 보고서
  • 간단한 재고 목록

일반적으로 PDF OCR 텍스트 추출 작업을 하는 경우, 이 방법은 IronOCR의 광범위한 문서 처리 기능과 완벽하게 통합됩니다.

:path=/static-assets/ocr/content-code-examples/how-to/read-table-in-document-with-tesseract.cs
using IronOcr;
using System;
using System.Data;

// Instantiate OCR engine
var ocr = new IronTesseract();

// Enable table detection
ocr.Configuration.ReadDataTables = true;

using var input = new OcrPdfInput("simple-table.pdf");
var result = ocr.Read(input);

// Retrieve the data
var table = result.Tables[0].DataTable;

// Print out the table data
foreach (DataRow row in table.Rows)
{
    foreach (var item in row.ItemArray)
    {
        Console.Write(item + "\t");
    }
    Console.WriteLine();
}
$vbLabelText   $csharpLabel

복잡한 송장 표를 어떻게 읽을 수 있나요?

비즈니스 환경에서 흔히 볼 수 있는 복잡한 표 중 하나는 송장입니다. 송장은 행과 열로 이루어진 복잡한 데이터 표이며, 종종 셀이 병합되거나, 열 너비가 다르거나, 중첩된 구조를 가지고 있습니다. IronOCR와 함께, 우리는 ReadDocumentAdvanced 메서드를 사용하여 이를 효과적으로 처리합니다. 이 과정은 문서를 스캔하고, 표 구조를 파악하고, 데이터를 추출하는 것을 포함합니다. 이 예시에서는 ' invoiceTable.pdf ' 파일을 사용하여 IronOCR이 송장에서 모든 정보를 추출하는 방법을 보여줍니다.

ReadDocumentAdvanced 메서드는 기본 IronOCR 패키지와 함께 IronOcr.Extensions.AdvancedScan 패키지를 설치해야 합니다. 이 확장 프로그램은 복잡한 문서 레이아웃에 맞게 특별히 학습된 고급 머신 러닝 기능을 제공합니다.

참고해 주세요
.NET Framework 에서 고급 검사를 사용하려면 프로젝트가 x64 아키텍처에서 실행되어야 합니다. 이 작업을 수행하려면 프로젝트 구성으로 이동하여 "32비트 우선" 옵션의 선택을 해제하십시오. 자세한 내용은 다음 문제 해결 가이드 " .NET Framework 고급 검사 "를 참조하십시오.
)}]

:path=/static-assets/ocr/content-code-examples/how-to/read-table-in-document-with-ml.cs
using IronOcr;
using System.Linq;

// Instantiate OCR engine
var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadPdf("invoiceTable.pdf");

// Perform OCR
var result = ocr.ReadDocumentAdvanced(input);

var cellList = result.Tables.First().CellInfos;
$vbLabelText   $csharpLabel

이 방법은 문서의 텍스트 데이터를 테두리로 둘러싸인 텍스트와 테두리가 없는 텍스트, 이렇게 두 가지 범주로 나눕니다. 테두리가 있는 콘텐츠의 경우, 라이브러리는 테이블 구조에 따라 해당 콘텐츠를 하위 섹션으로 더 세분화합니다. 이 방법은 다음과 같은 상황에서 탁월한 성능을 발휘합니다:

  • 설명이 다양한 송장 품목
  • 다중 열 가격 분석
  • 배송 및 청구 주소 블록
  • 세금 및 총액 계산 부분
  • 머리글 및 바닥글 정보

결과는 아래와 같습니다. 이 방법은 테두리로 둘러싸인 정보에 초점을 맞추기 때문에 여러 행에 걸쳐 병합된 셀은 단일 셀로 처리됩니다.

추출된 데이터는 어떤 형태인가요?

IronSoftware OCR을 사용하여 배송 송장의 표 데이터를 추출하고 구조화된 계층 형식으로 변환합니다.

추출된 테이블 셀을 어떻게 정리하고 처리해야 하나요?

현재 구현에서는 추출된 세포들이 아직 제대로 정리되지 않았습니다. 하지만 각 셀에는 X, Y 좌표, 크기 등과 같은 귀중한 정보가 담겨 있습니다. 이 데이터를 활용하면 다양한 용도로 사용할 수 있는 헬퍼 클래스를 만들 수 있습니다. 세포 정보에는 다음이 포함됩니다.

  • 정확한 위치 지정을 위한 X/Y 좌표
  • 너비 및 높이 치수
  • 텍스트 내용
  • 신뢰도 점수
  • 세포 간 관계

이러한 상세 정보를 통해 프로그래밍 방식으로 테이블 구조를 재구성하고 데이터 추출을 위한 사용자 지정 로직을 적용할 수 있습니다. 이러한 좌표를 사용하여 후속 작업에서 특정 영역을 대상으로 OCR 처리를 수행 할 수 있습니다.

다음은 몇 가지 기본적인 도우미 메서드입니다.

using System;
using System.Collections.Generic;
using System.Linq;

// A helper class to process table data by sorting cells based on coordinates
public static class TableProcessor
{
    // Method to organize cells by their coordinates (Y top to bottom, X left to right)
    public static List<CellInfo> OrganizeCellsByCoordinates(List<CellInfo> cells)
    {
        // Sort cells by Y (top to bottom), then by X (left to right)
        var sortedCells = cells
            .OrderBy(cell => cell.CellRect.Y)
            .ThenBy(cell => cell.CellRect.X)
            .ToList();

        return sortedCells;
    }

    // Example method demonstrating how to process multiple tables
    public static void ProcessTables(Tables tables)
    {
        foreach (var table in tables)
        {
            var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);

            Console.WriteLine("Organized Table Cells:");

            // Initialize previous Y coordinate
            int previousY = sortedCells.Any() ? sortedCells.First().CellRect.Y : 0;

            foreach (var cell in sortedCells)
            {
                // Print a new line if the Y-coordinate changes, indicating a new row
                if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
                {
                    Console.WriteLine();  // Start a new row
                    previousY = cell.CellRect.Y;
                }

                // Print the cell text followed by a tab
                Console.Write($"{cell.CellText}\t");
            }

            Console.WriteLine("\n--- End of Table ---");  // End of a table
        }
    }

    // Method to extract a specific row by the given index
    public static List<CellInfo> ExtractRowByIndex(TableInfo table, int rowIndex)
    {
        if (table == null || table.CellInfos == null || !table.CellInfos.Any())
        {
            throw new ArgumentException("Table is empty or invalid.");
        }

        var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);
        List<List<CellInfo>> rows = new List<List<CellInfo>>();

        // Group cells into rows based on Y coordinates
        int previousY = sortedCells.First().CellRect.Y;
        List<CellInfo> currentRow = new List<CellInfo>();

        foreach (var cell in sortedCells)
        {
            if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
            {
                // Store the completed row and start a new one
                rows.Add(new List<CellInfo>(currentRow));
                currentRow.Clear();

                previousY = cell.CellRect.Y;
            }

            currentRow.Add(cell);
        }

        // Add the last row if it wasn't added yet
        if (currentRow.Any())
        {
            rows.Add(currentRow);
        }

        // Retrieve the specified row
        if (rowIndex < 0 || rowIndex >= rows.Count)
        {
            throw new IndexOutOfRangeException($"Row index {rowIndex} is out of range.");
        }

        return rows[rowIndex];
    }
}
using System;
using System.Collections.Generic;
using System.Linq;

// A helper class to process table data by sorting cells based on coordinates
public static class TableProcessor
{
    // Method to organize cells by their coordinates (Y top to bottom, X left to right)
    public static List<CellInfo> OrganizeCellsByCoordinates(List<CellInfo> cells)
    {
        // Sort cells by Y (top to bottom), then by X (left to right)
        var sortedCells = cells
            .OrderBy(cell => cell.CellRect.Y)
            .ThenBy(cell => cell.CellRect.X)
            .ToList();

        return sortedCells;
    }

    // Example method demonstrating how to process multiple tables
    public static void ProcessTables(Tables tables)
    {
        foreach (var table in tables)
        {
            var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);

            Console.WriteLine("Organized Table Cells:");

            // Initialize previous Y coordinate
            int previousY = sortedCells.Any() ? sortedCells.First().CellRect.Y : 0;

            foreach (var cell in sortedCells)
            {
                // Print a new line if the Y-coordinate changes, indicating a new row
                if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
                {
                    Console.WriteLine();  // Start a new row
                    previousY = cell.CellRect.Y;
                }

                // Print the cell text followed by a tab
                Console.Write($"{cell.CellText}\t");
            }

            Console.WriteLine("\n--- End of Table ---");  // End of a table
        }
    }

    // Method to extract a specific row by the given index
    public static List<CellInfo> ExtractRowByIndex(TableInfo table, int rowIndex)
    {
        if (table == null || table.CellInfos == null || !table.CellInfos.Any())
        {
            throw new ArgumentException("Table is empty or invalid.");
        }

        var sortedCells = OrganizeCellsByCoordinates(table.CellInfos);
        List<List<CellInfo>> rows = new List<List<CellInfo>>();

        // Group cells into rows based on Y coordinates
        int previousY = sortedCells.First().CellRect.Y;
        List<CellInfo> currentRow = new List<CellInfo>();

        foreach (var cell in sortedCells)
        {
            if (Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8)
            {
                // Store the completed row and start a new one
                rows.Add(new List<CellInfo>(currentRow));
                currentRow.Clear();

                previousY = cell.CellRect.Y;
            }

            currentRow.Add(cell);
        }

        // Add the last row if it wasn't added yet
        if (currentRow.Any())
        {
            rows.Add(currentRow);
        }

        // Retrieve the specified row
        if (rowIndex < 0 || rowIndex >= rows.Count)
        {
            throw new IndexOutOfRangeException($"Row index {rowIndex} is out of range.");
        }

        return rows[rowIndex];
    }
}
$vbLabelText   $csharpLabel

테이블 추출을 위한 모범 사례

IronOCR에서 테이블 추출 작업을 할 때는 다음과 같은 모범 사례를 고려하십시오.

  1. 문서 품질 : 해상도가 높은 문서일수록 더 나은 결과를 얻을 수 있습니다. 스캔한 문서의 경우 최소 300 DPI를 확인하십시오.

  2. 전처리 : 품질이 낮거나 표가 왜곡된 문서의 경우, 처리 전에 IronOCR의 이미지 보정 기능을 사용하는 것을 고려해 보세요.

  3. 성능 : 여러 테이블이 포함된 대용량 문서의 경우, 페이지를 병렬로 처리하기 위해 멀티스레딩 및 비동기 지원을 활용하는 것을 고려하십시오.

  4. 출력 옵션 : 테이블 데이터를 추출한 후 다양한 형식으로 결과를 내보낼 수 있습니다. 데이터 출력 옵션 과 처리된 문서에서 검색 가능한 PDF를 생성하는 방법에 대해 자세히 알아보세요.

  5. 스트림 처리 : 웹 애플리케이션이나 메모리 내 문서를 사용하는 시나리오의 경우 파일 시스템 작업을 피하기 위해 PDF 스트림에 OCR을 사용하는 것을 고려해 보세요.

요약

IronOCR은 표준 Tesseract 기반 탐지 및 고급 머신 러닝 방법을 통해 강력한 테이블 추출 기능을 제공합니다. 표준 접근법은 간단한 테이블에 잘 작동하며, ReadDocumentAdvanced 메서드는 인보이스와 같은 복잡한 문서에 뛰어납니다. 제공된 도우미 메서드를 사용하면 추출된 데이터를 특정 요구 사항에 맞게 구성하고 처리할 수 있습니다.

IronOCR의 다양한 기능을 살펴보고 문서 처리 워크플로를 개선하며 .NET 애플리케이션에서 광학 문자 인식의 잠재력을 최대한 활용해 보세요.

자주 묻는 질문

C#에서 PDF 및 이미지에서 표 데이터를 추출하는 방법은 무엇입니까?

IronOCR은 C# 개발자가 고급 머신러닝 모델을 사용하여 PDF 및 이미지에서 표 데이터를 추출할 수 있도록 지원합니다. 간단한 표의 경우, ReadDataTables 속성을 true로 설정한 OcrInput 클래스를 사용하십시오. 병합된 셀이 있는 복잡한 표의 경우, 더 정확한 결과를 얻으려면 ReadDocumentAdvanced 메서드를 사용하십시오.

단순 테이블 추출과 복잡 테이블 추출의 차이점은 무엇인가요?

IronOCR에서 간단한 표 추출은 Tesseract의 ReadDataTables 속성을 사용하며, 셀 경계가 명확한 기본 표에 적합합니다. 복잡한 표 추출에는 ReadDocumentAdvanced 메서드가 필요하며, 이 메서드는 머신 러닝을 사용하여 병합된 셀, 송장 및 복잡한 서식을 처리합니다.

복잡한 표에서 데이터를 빠르게 추출하는 방법은 무엇인가요?

IronOCR의 ReadDocumentAdvanced 메서드를 한 번에 호출하여 사용할 수 있습니다. 예를 들어, 다음과 같이 작성할 수 있습니다. var cells = new IronTesseract().ReadDocumentAdvanced(new OcrInput().LoadPdf('invoiceTable.pdf')).Tables.First().CellInfos; 이 코드는 머신 러닝을 활용하여 테이블 레이아웃과 복잡한 서식을 이해합니다.

간단한 테이블 감지 기능에 가장 적합한 문서 유형은 무엇인가요?

IronOCR의 간단한 테이블 감지 방법은 스프레드시트 내보내기, 일관된 행/열 구조를 가진 기본 데이터 테이블, 표 형식 데이터가 포함된 보고서, 병합된 셀이 없는 간단한 재고 목록에서 특히 효과적입니다.

기본 테이블에 대한 테이블 감지 기능을 어떻게 활성화할 수 있나요?

IronOCR에서 기본 테이블에 대한 테이블 감지 기능을 활성화하려면 ReadDataTables 속성을 true로 설정하십시오. 이렇게 하면 Tesseract의 테이블 감지 기능을 사용할 수 있으며, 셀 경계가 명확하고 병합된 셀이 없는 테이블에서 잘 작동합니다.

도서관에서 복잡한 레이아웃의 청구서와 재무 보고서를 처리할 수 있습니까?

네, IronOCR의 ReadDocumentAdvanced 메서드는 송장이나 재무 보고서와 같은 복잡한 문서를 처리하도록 특별히 설계되었습니다. 이 메서드는 병합된 셀과 복잡한 서식이 포함된 표에서 데이터를 감지하고 추출하도록 학습된 머신 러닝 모델을 사용합니다.

커티스 차우
기술 문서 작성자

커티스 차우는 칼턴 대학교에서 컴퓨터 과학 학사 학위를 취득했으며, Node.js, TypeScript, JavaScript, React를 전문으로 하는 프론트엔드 개발자입니다. 직관적이고 미적으로 뛰어난 사용자 인터페이스를 만드는 데 열정을 가진 그는 최신 프레임워크를 활용하고, 잘 구성되고 시각적으로 매력적인 매뉴얼을 제작하는 것을 즐깁니다.

커티스는 개발 분야 외에도 사물 인터넷(IoT)에 깊은 관심을 가지고 있으며, 하드웨어와 소프트웨어를 통합하는 혁신적인 방법을 연구합니다. 여가 시간에는 게임을 즐기거나 디스코드 봇을 만들면서 기술에 대한 애정과 창의성을 결합합니다.

검토자:
제프 프리츠
제프리 T. 프리츠
.NET 커뮤니티 팀의 수석 프로그램 관리자
제프는 .NET 및 Visual Studio 팀의 수석 프로그램 관리자이기도 합니다. 그는 .NET Conf 가상 컨퍼런스 시리즈의 총괄 프로듀서이며, 개발자를 위한 라이브 스트림 'Fritz and Friends'를 주 2회 진행하며 시청자들과 함께 기술에 대해 이야기하고 코드를 작성합니다. 제프는 Microsoft Build, Microsoft Ignite, .NET Conf, Microsoft MVP Summit 등 주요 Microsoft 개발자 행사를 위한 워크숍, 프레젠테이션 및 콘텐츠 기획을 담당합니다.
시작할 준비 되셨나요?
Nuget 다운로드 5,525,971 | 버전: 2026.3 방금 출시되었습니다
Still Scrolling Icon

아직도 스크롤하고 계신가요?

빠른 증거를 원하시나요? PM > Install-Package IronOcr
샘플을 실행하세요 이미지가 검색 가능한 텍스트로 바뀌는 것을 확인해 보세요.