在许多企业和组织中,存在海量的PDF文件,如财务报告、统计数据报表等。这些文件包含重要的信息,但传统的处理方式效率低下。例如,一个大型企业每年可能产生数以万计的财务报表PDF,人工提取表格数据并重命名文件非常耗时且易出错。

以下是基于 WPF(Windows Presentation Foundation)和飞桨开发图片文档多区域定点文字识别并导出至 Excel 的工具的详细步骤:

一、开发思路

  1. 使用 WPF 构建用户界面,方便用户选择图片文件、指定识别区域、触发文字识别操作以及导出结果至 Excel。
  2. 利用飞桨的 OCR 能力进行文字识别。
  3. 使用 EPPlus 库在 C# 中操作 Excel 文件。

二、环境搭建

  1. 安装所需工具和库
    • 确保已安装 Visual Studio,用于开发 WPF 应用程序。
    • 在 Visual Studio 中创建一个新的 WPF 项目。
    • 安装飞桨相关的库:飞桨在 C# 中的使用可以通过调用其 REST API 或使用飞桨的 JavaScript 库结合 C# 的 WebView2 控件来实现。这里我们将使用调用 REST API 的方式,需要确保你有一个运行飞桨 OCR 服务的服务器,或者使用飞桨官方提供的 OCR 服务。
    • 安装 EPPlus 库:在 Visual Studio 中,通过 NuGet 包管理器安装 EPPlus 库,用于操作 Excel 文件。

三、构建 WPF 界面

  1. 设计界面布局
    • 在 MainWindow.xaml 文件中设计界面,包括:
      • 一个 Button 用于选择图片文件。
      • 一个 Canvas 用于显示图片,并允许用户在上面绘制矩形区域来指定识别区域。
      • 一个 Button 用于触发文字识别操作。
      • 一个 Button 用于导出结果至 Excel。

以下是一个简单的 MainWindow.xaml 示例:

xml

<Window x:Class="ImageOCR.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Image OCR Tool" Height="450" Width="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
        <Button Content="Select Image" Click="SelectImageButton_Click" Grid.Row="0"/>
        <Canvas x:Name="ImageCanvas" Grid.Row="1" MouseLeftButtonDown="Canvas_MouseLeftButtonDown" MouseLeftButtonUp="Canvas_MouseLeftButtonUp" MouseMove="Canvas_MouseMove"/>
        <Button Content="Run OCR" Click="RunOCRButton_Click" Grid.Row="2"/>
        <Button Content="Export to Excel" Click="ExportToExcelButton_Click" Grid.Row="3"/>
    </Grid>
</Window>

四、实现后台逻辑

  1. 处理图片选择
    • 在 MainWindow.xaml.cs 文件中实现 SelectImageButton_Click 事件处理程序,使用 OpenFileDialog 选择图片文件并在 Canvas 上显示。

csharp

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Input;
using Microsoft.Win32;

namespace ImageOCR
{
    public partial class MainWindow : Window
    {
        private string imagePath;
        private BitmapImage imageSource;
        private Rectangle selectionRectangle;
        private Point startPoint;
        private Point endPoint;

        public MainWindow()
        {
            InitializeComponent();
        }

        private void SelectImageButton_Click(object sender, RoutedEventArgs e)
        {
            OpenFileDialog openFileDialog = new OpenFileDialog();
            openFileDialog.Filter = "Image files (*.png;*.jpg;*.jpeg)|*.png;*.jpg;*.jpeg|All files (*.*)|*.*";
            if (openFileDialog.ShowDialog() == true)
            {
                imagePath = openFileDialog.FileName;
                imageSource = new BitmapImage(new Uri(imagePath));
                ImageCanvas.Width = imageSource.Width;
                ImageCanvas.Height = imageSource.Height;
                Image image = new Image();
                image.Source = imageSource;
                ImageCanvas.Children.Add(image);
            }
        }
    }
}
  1. 用户绘制区域
    • 实现 Canvas_MouseLeftButtonDownCanvas_MouseLeftButtonUp 和 Canvas_MouseMove 事件处理程序,允许用户在 Canvas 上绘制矩形区域。

csharp

private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
    startPoint = e.GetPosition(ImageCanvas);
    selectionRectangle = new Rectangle
    {
        Stroke = System.Windows.Media.Brushes.Red,
        StrokeThickness = 2
    };
    ImageCanvas.Children.Add(selectionRectangle);
}

private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
    endPoint = e.GetPosition(ImageCanvas);
    double x = Math.Min(startPoint.X, endPoint.X);
    double y = Math.Min(startPoint.Y, endPoint.Y);
    double width = Math.Abs(endPoint.X - startPoint.X);
    double height = Math.Abs(endPoint.Y - startPoint.Y);
    Canvas.SetLeft(selectionRectangle, x);
    Canvas.SetTop(selectionRectangle, y);
    selectionRectangle.Width = width;
    selectionRectangle.Height = height;
}

