C#利用PaddleOCRSharp實(shí)現(xiàn)表格文字識(shí)別及可視化對(duì)比
引言
PaddleOCR 是百度飛槳開(kāi)源的 OCR 工具庫(kù),支持多語(yǔ)言文本識(shí)別,尤其在中文字符識(shí)別上表現(xiàn)優(yōu)異。在 C# 開(kāi)發(fā)中,我們可以通過(guò) PaddleOCRSharp 封裝庫(kù)快速集成 OCR 功能。本文將通過(guò)一個(gè) WinForms 示例,演示如何實(shí)現(xiàn)圖片和 PDF 中的表格文字識(shí)別,并在窗體中顯示三圖對(duì)比(原圖、檢測(cè)框圖、識(shí)別結(jié)果圖),幫助開(kāi)發(fā)者直觀驗(yàn)證 OCR 效果。
開(kāi)發(fā)環(huán)境:
- Visual Studio 2022(任意版本)
- .NET Framework 4.8(或 .NET 6/8,本文以 .NET Framework 4.8 為例)
- NuGet 包版本(詳見(jiàn)下文)
第一部分:環(huán)境準(zhǔn)備和 NuGet 配置
1.1 創(chuàng)建項(xiàng)目
打開(kāi) Visual Studio 2022,創(chuàng)建一個(gè)新的 Windows Forms 應(yīng)用(選擇 .NET Framework 4.8 或更高版本)。
1.2 安裝 NuGet 包
在“管理 NuGet 程序包”中搜索并安裝以下指定版本的包(版本號(hào)已實(shí)際測(cè)試通過(guò)):
| 包名 | 版本 | 說(shuō)明 |
|---|---|---|
| PaddleOCRSharp | 6.1.0 | PaddleOCR 的 C# 封裝,提供 OCR 識(shí)別引擎 |
| OpenCvSharp4.Windows | 4.13.0.20260222 | OpenCV 的 C# 封裝,用于圖像繪制和處理 |
| OpenCvSharp4.Extensions | 4.13.0.20260222 | OpenCV 擴(kuò)展方法,便于 Bitmap 與 Mat 互轉(zhuǎn) |
| OpenCvSharp4.Runtime.win | 4.13.0.20260222 | OpenCV 運(yùn)行時(shí)依賴(通常由 Windows 包自動(dòng)引入) |
| Paddle.Runtime.win_x64 | 3.3.0.2 | Paddle Inference 運(yùn)行時(shí)(PaddleOCRSharp 依賴) |
| (可選) DevExpress.Win.Design | 24.2.5 | 用于美化界面,本文使用普通 WinForms 控件,非必須 |
注意:請(qǐng)確保項(xiàng)目目標(biāo)平臺(tái)為 x64,因?yàn)?Paddle 運(yùn)行時(shí)僅支持 64 位。在項(xiàng)目屬性 -> 生成 -> 目標(biāo)平臺(tái)中選擇 x64。
1.3 引入命名空間
在代碼文件頂部添加以下 using 指令:
using PaddleOCRSharp; using OpenCvSharp; using OpenCvSharp.Extensions; using System.Drawing; using System.IO; using System.Windows.Forms; using System; // 可能還需要其他基礎(chǔ)命名空間
第二部分:實(shí)現(xiàn)文字識(shí)別并在文本框輸出
2.1 初始化 OCR 引擎
PaddleOCRSharp 提供了 PaddleOCREngine 類,可配置模型路徑和識(shí)別參數(shù)。通常使用默認(rèn)配置即可。
private PaddleOCREngine engine;
// 在窗體構(gòu)造函數(shù)或需要時(shí)初始化
public Form1()
{
InitializeComponent();
OCRModelConfig config = null;
OCRParameter param = new OCRParameter();
engine = new PaddleOCREngine(config, param);
}
2.2 識(shí)別圖片中的文字
通過(guò) OpenFileDialog 選擇圖片,調(diào)用 DetectText 方法獲取識(shí)別結(jié)果,并將文本顯示在 TextBox 中。
private void btnImageOCR_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "圖像文件|*.bmp;*.jpg;*.jpeg;*.png;*.tiff";
if (ofd.ShowDialog() != DialogResult.OK) return;
byte[] imageBytes = File.ReadAllBytes(ofd.FileName);
Bitmap bitmap = new Bitmap(new MemoryStream(imageBytes));
// 執(zhí)行識(shí)別
OCRResult result = engine.DetectText(bitmap);
if (result != null)
{
textBox1.Text = result.Text; // 輸出純文本
}
}


