如何调试C#中的OCR

This article was translated from English: Does it need improvement?
Translated
View the article in English

IronOCR 使您能够在源头检测 OCR 错误,在单词和字符级别评估识别质量,并实时监控长时间运行的任务。内置工具(如诊断文件日志记录、类型化异常层次结构、按结果的置信度评分以及 OcrProgress 事件)支持生产管道中的这些工作流。

本指南将逐一介绍以下工作示例:启用诊断日志记录、处理类型异常、使用置信度分数验证输出、实时监控作业进度以及隔离批处理管道中的错误。

快速入门:启用完整 OCR 诊断日志记录

在首次调用 Read 之前,需在 Installation 类上设置 LogFilePathLogging模式。 只需两个属性即可将 Tesseract 初始化、语言包加载和处理详细信息捕获到日志文件中。

  1. 使用 NuGet 包管理器安装 https://www.nuget.org/packages/IronOcr

    PM > Install-Package IronOcr
  2. 复制并运行这段代码。

    IronOcr.Installation.LogFilePath = "ocr.log"; IronOcr.Installation.Logging模式 = IronOcr.Installation.LoggingModes.All;
  3. 部署到您的生产环境中进行测试

    通过免费试用立即在您的项目中开始使用IronOCR

    arrow pointer


如何启用诊断日志记录?

Installation 类提供了三个日志控件。 在调用任何 Read 方法之前,请先设置这些选项。

:path=/static-assets/ocr/content-code-examples/how-to/debugging-enable-logging.cs
using IronOcr;

// Write logs to a specific file
Installation.LogFilePath = "logs/ocr_diagnostics.log";

// Enable all logging channels: file + debug output
Installation.LoggingMode = Installation.LoggingModes.All;

// Or pipe logs into your existing ILogger pipeline
Installation.CustomLogger = myLoggerInstance;
Imports IronOcr

' Write logs to a specific file
Installation.LogFilePath = "logs/ocr_diagnostics.log"

' Enable all logging channels: file + debug output
Installation.LoggingMode = Installation.LoggingModes.All

' Or pipe logs into your existing ILogger pipeline
Installation.CustomLogger = myLoggerInstance
$vbLabelText   $csharpLabel

Logging模式 接受来自 Logging模式s 枚举的标志值:

表 1:日志模式选项
模式输出目标用例
禁用带有外部监控的生产
调试IDE调试输出窗口本地开发
文件LogFilePath服务器端日志收集
全部调试 + 文件完整的诊断捕获

CustomLogger 属性支持任何 Microsoft.Extensions.Logging.ILogger 实现,允许您将 OCR 诊断信息发送到 Serilog、NLog 或管道中的其他结构化日志接收器。使用 ClearLogFiles 清除运行间积累的日志数据。

日志记录就绪后,下一步是了解IronOCR可能抛出哪些异常以及如何处理每一种异常。

IronOCR会抛出哪些异常?

IronOCR 在 IronOcr.Exceptions 命名空间下定义了类型化异常。 与其进行一刀切式拦截,不如专门针对这些故障类型进行拦截,这样可以将每种故障类型路由到正确的修复路径。

表 2: IronOCR异常参考
例外情况常见原因修复
IronOcrInput例外情况损坏或不支持的图像/PDF在加载到OcrInput之前验证文件
IronOcrProduct例外情况OCR执行期间的内部引擎错误启用日志,检查日志输出,更新到最新的NuGet版本
IronOcrDictionary例外情况缺少或损坏的.traineddata语言文件重新安装语言包NuGet或设置LanguagePackDirectory
IronOcrNative例外情况原生C++互操作失败安装Visual C++ Redistributable;检查AVX支持
IronOcrLicensing例外情况缺少或过期的许可证密钥在调用Read之前设置LicenseKey
LanguagePack例外情况在预期路径中找不到语言包验证LanguagePackDirectory或重新安装NuGet语言包
IronOcrAssemblyVersionMismatch例外情况部分更新后程序集版本不匹配清除NuGet缓存,恢复包,确保所有IronOCR包匹配

使用以下 try-catch 块分别处理每种异常类型,应用异常过滤器进行条件日志记录。

输入

IronOCR Solutions 向 Acme Corporation 开具的一页供应商发票,通过 LoadPdf 加载到 OcrInput 中。 它包括四项内容、税款和总计——足够丰富的文本种类,可以给每个异常处理程序一个现实的练习。

