C#调用百度OCR实战:从API接入到截图识别工具开发全指南

1次阅读
没有评论

共计 3657 个字符,预计需要花费 10 分钟才能阅读完成。

image.webp

背景痛点分析

工作中经常遇到需要从图片中提取文字的场景,比如截图识别、证件信息采集等。传统手动录入效率低下,而接入 OCR 技术时往往会遇到几个头疼的问题:

C# 调用百度 OCR 实战:从 API 接入到截图识别工具开发全指南

  • 鉴权流程复杂:百度 OCR 的 AccessToken 需要定期刷新,新手容易忽略过期机制
  • 图像格式限制:原始 API 只支持特定格式(如 JPG/PNG),实际业务中常遇到 BMP 等格式
  • 并发瓶颈:免费版 QPS 限制为 2,稍不注意就会触发限流

技术方案选型

对比主流 OCR 方案,我们选择了百度 OCR 是因为:

  • 准确率高:特别是对中文印刷体识别率可达 98% 以上
  • 接口丰富:支持身份证、银行卡等特殊场景的结构化识别
  • 开发友好:提供标准的 RESTful 接口

与开源的 Tesseract 对比:

特性 百度 OCR Tesseract
中文识别精度 ★★★★★ ★★★☆☆
部署成本 云服务即用 需要本地训练
特殊场景支持 证件 / 票据专用 通用场景

核心实现步骤

1. 准备工作

首先需要在 百度 AI 开放平台 申请 API Key:

  1. 注册百度云账号
  2. 创建文字识别应用
  3. 获取 API Key 和 Secret Key

2. 基础封装类

创建 BaiduOcrService.cs 核心类,使用 HttpClient 封装带重试机制的请求:

public class BaiduOcrService
{
    private readonly HttpClient _httpClient;
    private readonly ILogger<BaiduOcrService> _logger;

    #region 配置参数
    private const string AuthUrl = "https://aip.baidubce.com/oauth/2.0/token";
    private const string GeneralUrl = "https://aip.baidubce.com/rest/2.0/ocr/v1/general_basic";
    private int _maxRetry = 3; // 最大重试次数
    #endregion

    public BaiduOcrService(HttpClient httpClient, ILogger<BaiduOcrService> logger)
    {
        _httpClient = httpClient;
        _logger = logger;
    }

    // 获取 AccessToken(带缓存机制)private async Task<string> GetAccessTokenAsync(string apiKey, string secretKey)
    {// 实现代码...}

    // 带重试机制的通用请求方法
    private async Task<string> SendWithRetryAsync(HttpRequestMessage request, int retryCount = 0)
    {
        try {var response = await _httpClient.SendAsync(request);
            response.EnsureSuccessStatusCode();
            return await response.Content.ReadAsStringAsync();}
        catch(Exception ex) when (retryCount < _maxRetry)
        {_logger.LogWarning($"请求失败,正在进行第 {retryCount+1} 次重试. Error: {ex.Message}");
            await Task.Delay(1000 * (retryCount + 1)); // 指数退避
            return await SendWithRetryAsync(request, retryCount + 1);
        }
    }
}

3. 图像处理模块

使用 System.Drawing 进行图像预处理:

public static class ImageHelper
{
    // 将截图转换为符合要求的 JPG 格式
    public static byte[] ProcessImage(Image image, int quality = 75)
    {using var ms = new MemoryStream();
        // 自动旋转校正
        if (Array.IndexOf(image.PropertyIdList, 274) > -1) 
        {var orientation = (int)image.GetPropertyItem(274).Value[0];
            image = RotateImageByExifOrientation(image, orientation);
        }

        // 质量压缩
        var encoderParams = new EncoderParameters(1);
        encoderParams.Param[0] = new EncoderParameter(Encoder.Quality, quality);

        // 转换为 RGB 格式(兼容百度 OCR)using var bitmap = new Bitmap(image);
        bitmap.Save(ms, GetEncoder(ImageFormat.Jpeg), encoderParams);

        return ms.ToArray();}

    private static ImageCodecInfo GetEncoder(ImageFormat format)
    {// 获取 JPG 编码器...}
}

4. 完整调用示例

组合各模块实现端到端识别流程:

public async Task<List<string>> RecognizeTextAsync(byte[] imageBytes)
{
    // 1. 获取 AccessToken
    var token = await GetAccessTokenAsync(_config.ApiKey, _config.SecretKey);

    // 2. 准备请求体
    var content = new MultipartFormDataContent();
    content.Add(new StringContent(token), "access_token");
    content.Add(new StringContent(Convert.ToBase64String(imageBytes)), "image");

    // 3. 发送请求
    var request = new HttpRequestMessage(HttpMethod.Post, GeneralUrl) {Content = content};
    var response = await SendWithRetryAsync(request);

    // 4. 解析结果
    var result = JsonConvert.DeserializeObject<BaiduOcrResult>(response);
    return result.words_result?.Select(x => x.words).ToList() ?? new List<string>();
}

生产环境建议

QPS 控制策略

// 使用 Polly 实现速率限制
var ratePolicy = Policy.RateLimitAsync(
    numberOfExecutions: 2, 
    perTimeSpan: TimeSpan.FromSeconds(1),
    maxBurst: 1);

// 结合重试策略
var policyWrap = Policy.WrapAsync(retryPolicy, ratePolicy);

敏感数据处理

在存储日志时添加脱敏处理:

private string SanitizeInput(string input)
{
    // 身份证号脱敏
    if (Regex.IsMatch(input, @"^[1-9]\d{5}\d{4}"))
        return Regex.Replace(input, @"(\d{6})\d{8}(\w{4})", "$1********$2");

    // 银行卡号脱敏
    if (Regex.IsMatch(input, @"^[1-9]\d{12,18}$"))
        return Regex.Replace(input, @"(\d{6})\d+(\d{4})", "$1******$2");

    return input;
}

延伸开发

基于上述核心模块,可以快速扩展出实用工具:

  1. 截图识别工具
  2. 使用 Graphics.CopyFromScreen 获取屏幕区域
  3. 通过热键触发识别流程

  4. WPF 可视化应用

    <Window>
        <Grid>
            <Button Content="截图识别" Click="OnCaptureClick"/>
            <Image x:Name="PreviewImage"/>
            <TextBox x:Name="ResultText" AcceptsReturn="True"/>
        </Grid>
    </Window>

完整代码示例已上传 Gist:点击查看完整项目

开发心得

经过这次实践,最大的收获是认识到完善的错误处理机制比核心功能更重要。特别是在网络请求场景中,重试策略、限流控制和降级方案缺一不可。建议大家在开发类似工具时:

  • 早期就建立完善的日志系统
  • 对第三方 API 做必要的抽象隔离
  • 在 UI 层提供明确的操作反馈

这些经验让我后续开发效率提升了至少 30%,希望对你也有所帮助。

正文完
 0
评论(没有评论)