如何使用 C# 進行表格 OCR辨識:從文件擷取圖片文字與資料

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

IronOCR使 C# 開發人員能夠使用高級機器學習模型透過 OCR辨識從 PDF 和圖像中的表格擷取圖片文字與數據,使用 ReadDocumentAdvanced 方法處理具有基本單元格的簡單表格和具有合併單元格的複雜結構(如發票)。

使用純 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();
}
Imports Microsoft.VisualBasic
Imports IronOcr
Imports System
Imports System.Data

' Instantiate OCR engine
Private ocr = New IronTesseract()

' Enable table detection
ocr.Configuration.ReadDataTables = True

Dim input = New OcrPdfInput("simple-table.pdf")
Dim result = ocr.Read(input)

' Retrieve the data
Dim table = result.Tables(0).DataTable

' Print out the table data
For Each row As DataRow In table.Rows
	For Each item In row.ItemArray
		Console.Write(item & vbTab)
	Next item
	Console.WriteLine()
Next row
$vbLabelText   $csharpLabel

如何解讀複雜的發票表格?

在商業環境中,發票是比較常見的複雜表格之一。 發票是複雜的表格,包含行和列數據,通常具有合併儲存格、不同的列寬和巢狀結構。 使用IronOCR,我們利用 ReadDocumentAdvanced 方法有效地處理它們。 該過程包括掃描文件、識別表格結構和提取資料。 在這個例子中,我們使用" invoiceTable.pdf "文件來展示IronOCR如何從發票中檢索所有資訊。

ReadDocumentAdvanced 方法需要將IronOcr.Extensions.AdvancedScan軟體包與基礎IronOCR軟體包一起安裝。 此擴充功能提供專門針對複雜文件佈局訓練的高級機器學習功能。

請注意
在.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;
Imports IronOcr
Imports System.Linq

' Instantiate OCR engine
Dim ocr = New IronTesseract()

Using input As New OcrInput()
    input.LoadPdf("invoiceTable.pdf")

    ' Perform OCR
    Dim result = ocr.ReadDocumentAdvanced(input)

    Dim cellList = result.Tables.First().CellInfos
End Using
$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];
    }
}
Imports Microsoft.VisualBasic
Imports System
Imports System.Collections.Generic
Imports System.Linq

' A helper class to process table data by sorting cells based on coordinates
Public Module TableProcessor
	' Method to organize cells by their coordinates (Y top to bottom, X left to right)
	Public Function OrganizeCellsByCoordinates(ByVal cells As List(Of CellInfo)) As List(Of CellInfo)
		' Sort cells by Y (top to bottom), then by X (left to right)
		Dim sortedCells = cells.OrderBy(Function(cell) cell.CellRect.Y).ThenBy(Function(cell) cell.CellRect.X).ToList()

		Return sortedCells
	End Function

	' Example method demonstrating how to process multiple tables
	Public Sub ProcessTables(ByVal tables As Tables)
		For Each table In tables
			Dim sortedCells = OrganizeCellsByCoordinates(table.CellInfos)

			Console.WriteLine("Organized Table Cells:")

			' Initialize previous Y coordinate
			Dim previousY As Integer = If(sortedCells.Any(), sortedCells.First().CellRect.Y, 0)

			For Each 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 Then
					Console.WriteLine() ' Start a new row
					previousY = cell.CellRect.Y
				End If

				' Print the cell text followed by a tab
				Console.Write($"{cell.CellText}" & vbTab)
			Next cell

			Console.WriteLine(vbLf & "--- End of Table ---") ' End of a table
		Next table
	End Sub

	' Method to extract a specific row by the given index
	Public Function ExtractRowByIndex(ByVal table As TableInfo, ByVal rowIndex As Integer) As List(Of CellInfo)
		If table Is Nothing OrElse table.CellInfos Is Nothing OrElse Not table.CellInfos.Any() Then
			Throw New ArgumentException("Table is empty or invalid.")
		End If

		Dim sortedCells = OrganizeCellsByCoordinates(table.CellInfos)
		Dim rows As New List(Of List(Of CellInfo))()

		' Group cells into rows based on Y coordinates
		Dim previousY As Integer = sortedCells.First().CellRect.Y
		Dim currentRow As New List(Of CellInfo)()

		For Each cell In sortedCells
			If Math.Abs(cell.CellRect.Y - previousY) > cell.CellRect.Height * 0.8 Then
				' Store the completed row and start a new one
				rows.Add(New List(Of CellInfo)(currentRow))
				currentRow.Clear()

				previousY = cell.CellRect.Y
			End If

			currentRow.Add(cell)
		Next cell

		' Add the last row if it wasn't added yet
		If currentRow.Any() Then
			rows.Add(currentRow)
		End If

		' Retrieve the specified row
		If rowIndex < 0 OrElse rowIndex >= rows.Count Then
			Throw New IndexOutOfRangeException($"Row index {rowIndex} is out of range.")
		End If

		Return rows(rowIndex)
	End Function
