如何使用 C# 進行表格 OCR辨識:從文件擷取圖片文字與資料
IronOCR使 C# 開發人員能夠使用高級機器學習模型透過 OCR辨識從 PDF 和圖像中的表格擷取圖片文字與數據,使用 ReadDocumentAdvanced 方法處理具有基本單元格的簡單表格和具有合併單元格的複雜結構(如發票)。
使用純 Tesseract 從表格中提取資料可能具有挑戰性,因為文字通常位於單元格中,並且稀疏地分散在整個文件中。 但是,我們的庫中包含一個經過訓練和微調的機器學習模型,可以準確地偵測和提取表格資料。 無論是處理財務報告、庫存清單或發票數據, IronOCR都能提供高效解析結構化資料的工具。
對於簡單的表格,可以使用標準的OcrInput 類別進行直接的表格檢測。 對於更複雜的結構,我們獨特的 ReadDocumentAdvanced 方法可提供強大的結果,有效地解析表格並提供資料。 這種先進的方法利用機器學習來理解表格佈局、合併單元格和複雜的格式,而傳統的 OCR 技術往往難以處理這些情況。
快速入門:一次呼叫提取複雜表格單元格
幾分鐘即可上手使用-此範例展示如何使用 ReadDocumentAdvanced 進行一次IronOCR調用,從複雜文件中取得詳細的表格儲存格資料。
它透過載入 PDF、應用進階表格檢測並直接返回儲存格資訊清單來展示易用性。
以下步驟引導您開始使用IronOCR讀取表格:
最簡工作流程(5個步驟)
- 下載一個 C# 庫,用於從表中提取資料。
- 準備好要擷取的影像和PDF文件。
- 將`ReadDataTables`屬性設為 true 以啟用表檢測
- 對於複雜表,請使用`ReadDocumentAdvanced`方法。
- 提取透過這些方法檢測到的數據
如何從簡單表格中提取資料?
將 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
如何解讀複雜的發票表格?
在商業環境中,發票是比較常見的複雜表格之一。 發票是複雜的表格,包含行和列數據,通常具有合併儲存格、不同的列寬和巢狀結構。 使用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
此方法將文件中的文字資料分為兩類:一類有邊框,另一類沒有邊框。 對於有邊框的內容,圖書館會根據表格的結構進一步細分為小節。 此方法擅長處理以下情況:
- 發票明細項目描述各不相同
- 多列價格明細
- 收貨地址和帳單地址欄
- 稅金和總額計算部分
- 頁首和頁尾訊息
結果如下圖所示。 由於此方法側重於邊界內的信息,因此任何跨越多行的合併單元格都將被視為單一單元格。
提取出來的資料是什麼樣的?
如何組織和處理提取的表格單元格?
在目前實作中,提取的單元格尚未正確組織。 但是,每個單元格都包含有價值的信息,例如 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
表格提取最佳實踐
在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 方法專門用於處理複雜的文件,例如發票和財務報告。它使用經過訓練的機器學習模型,從具有合併單元格和複雜格式的表格中檢測並擷取資料。