invoice_scan.pdf:供应商发票(#INV-2024-7829),用于按顺序演示每个类型化的异常处理程序。

:path=/static-assets/ocr/content-code-examples/how-to/debugging-exception-handling.cs
using IronOcr;
using IronOcr.Exceptions;

var ocr = new IronTesseract();

try
{
    using var input = new OcrInput();
    input.LoadPdf("invoice_scan.pdf");

    OcrResult result = ocr.Read(input);
    Console.WriteLine($"Text: {result.Text}");
    Console.WriteLine($"Confidence: {result.Confidence:P1}");
}
catch (IronOcrInputException ex)
{
    // File could not be loaded — corrupt, locked, or unsupported format
    Console.Error.WriteLine($"Input error: {ex.Message}");
}
catch (IronOcrDictionaryException ex)
{
    // Language pack missing — common in containerized deployments
    Console.Error.WriteLine($"Language pack error: {ex.Message}");
}
catch (IronOcrNativeException ex) when (ex.Message.Contains("AVX"))
{
    // CPU does not support AVX instructions
    Console.Error.WriteLine($"Hardware incompatibility: {ex.Message}");
}
catch (IronOcrLicensingException)
{
    Console.Error.WriteLine("License key is missing or invalid.");
}
catch (IronOcrProductException ex)
{
    // Catch-all for other IronOCR engine errors
    Console.Error.WriteLine($"OCR engine error: {ex.Message}");
    Console.Error.WriteLine($"Stack trace: {ex.StackTrace}");
}
Imports IronOcr
Imports IronOcr.Exceptions

Dim ocr As New IronTesseract()

Try
    Using input As New OcrInput()
        input.LoadPdf("invoice_scan.pdf")

        Dim result As OcrResult = ocr.Read(input)
        Console.WriteLine($"Text: {result.Text}")
        Console.WriteLine($"Confidence: {result.Confidence:P1}")
    End Using
Catch ex As IronOcrInputException
    ' File could not be loaded — corrupt, locked, or unsupported format
    Console.Error.WriteLine($"Input error: {ex.Message}")
Catch ex As IronOcrDictionaryException
    ' Language pack missing — common in containerized deployments
    Console.Error.WriteLine($"Language pack error: {ex.Message}")
Catch ex As IronOcrNativeException When ex.Message.Contains("AVX")
    ' CPU does not support AVX instructions
    Console.Error.WriteLine($"Hardware incompatibility: {ex.Message}")
Catch ex As IronOcrLicensingException
    Console.Error.WriteLine("License key is missing or invalid.")
Catch ex As IronOcrProductException
    ' Catch-all for other IronOCR engine errors
    Console.Error.WriteLine($"OCR engine error: {ex.Message}")
    Console.Error.WriteLine($"Stack trace: {ex.StackTrace}")
End Try
$vbLabelText   $csharpLabel

输出

成功输出

发票加载正常,引擎返回字符数和置信度评分。

终端输出显示成功读取 invoice_scan.pdf 的 OCR 字符集,包括字符数和置信度。

输出失败

终端输出显示加载缺失的 PDF 文件时抛出异常

按从最具体到最一般的顺序排列捕获块。 when 子句在 IronOcrNative例外情况 过滤器上筛选与 AVX 相关的故障,同时不会捕获无关的原生错误。 每个处理程序都会记录异常消息; 兜底块还会捕获堆栈跟踪信息,以便进行事后分析。

捕获正确的异常可以告诉你哪里出了问题,但并不能告诉你引擎在成功运行时表现如何。 为此,可以使用置信度评分。

如何使用置信度分数验证 OCR 输出?

每个 OcrResult 都会暴露一个 Confidence 属性,其取值范围为 0 到 1,代表引擎对所有识别字符的统计置信度平均值。 您可以在结果层次结构的每个级别访问此功能:文档页面段落单词字符

使用阈值门控模式防止低质量结果向下游传播。

输入

一张热敏收据,包含明细项目、折扣、总计和BarCode,通过 LoadImage 加载。 它的窄宽度、等宽字体和淡淡的印刷字体使其成为逐字置信度阈值的实用压力测试。

这是FoodMart超市的热敏收据样本,显示了详细的购买项目、总计和奖励积分,用作OCR输入。

receipt.png: 热敏收据扫描用于演示阈值门控置信度验证和逐词准确性搜索的收据图像

:path=/static-assets/ocr/content-code-examples/how-to/debugging-confidence-scoring.cs
using IronOcr;

var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("receipt.png");

OcrResult result = ocr.Read(input);
double confidence = result.Confidence;

Console.WriteLine($"Overall confidence: {confidence:P1}");

// Threshold-gated decision
if (confidence >= 0.90)
{
    Console.WriteLine("ACCEPT — high confidence, processing result.");
    ProcessResult(result.Text);
}
else if (confidence >= 0.70)
{
    Console.WriteLine("FLAG — moderate confidence, queuing for review.");
    QueueForReview(result.Text, confidence);
}
else
{
    Console.WriteLine("REJECT — low confidence, logging for investigation.");
    LogRejection("receipt.png", confidence);
}

// Drill into per-page and per-word confidence for diagnostics
foreach (var page in result.Pages)
{
    Console.WriteLine($"  Page {page.PageNumber}: {page.Confidence:P1}");

    var lowConfidenceWords = page.Words
        .Where(w => w.Confidence < 0.70)
        .ToList();

    foreach (var word in lowConfidenceWords)
    {
        Console.WriteLine($"    Low-confidence word: \"{word.Text}\" ({word.Confidence:P1})");
    }
}
Imports IronOcr

Dim ocr As New IronTesseract()
Using input As New OcrInput()
    input.LoadImage("receipt.png")

    Dim result As OcrResult = ocr.Read(input)
    Dim confidence As Double = result.Confidence

    Console.WriteLine($"Overall confidence: {confidence:P1}")

    ' Threshold-gated decision
    If confidence >= 0.9 Then
        Console.WriteLine("ACCEPT — high confidence, processing result.")
        ProcessResult(result.Text)
    ElseIf confidence >= 0.7 Then
        Console.WriteLine("FLAG — moderate confidence, queuing for review.")
        QueueForReview(result.Text, confidence)
    Else
        Console.WriteLine("REJECT — low confidence, logging for investigation.")
        LogRejection("receipt.png", confidence)
    End If

    ' Drill into per-page and per-word confidence for diagnostics
    For Each page In result.Pages
        Console.WriteLine($"  Page {page.PageNumber}: {page.Confidence:P1}")

        Dim lowConfidenceWords = page.Words _
            .Where(Function(w) w.Confidence < 0.7) _
            .ToList()

        For Each word In lowConfidenceWords
            Console.WriteLine($"    Low-confidence word: ""{word.Text}"" ({word.Confidence:P1})")
        Next
    Next
End Using
$vbLabelText   $csharpLabel

输出

终端输出显示收据图像的置信度评分、接受/标记/拒绝决定,以及逐字低置信度细分信息。

这种模式在OCR反馈到数据输入、发票处理或合规工作流的管道中至关重要。 逐字分析可以准确地确定源图像的哪些区域导致了图像质量下降; 然后您可以应用图像质量滤镜方向校正并重新处理。 对于置信评分的更深入了解,请参阅置信度级别指导

对于需要长期从事的工作来说,光有自信是不够的。 您还需要了解引擎是否仍在运行,而这就是 OcrProgress 事件的作用所在。

如何实时监控OCR识别进度?

对于多页文档,每完成一页后,IronTesseract 上的 OcrProgress 事件就会触发。 OcrProgressEventArgs 对象公开了进度百分比、已用时长、总页数和已完成页数。 该示例使用这份三页的季度报告作为输入:一份结构化的商业文档,包括执行摘要、收入明细和运营指标。

输入

通过 LoadPdf 加载的 2024 年第一季度三页财务报告。 第一页涵盖了执行摘要和 KPI 指标,第二页包含按产品线和地区划分的收入表,第三页涵盖了运营处理量——每种页面类型都会产生不同的每页时间,您可以在进度回调中观察到。

quarterly_report.pdf: Three-page Q1 2024 financial report (executive summary, revenue breakdown, operational metrics) used to demonstrate real-time `OcrProgress` callbacks per page.

:path=/static-assets/ocr/content-code-examples/how-to/debugging-progress-monitoring.cs
using IronOcr;

var ocr = new IronTesseract();

ocr.OcrProgress += (sender, e) =>
{
    Console.WriteLine(
        $"[OCR] {e.ProgressPercent}% complete | " +
        $"Page {e.PagesComplete}/{e.TotalPages} | " +
        $"Elapsed: {e.Duration.TotalSeconds:F1}s"
    );
};

using var input = new OcrInput();
input.LoadPdf("quarterly_report.pdf");

OcrResult result = ocr.Read(input);
Console.WriteLine($"Finished in {result.Pages.Count()} pages, confidence: {result.Confidence:P1}");
Imports IronOcr

Dim ocr = New IronTesseract()

AddHandler ocr.OcrProgress, Sub(sender, e)
    Console.WriteLine(
        $"[OCR] {e.ProgressPercent}% complete | " &
        $"Page {e.PagesComplete}/{e.TotalPages} | " &
        $"Elapsed: {e.Duration.TotalSeconds:F1}s"
    )
End Sub

Using input As New OcrInput()
    input.LoadPdf("quarterly_report.pdf")

    Dim result As OcrResult = ocr.Read(input)
    Console.WriteLine($"Finished in {result.Pages.Count()} pages, confidence: {result.Confidence:P1}")
End Using
$vbLabelText   $csharpLabel

输出

终端输出显示了三页 PDF 文件中每页的 OcrProgress 事件回调次数、完成百分比和耗时。

将此事件连接到您的日志记录基础架构,以跟踪 OCR 作业持续时间并检测停滞情况。 如果经过的时间超过阈值而进度百分比没有增加,则管道可以标记该作业以进行调查。 这对于批量PDF处理特别有用,因为单个格式错误的页面可能会阻止整个作业。

进度监控显示执行状态,但如果不进行隔离,文件级故障仍然可能导致整个批处理提前停止。

如何处理批量 OCR 流程中的错误?

在生产环境中,单个文件故障不应该导致整个批次停止运行。 按文件隔离错误,记录故障及其上下文,并在最后生成总结报告。 此示例处理一个包含发票、采购订单、服务合同以及一个故意损坏文件的扫描文档文件夹以触发错误路径。 下面展示的是一个具有代表性的例子:

输入

一个包含 PDF 文件的文件夹被传递给 Directory.GetFiles —— 其中包括一张发票、一份采购订单、一份服务合同以及一个故意损坏的文件。下面的两个代表性示例展示了该处理管道在单次运行中处理的文档多样性。

:path=/static-assets/ocr/content-code-examples/how-to/debugging-batch-pipeline.cs
using IronOcr;
using IronOcr.Exceptions;

var ocr = new IronTesseract();
Installation.LogFilePath = "batch_debug.log";
Installation.LoggingMode = Installation.LoggingModes.File;

string[] files = Directory.GetFiles("scans/", "*.pdf");
int succeeded = 0, failed = 0;
double totalConfidence = 0;
var failures = new List<(string File, string Error)>();

foreach (string file in files)
{
    try
    {
        using var input = new OcrInput();
        input.LoadPdf(file);

        OcrResult result = ocr.Read(input);
        totalConfidence += result.Confidence;
        succeeded++;

        Console.WriteLine($"OK: {Path.GetFileName(file)} — {result.Confidence:P1}");
    }
    catch (IronOcrInputException ex)
    {
        failed++;
        failures.Add((file, $"Input error: {ex.Message}"));
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.Message}");
    }
    catch (IronOcrProductException ex)
    {
        failed++;
        failures.Add((file, $"Engine error: {ex.Message}"));
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.Message}");
    }
    catch (Exception ex)
    {
        failed++;
        failures.Add((file, $"Unexpected: {ex.Message}"));
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.GetType().Name}: {ex.Message}");
    }
}