2.3 識(shí)別 PDF 文檔中的文字
PDF 識(shí)別使用 DetectTextPDF 方法,需要傳入 PDF 字節(jié)數(shù)組和分辨率(通常 150 或 200)。該方法支持分頁(yè)回調(diào),便于顯示進(jìn)度。
private void btnPDFOCR_Click(object sender, EventArgs e)
{
OpenFileDialog ofd = new OpenFileDialog();
ofd.Filter = "PDF文件|*.pdf";
if (ofd.ShowDialog() != DialogResult.OK) return;
byte[] pdfBytes = File.ReadAllBytes(ofd.FileName);
// 設(shè)置回調(diào)顯示處理進(jìn)度
Action<int> progress = page => Console.WriteLine($"正在處理第 {page} 頁(yè)");
var result = engine.DetectTextPDF(pdfBytes, 150, progress);
StringBuilder sb = new StringBuilder();
foreach (var page in result.Pages)
{
sb.AppendLine(page.Text);
}
textBox1.Text = sb.ToString();
}
注意:OCRResult 對(duì)象除了包含整體文本外,還包含了每個(gè)文本塊的詳細(xì)信息(如位置坐標(biāo)、置信度等),這些信息將在第三部分用于繪制檢測(cè)框。
第三部分:實(shí)現(xiàn)三圖對(duì)比顯示
為了直觀驗(yàn)證 OCR 效果,我們希望在識(shí)別后彈出一個(gè)新窗體,展示三幅并排的圖像:
- 原圖:原始輸入圖像。
- 檢測(cè)框圖:在原圖上繪制淺藍(lán)色檢測(cè)框(BGR = 255,255,0),不顯示文字。
- 識(shí)別結(jié)果圖:純白色背景,繪制淺藍(lán)色檢測(cè)框,并用黑色文字居中顯示識(shí)別結(jié)果(解決中文顯示問(wèn)題)。
由于 OpenCvSharp 的 PutText 不支持中文,我們需要借助 System.Drawing 繪制中文,再將結(jié)果轉(zhuǎn)回 OpenCV 的 Mat 進(jìn)行拼接。
3.1 創(chuàng)建對(duì)比窗體 Form2
在項(xiàng)目中添加一個(gè)新窗體 Form2,放置一個(gè) PictureBox 控件(命名為 pictureBox1),并將 SizeMode 設(shè)置為 AutoSize,同時(shí)啟用窗體的 AutoScroll 屬性以支持滾動(dòng)查看大圖。
3.2 編寫(xiě)繪圖方法
核心函數(shù) DrawThreeImages 接收原始圖像和 OCR 結(jié)果,返回拼接后的 Bitmap。
private Bitmap DrawThreeImages(Bitmap original, OCRResult ocrResult)
{
// 1. 將原圖轉(zhuǎn)為 Mat,確保為 3 通道彩色
Mat originalMat = BitmapConverter.ToMat(original);
if (originalMat.Channels() == 1)
Cv2.CvtColor(originalMat, originalMat, ColorConversionCodes.GRAY2BGR);
else if (originalMat.Channels() == 4)
Cv2.CvtColor(originalMat, originalMat, ColorConversionCodes.BGRA2BGR);
// 2. 第二張圖:原圖克隆,僅繪制框
Mat boxesMat = originalMat.Clone();
// 3. 第三張圖:純白色背景
Mat textMat = new Mat(originalMat.Size(), originalMat.Type(), Scalar.White);
// 定義顏色(BGR順序)
Scalar lightBlue = new Scalar(255, 255, 0); // 淺藍(lán)色
// 獲取文本塊列表(根據(jù)實(shí)際屬性名調(diào)整,PaddleOCRSharp 中為 TextBlocks)
var blocks = ocrResult.TextBlocks;
if (blocks != null)
{
// 3.1 先用 OpenCV 繪制框到 boxesMat 和 textMat
foreach (var block in blocks)
{
var points = block.BoxPoints; // 通常為 List<PointF> 或 PointF[]
if (points == null || points.Count < 4) continue;
Point[] pts = new Point[4];
for (int i = 0; i < 4; i++)
pts[i] = new Point((int)points[i].X, (int)points[i].Y);
Cv2.Polylines(boxesMat, new[] { pts }, true, lightBlue, 2);
Cv2.Polylines(textMat, new[] { pts }, true, lightBlue, 2);
}
// 3.2 將 textMat 轉(zhuǎn)為 Bitmap,用 System.Drawing 繪制中文文字
Bitmap textBmp = BitmapConverter.ToBitmap(textMat);
textMat.Dispose();
using (Graphics g = Graphics.FromImage(textBmp))
{
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
foreach (var block in blocks)
{
var points = block.BoxPoints;
if (points == null || points.Count < 4) continue;
string text = block.Text;
if (string.IsNullOrEmpty(text)) continue;
// 計(jì)算文本框的邊界矩形
float minX = points.Min(p => p.X);
float maxX = points.Max(p => p.X);
float minY = points.Min(p => p.Y);
float maxY = points.Max(p => p.Y);
float width = maxX - minX;
float height = maxY - minY;
if (width <= 0 || height <= 0) continue;
// 根據(jù)框高度動(dòng)態(tài)設(shè)置字體大?。s0.4倍)
float fontSize = height * 0.4f;
fontSize = Math.Max(8, Math.Min(48, fontSize));
using (Font font = new Font("Microsoft YaHei", fontSize, FontStyle.Regular, GraphicsUnit.Pixel))
using (Brush brush = new SolidBrush(Color.Black))
using (StringFormat sf = new StringFormat())
{
sf.Alignment = StringAlignment.Center;
sf.LineAlignment = StringAlignment.Center;
float centerX = (minX + maxX) / 2;
float centerY = (minY + maxY) / 2;
g.DrawString(text, font, brush, centerX, centerY, sf);
}
}
}
// 將繪制好的 Bitmap 轉(zhuǎn)回 Mat
textMat = BitmapConverter.ToMat(textBmp);
textBmp.Dispose();
}
// 4. 水平拼接三張圖
Mat[] mats = { originalMat, boxesMat, textMat };
Mat resultMat = new Mat();
Cv2.HConcat(mats, resultMat);
// 5. 轉(zhuǎn)換為 Bitmap
Bitmap resultBitmap = BitmapConverter.ToBitmap(resultMat);
// 6. 釋放資源
originalMat.Dispose();
boxesMat.Dispose();
textMat.Dispose();
resultMat.Dispose();
return resultBitmap;
}
3.3 在識(shí)別后顯示對(duì)比窗體
修改圖片識(shí)別按鈕的點(diǎn)擊事件,識(shí)別完成后調(diào)用上述方法,并顯示 Form2。
private void btnImageOCR_Click(object sender, EventArgs e)
{
// ... 前面的識(shí)別代碼 ...
if (ocrResult != null)
{
textBox1.Text = ocrResult.Text;
// 生成三圖對(duì)比
Bitmap merged = DrawThreeImages(bitmap, ocrResult);
// 顯示新窗體
Form2 form2 = new Form2();
form2.pictureBox1.Image = merged;
form2.Show();
}
}
3.4 效果預(yù)覽
運(yùn)行程序,選擇一張包含表格的圖片,識(shí)別后彈出 Form2,可以看到:
- 左側(cè)原圖;
- 中間原圖疊加淺藍(lán)色檢測(cè)框;
- 右側(cè)純白背景,檢測(cè)框內(nèi)居中顯示黑色文字(中文正確顯示)。