private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
    if (e.LeftButton == MouseButtonState.Pressed && selectionRectangle!= null)
    {
        endPoint = e.GetPosition(ImageCanvas);
        double x = Math.Min(startPoint.X, endPoint.X);
        double y = Math.Min(startPoint.Y, endPoint.Y);
        double width = Math.Abs(endPoint.X - startPoint.X);
        double height = Math.Abs(endPoint.Y - startPoint.Y);
        Canvas.SetLeft(selectionRectangle, x);
        Canvas.SetTop(selectionRectangle, y);
        selectionRectangle.Width = width;
        selectionRectangle.Height = height;
    }
}

  1. 调用飞桨 OCR 服务
    • 实现 RunOCRButton_Click 事件处理程序,调用飞桨的 OCR 服务进行文字识别。这里假设你已经有一个运行飞桨 OCR 服务的 REST API 端点。

csharp

using System.Net.Http;
using System.Net.Http.Json;
using System.Collections.Generic;
using System.Threading.Tasks;

private async Task<List<string>> CallPaddleOCR(string imagePath, double left, double top, double width, double height)
{
    using (HttpClient client = new HttpClient())
    {
        var request = new
        {
            image = imagePath,
            region = new { left, top, width, height }
        };
        var response = await client.PostAsJsonAsync("http://your-paddle-ocr-api-endpoint", request);
        if (response.IsSuccessStatusCode)
        {
            var result = await response.Content.ReadFromJsonAsync<List<string>>();
            return result;
        }
        else
        {
            return new List<string>();
        }
    }
}

private async void RunOCRButton_Click(object sender, RoutedEventArgs e)
{
    if (imagePath == null || selectionRectangle == null) return;
    double left = Canvas.GetLeft(selectionRectangle);
    double top = Canvas.GetTop(selectionRectangle);
    double width = selectionRectangle.Width;
    double height = selectionRectangle.Height;
    var ocrResults = await CallPaddleOCR(imagePath, left, top, width, height);
    // 存储结果,可使用一个 List<string> 来存储多个区域的识别结果
}
  1. 导出至 Excel
    • 实现 ExportToExcelButton_Click 事件处理程序,使用 EPPlus 库将结果导出至 Excel 文件。

csharp

using OfficeOpenXml;
using System.IO;

private void ExportToExcelButton_Click(object sender, RoutedEventArgs e)
{
    // 假设 ocrResults 是存储识别结果的 List<string>
    var ocrResults = new List<string>(); 
    using (ExcelPackage excelPackage = new ExcelPackage())
    {
        var worksheet = excelPackage.Workbook.Worksheets.Add("OCR Results");
        for (int i = 0; i < ocrResults.Count; i++)
        {
            worksheet.Cells[i + 1, 1].Value = ocrResults[i];
        }
        using (FileStream fileStream = new FileStream("OCRResults.xlsx", FileMode.Create))
        {
            excelPackage.SaveAs(fileStream);
        }
    }
}

五、优化和扩展

  1. 错误处理:添加异常处理代码,如文件选择失败、OCR 服务调用失败、Excel 保存失败等。
  2. 多区域支持:存储多个用户绘制的区域,并对每个区域调用飞桨 OCR 服务进行识别。
  3. 区域管理:允许用户编辑、删除已绘制的区域。
  4. OCR 性能和准确性:根据需要调整飞桨的参数,提高 OCR 性能和准确性。

六、总结

  1. 通过上述步骤,我们创建了一个 WPF 应用程序,用户可以选择图片文件并在 Canvas 上绘制识别区域。
  2. 使用飞桨的 OCR 服务对指定区域进行文字识别。
  3. 使用 EPPlus 库将结果导出至 Excel 文件。

以下是代码的使用说明:

  1. 打开 Visual Studio,创建一个新的 WPF 项目。
  2. 在 MainWindow.xaml 中设计界面布局。
  3. 在 MainWindow.xaml.cs 中实现后台逻辑,包括图片选择、区域绘制、OCR 调用和 Excel 导出功能。
  4. 运行项目,选择图片文件,在 Canvas 上绘制区域,点击 "Run OCR" 按钮进行文字识别,最后点击 "Export to Excel" 按钮导出结果。

请注意,调用飞桨 OCR 服务时,需要将 "http://your-paddle-ocr-api-endpoint" 替换为实际的飞桨 OCR 服务 REST API 地址,并且确保该服务已正确部署和运行。

此方案结合了 WPF 的强大界面开发能力和飞桨的 OCR 技术,为用户提供了一个方便的工具,用于图片文档的多区域定点文字识别和结果导出。根据实际需求,可以对代码进行优化和扩展,以满足更复杂的应用场景。

更多推荐