// Summary report
Console.WriteLine($"\n--- Batch Summary ---");
Console.WriteLine($"Total: {files.Length} | Passed: {succeeded} | Failed: {failed}");
if (succeeded > 0)
    Console.WriteLine($"Average confidence: {totalConfidence / succeeded:P1}");

foreach (var (f, err) in failures)
    Console.WriteLine($"  {Path.GetFileName(f)}: {err}");
Imports IronOcr
Imports IronOcr.Exceptions
Imports System.IO

Dim ocr As New IronTesseract()
Installation.LogFilePath = "batch_debug.log"
Installation.LoggingMode = Installation.LoggingModes.File

Dim files As String() = Directory.GetFiles("scans/", "*.pdf")
Dim succeeded As Integer = 0
Dim failed As Integer = 0
Dim totalConfidence As Double = 0
Dim failures As New List(Of (File As String, Error As String))()

For Each file As String In files
    Try
        Using input As New OcrInput()
            input.LoadPdf(file)

            Dim result As OcrResult = ocr.Read(input)
            totalConfidence += result.Confidence
            succeeded += 1

            Console.WriteLine($"OK: {Path.GetFileName(file)} — {result.Confidence:P1}")
        End Using
    Catch ex As IronOcrInputException
        failed += 1
        failures.Add((file, $"Input error: {ex.Message}"))
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.Message}")
    Catch ex As IronOcrProductException
        failed += 1
        failures.Add((file, $"Engine error: {ex.Message}"))
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.Message}")
    Catch ex As Exception
        failed += 1
        failures.Add((file, $"Unexpected: {ex.Message}"))
        Console.Error.WriteLine($"FAIL: {Path.GetFileName(file)} — {ex.GetType().Name}: {ex.Message}")
    End Try