End Module
$vbLabelText   $csharpLabel

表格提取最佳實踐

在IronOCR中進行表格提取時,請遵循以下最佳實踐:

1.文檔品質:解析度越高的文檔,效果越好。 掃描文件解析度至少應為 300 DPI。

2.預處理:對於品質較差或表格傾斜的文檔,請考慮在處理前使用 IronOCR 的影像校正功能。

3.效能:對於包含多個表格的大型文檔,請考慮使用多線程和非同步支援來並行處理頁面。

4.輸出選項:擷取表格資料後,您可以將結果匯出為各種格式。 了解更多資料輸出選項以及如何從處理後的文件建立可搜尋的 PDF

5.流程處理:對於 Web 應用程式或處理記憶體文件的場景,請考慮使用OCR 處理 PDF 流,以避免檔案系統操作。

概括

IronOCR透過基於 Tesseract 的標準檢測和先進的機器學習方法,提供強大的表格提取功能。 標準方法適用於簡單的表格,而 ReadDocumentAdvanced 方法則擅長處理發票等複雜文件。 借助提供的輔助方法,您可以組織和處理提取的數據,以滿足您的特定需求。

探索更多IronOCR功能,以增強您的文件處理工作流程,並在您的.NET應用程式中充分發揮光學字元辨識的潛力。

常見問題解答

如何使用 C# 從 PDF 和影像中萃取表格資料?

IronOCR 可讓 C# 開發人員使用先進的機器學習模型從 PDF 和影像中萃取表格資料。對於簡單的表格,請使用 OcrInput 類,並將 ReadDataTables 屬性設定為 true。對於具有合併單元格的複雜表格,請使用 ReadDocumentAdvanced 方法,以獲得更精確的結果。

簡單與複雜的表格抽取有何差異?

IronOCR 中的簡單表格擷取使用 Tesseract 的 ReadDataTables 屬性,對於具有明確儲存格邊界的基本表格效果良好。複雜的表格擷取需要使用 ReadDocumentAdvanced 方法,該方法使用機器學習來處理合併的儲存格、發票和複雜格式。

如何從複雜的表格中快速抽取資料?

在單次呼叫中使用 IronOCR 的 ReadDocumentAdvanced 方法: var cells = new IronTesseract().ReadDocumentAdvanced(new IronOcrInput().LoadPdf('invoiceTable.pdf')).Tables.First().CellInfos; 這可利用機器學習來理解表格佈局和複雜格式。

哪些類型的文件最適合使用簡單的表格檢測?

IronOCR 簡單的表格偵測方法特別適用於電子表格匯出、具有一致行列結構的基本資料表格、具有表格資料的報告,以及沒有合併單元格的簡單庫存清單。

如何啟用基本表格的表格偵測?

若要在 IronOCR 中啟用基本表格的表格偵測,請將 ReadDataTables 屬性設定為 true。這會使用 Tesseract 的表格偵測功能,對於單元格邊界清楚且沒有合併單元格的表格效果很好。

圖書館能否處理複雜佈局的發票和財務報告?

是的,IronOCR 的 ReadDocumentAdvanced 方法專門用於處理複雜的文件,例如發票和財務報告。它使用經過訓練的機器學習模型,從具有合併單元格和複雜格式的表格中檢測並擷取資料。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

審核人
Jeff Fritz
Jeffrey T. Fritz
首席程序经理 - .NET 社群团队
Jeff 也是 .NET 和 Visual Studio 团队的首席程序经理。他是 .NET Conf 虚拟会议系列的执行制作人,并主持“Fritz 和朋友”这一每周两次的開發者的直播节目,在节目上讨论技術并与观众一起编写代碼。Jeff 撰写研讨会、主持演讲,并计划大型 Microsoft 開發者活動(包括 Microsoft Build、Microsoft Ignite、.NET Conf 和 Microsoft MVP Summit)的內容。
準備好開始了嗎?
Nuget 下載 5,570,591 | 版本: 2026.4 剛剛發布
Still Scrolling Icon

還在捲動嗎?

想要快速證明? PM > Install-Package IronOcr
執行範例 觀看您的圖片變成可搜尋的文字。