總結(jié)
通過(guò) PaddleOCRSharp 和 OpenCvSharp,我們能夠在 C# 中輕松集成 PaddleOCR 的高效文字識(shí)別能力。本文不僅實(shí)現(xiàn)了基礎(chǔ)的文本提取,還通過(guò)三圖對(duì)比功能直觀展示了檢測(cè)和識(shí)別效果,尤其解決了中文顯示問(wèn)題。這種可視化方式對(duì)于調(diào)試 OCR 參數(shù)、驗(yàn)證識(shí)別準(zhǔn)確率非常有幫助。
未來(lái)可根據(jù)需求擴(kuò)展:如識(shí)別表格結(jié)構(gòu)、輸出結(jié)構(gòu)化數(shù)據(jù)等。希望本文能為你的 C# OCR 開(kāi)發(fā)提供參考。
注意事項(xiàng):
- 務(wù)必使用 x64 平臺(tái)編譯。
- 若中文顯示仍有問(wèn)題,檢查系統(tǒng)是否安裝 Microsoft YaHei 字體,或更換為其他中文字體(如“SimSun”)。
以上就是C#利用PaddleOCRSharp實(shí)現(xiàn)表格文字識(shí)別及可視化對(duì)比的詳細(xì)內(nèi)容,更多關(guān)于C# PaddleOCRSharp表格文字識(shí)別及對(duì)比的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
C#基于Socket的TCP通信實(shí)現(xiàn)聊天室案例
這篇文章主要為大家詳細(xì)介紹了C#基于Socket的TCP通信實(shí)現(xiàn)聊天室案例,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-02-02
C#中將DataTable轉(zhuǎn)化成List<T>的方法解析
大家應(yīng)該都知道在.net項(xiàng)目中使用到DataTable和List<T>集合的地方較多,有的時(shí)候需要將DataTable轉(zhuǎn)化成List<T>,那么改如何轉(zhuǎn)化呢?下面通過(guò)這篇文章來(lái)一起學(xué)習(xí)下吧,本文中給出了詳細(xì)的示例代碼,相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值。2016-12-12
C#實(shí)現(xiàn)在購(gòu)物車(chē)系統(tǒng)中生成不重復(fù)訂單號(hào)的方法
這篇文章主要介紹了C#實(shí)現(xiàn)在購(gòu)物車(chē)系統(tǒng)中生成不重復(fù)訂單號(hào)的方法,涉及C#中時(shí)間與字符串操作的相關(guān)技巧,非常簡(jiǎn)單實(shí)用,需要的朋友可以參考下2015-05-05