Next

' Summary report
Console.WriteLine(vbCrLf & "--- Batch Summary ---")
Console.WriteLine($"Total: {files.Length} | Passed: {succeeded} | Failed: {failed}")
If succeeded > 0 Then
    Console.WriteLine($"Average confidence: {totalConfidence / succeeded:P1}")
End If

For Each failure In failures
    Console.WriteLine($"  {Path.GetFileName(failure.File)}: {failure.Error}")
Next
$vbLabelText   $csharpLabel

输出

终端输出显示批处理管道的结果,包括每个文件的字符数、置信度分数、一个来自损坏 PDF 的错误以及摘要行。

外部 catch 块处理意外错误,包括共享存储上的网络超时、权限问题或大型 TIFF 文件内存不足的情况。 每个故障记录文件路径和错误消息以供总结,而循环继续处理剩余的文件。 位于 batch_debug.log 的日志文件记录了任何触发内部诊断的文件的引擎级详细信息。

为了在服务或 Web 应用程序中实现非阻塞执行,IronOCR 支持 ReadAsync,该功能采用相同的 try-catch 结构。

如果管道运行没有错误,但提取的文本仍然错误,那么根本原因几乎总是图像质量而不是代码。 以下是解决之道。

如何调试OCR准确率?

如果置信度得分持续偏低,则问题出在源图像上,而不是 OCR 引擎。IronOCR 提供了IronOCR工具来解决这个问题:

针对部署特定问题, IronOCR维护了Azure FunctionsDocker 和 Linux的专门故障排除指南以及一般环境设置指南。

接下来我该去哪里?

既然您已经了解如何在运行时调试IronOCR ,请探索以下内容:

如需用于生产,请务必获取许可证以去除水印并使用全部功能。

常见问题解答

调试C#中的OCR时常见问题是什么?

常见问题包括OCR结果不正确、置信度评分低和意外异常。IronOCR提供日志记录和置信度评分等工具,以帮助识别和解决这些问题。

IronOCR如何协助C#中的错误处理?

IronOCR提供类型化异常和详细错误消息,有助于在C#应用程序的OCR操作期间有效理解和处理错误。

IronOCR提供了哪些用于调试的日志功能?

IronOCR包括内置日志功能,有助于跟踪OCR过程并通过记录OCR操作的详细信息来识别潜在问题。

置信度评分如何改善OCR结果?

IronOCR中的置信度评分有助于确定识别文本的准确性,使开发者可以专注于低置信度区域并改进OCR结果。

我可以使用IronOCR跟踪OCR任务的进度吗?

可以,IronOCR提供的进度跟踪功能使开发者能够监控OCR任务的状态和持续时间,从而促进更好的资源管理和性能优化。

OCR错误处理推荐哪些try-catch模式?

IronOCR建议使用生产就绪的try-catch模式来优雅地处理异常,确保OCR应用程序的稳健性和可维护性。

IronOCR的内置工具如何增强OCR调试?

IronOCR的工具,如日志记录、类型化异常和置信度评分,为识别和解决问题提供了全面支持,从而增强调试过程。

为何错误日志记录在OCR应用程序中很重要?

错误日志记录非常重要,因为它提供了OCR处理过程中出现问题的见解,使开发者可以快速诊断和修复应用程序中的问题。

类型化异常在IronOCR的调试中发挥了什么作用?

IronOCR中的类型化异常提供了具体错误信息,使开发人员更容易理解问题的性质并在调试期间应用适当的解决方案。

开发者如何从IronOCR的调试功能中获益?

开发者可以利用IronOCR的调试功能来高效解决问题,提高应用程序的稳定性,并改善OCR结果的整体质量。

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

除了开发之外,Curtis 对物联网 (IoT) 有浓厚的兴趣,探索将硬件和软件集成的新方法。在空闲时间,他喜欢玩游戏和构建 Discord 机器人,将他对技术的热爱与创造力相结合。

准备开始了吗?
Nuget 下载 5,896,332 | 版本: 2026.5 just released
Still Scrolling Icon

还在滚动吗?

想快速获得证据? PM > Install-Package IronOcr
运行示例 观看您的图像变成可搜索文本。