C#利用PaddleOCRSharp实现表格文字识别及可视化对比

 更新时间:2026年02月26日 09:00:58   作者:河西石头  
PaddleOCR 是百度飞桨开源的 OCR 工具库,支持多语言文本识别,尤其在中文字符识别上表现优异,在 C# 开发中,我们可以通过 PaddleOCRSharp 封装库快速集成 OCR 功能,本文将通过一个 WinForms 示例,演示如何实现图片和 PDF 中的表格文字识别,需要的朋友可以参考下

引言

PaddleOCR 是百度飞桨开源的 OCR 工具库,支持多语言文本识别,尤其在中文字符识别上表现优异。在 C# 开发中,我们可以通过 PaddleOCRSharp 封装库快速集成 OCR 功能。本文将通过一个 WinForms 示例,演示如何实现图片和 PDF 中的表格文字识别,并在窗体中显示三图对比(原图、检测框图、识别结果图),帮助开发者直观验证 OCR 效果。

开发环境

  • Visual Studio 2022(任意版本)
  • .NET Framework 4.8(或 .NET 6/8,本文以 .NET Framework 4.8 为例)
  • NuGet 包版本(详见下文)

第一部分:环境准备和 NuGet 配置

1.1 创建项目

打开 Visual Studio 2022,创建一个新的 Windows Forms 应用(选择 .NET Framework 4.8 或更高版本)。

1.2 安装 NuGet 包

在“管理 NuGet 程序包”中搜索并安装以下指定版本的包(版本号已实际测试通过):

包名版本说明
PaddleOCRSharp6.1.0PaddleOCR 的 C# 封装,提供 OCR 识别引擎
OpenCvSharp4.Windows4.13.0.20260222OpenCV 的 C# 封装,用于图像绘制和处理
OpenCvSharp4.Extensions4.13.0.20260222OpenCV 扩展方法,便于 Bitmap 与 Mat 互转
OpenCvSharp4.Runtime.win4.13.0.20260222OpenCV 运行时依赖(通常由 Windows 包自动引入)
Paddle.Runtime.win_x643.3.0.2Paddle Inference 运行时(PaddleOCRSharp 依赖)
(可选) DevExpress.Win.Design24.2.5用于美化界面,本文使用普通 WinForms 控件,非必须

注意:请确保项目目标平台为 x64,因为 Paddle 运行时仅支持 64 位。在项目属性 -> 生成 -> 目标平台中选择 x64。

1.3 引入命名空间

在代码文件顶部添加以下 using 指令:

using PaddleOCRSharp;
using OpenCvSharp;
using OpenCvSharp.Extensions;
using System.Drawing;
using System.IO;
using System.Windows.Forms;
using System; // 可能还需要其他基础命名空间

第二部分:实现文字识别并在文本框输出

2.1 初始化 OCR 引擎

PaddleOCRSharp 提供了 PaddleOCREngine 类,可配置模型路径和识别参数。通常使用默认配置即可。

private PaddleOCREngine engine;

// 在窗体构造函数或需要时初始化
public Form1()
{
    InitializeComponent();
    OCRModelConfig config = null;
    OCRParameter param = new OCRParameter();
    engine = new PaddleOCREngine(config, param);
}

2.2 识别图片中的文字

通过 OpenFileDialog 选择图片,调用 DetectText 方法获取识别结果,并将文本显示在 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));

    // 执行识别
    OCRResult result = engine.DetectText(bitmap);
    if (result != null)
    {
        textBox1.Text = result.Text; // 输出纯文本
    }
}

2.3 识别 PDF 文档中的文字

PDF 识别使用 DetectTextPDF 方法,需要传入 PDF 字节数组和分辨率(通常 150 或 200)。该方法支持分页回调,便于显示进度。

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);
    
    // 设置回调显示处理进度
    Action<int> progress = page => Console.WriteLine($"正在处理第 {page} 页");
    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 对象除了包含整体文本外,还包含了每个文本块的详细信息(如位置坐标、置信度等),这些信息将在第三部分用于绘制检测框。

第三部分:实现三图对比显示

为了直观验证 OCR 效果,我们希望在识别后弹出一个新窗体,展示三幅并排的图像:

  • 原图:原始输入图像。
  • 检测框图:在原图上绘制浅蓝色检测框(BGR = 255,255,0),不显示文字。
  • 识别结果图:纯白色背景,绘制浅蓝色检测框,并用黑色文字居中显示识别结果(解决中文显示问题)。

由于 OpenCvSharp 的 PutText 不支持中文,我们需要借助 System.Drawing 绘制中文,再将结果转回 OpenCV 的 Mat 进行拼接。

3.1 创建对比窗体 Form2

在项目中添加一个新窗体 Form2,放置一个 PictureBox 控件(命名为 pictureBox1),并将 SizeMode 设置为 AutoSize,同时启用窗体的 AutoScroll 属性以支持滚动查看大图。

3.2 编写绘图方法

核心函数 DrawThreeImages 接收原始图像和 OCR 结果,返回拼接后的 Bitmap。

private Bitmap DrawThreeImages(Bitmap original, OCRResult ocrResult)
{
    // 1. 将原图转为 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); // 浅蓝色

    // 获取文本块列表(根据实际属性名调整,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 转为 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;

                // 计算文本框的边界矩形
                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;

                // 根据框高度动态设置字体大小(约0.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 转回 Mat
        textMat = BitmapConverter.ToMat(textBmp);
        textBmp.Dispose();
    }

    // 4. 水平拼接三张图
    Mat[] mats = { originalMat, boxesMat, textMat };
    Mat resultMat = new Mat();
    Cv2.HConcat(mats, resultMat);

    // 5. 转换为 Bitmap
    Bitmap resultBitmap = BitmapConverter.ToBitmap(resultMat);

    // 6. 释放资源
    originalMat.Dispose();
    boxesMat.Dispose();
    textMat.Dispose();
    resultMat.Dispose();

    return resultBitmap;
}

3.3 在识别后显示对比窗体

修改图片识别按钮的点击事件,识别完成后调用上述方法,并显示 Form2。

private void btnImageOCR_Click(object sender, EventArgs e)
{
    // ... 前面的识别代码 ...
    if (ocrResult != null)
    {
        textBox1.Text = ocrResult.Text;

        // 生成三图对比
        Bitmap merged = DrawThreeImages(bitmap, ocrResult);

        // 显示新窗体
        Form2 form2 = new Form2();
        form2.pictureBox1.Image = merged;
        form2.Show();
    }
}

3.4 效果预览

运行程序,选择一张包含表格的图片,识别后弹出 Form2,可以看到:

  • 左侧原图;
  • 中间原图叠加浅蓝色检测框;
  • 右侧纯白背景,检测框内居中显示黑色文字(中文正确显示)。

总结

通过 PaddleOCRSharpOpenCvSharp,我们能够在 C# 中轻松集成 PaddleOCR 的高效文字识别能力。本文不仅实现了基础的文本提取,还通过三图对比功能直观展示了检测和识别效果,尤其解决了中文显示问题。这种可视化方式对于调试 OCR 参数、验证识别准确率非常有帮助。

未来可根据需求扩展:如识别表格结构、输出结构化数据等。希望本文能为你的 C# OCR 开发提供参考。

注意事项

  • 务必使用 x64 平台编译。
  • 若中文显示仍有问题,检查系统是否安装 Microsoft YaHei 字体,或更换为其他中文字体(如“SimSun”)。

以上就是C#利用PaddleOCRSharp实现表格文字识别及可视化对比的详细内容,更多关于C# PaddleOCRSharp表格文字识别及对比的资料请关注脚本之家其它相关文章!

相关文章

  • 绑定winform中DataGrid

    绑定winform中DataGrid

    绑定winform中DataGrid,需要的朋友可以参考一下
    2013-02-02
  • C#读取二进制文件方法分析

    C#读取二进制文件方法分析

    这篇文章主要介绍了C#读取二进制文件方法,较为详细的分析了C#读取二进制文件的原理与注意事项,具有一定参考借鉴价值,需要的朋友可以参考下
    2015-01-01
  • C# Winfom 中ListBox的简单用法详解

    C# Winfom 中ListBox的简单用法详解

    这篇文章主要介绍了C# Winfom 中ListBox的简单用法详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 使用C#实现Excel与ODS之间的互相转换

    使用C#实现Excel与ODS之间的互相转换

    Excel 由微软开发,是一款被广泛使用的电子表格应用程序,提供了丰富的数据分析、可视化和管理功能,ODS是一种开放标准的电子表格格式,这意味着它可以被多种软件应用程序读取和编辑,本文将介绍如何在C#中实现Excel与ODS之间的相互转换
    2025-12-12
  • Unity的IPostBuildPlayerScriptDLLs实用案例深入解析

    Unity的IPostBuildPlayerScriptDLLs实用案例深入解析

    这篇文章主要为大家介绍了Unity的IPostBuildPlayerScriptDLLs实用案例深入解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-05-05
  • C#中实现左侧折叠导航菜单的示例代码

    C#中实现左侧折叠导航菜单的示例代码

    本文详细介绍了基于C#实现左侧折叠导航菜单的技术方案,涵盖WinForms和WPF框架,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2026-01-01
  • C#实现将PDF转为线性化PDF

    C#实现将PDF转为线性化PDF

    线性化PDF文件是PDF文件的一种特殊格式,可以通过Internet更快地进行查看。这篇文章主要介绍了如何通过C#实现将PDF转为线性化PDF,感兴趣的小伙伴可以学习一下
    2021-12-12
  • C#使用CefSharp实现内嵌网页详解

    C#使用CefSharp实现内嵌网页详解

    这篇文章主要介绍了C# WPF里怎么使用CefSharp嵌入一个网页,并给出一个简单示例演示C#和网页(JS)的交互实现,感兴趣的小伙伴可以了解一下
    2023-04-04
  • 如何用WindowsForm给窗口添加一些简单的动画效果

    如何用WindowsForm给窗口添加一些简单的动画效果

    这篇文章主要介绍了如何用WindowsForm给窗口添加一些简单的动画效果,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
    2020-07-07
  • C# 运用params修饰符来实现变长参数传递的方法

    C# 运用params修饰符来实现变长参数传递的方法

    一般来说,参数个数都是固定的,定义为集群类型的参数可以实现可变数目参数的目的,但是.NET提供了更灵活的机制来实现可变数目参数,这就是使用params修饰符
    2013-09-09

最新评论