跳至頁尾內容
影片

如何在 C# 中讀取多 FramePage GIF 和 TIFF

本指南帶領.NET開發人員全面遷移從PaddleSharp OCR (Sdcb.PaddleOCR) 到 IronOCR。 它涵蓋替換推理會話管理,消除OpenCV預處理依賴,移除CPU、GPU和OpenVINO的後端選擇邏輯,以及遷移表格識別工作流程。 每個部分提供來自PaddleSharp特定模式的前後程式碼範例,這些模式不會出現在一般OCR比較中。

為什麼從PaddleSharp OCR遷移

PaddleSharp在應用層導出一個深度學習推理管道。 該架構讓您可以存取PaddlePaddle模型性能,但要求您的應用程式管理否則會是基礎設施的問題。 以下痛點驅使大多數.NET團隊尋找替代方案。

推理後端配置為應用程式程式碼。 在PaddleSharp中,選擇CPU、GPU和OpenVINO後端需要構建和配置PaddleConfig物件,選擇適合部署目標的本機運行時NuGet包,並根據運行時可用的硬體有條件地分支您的初始化程式碼。此邏輯存在於您的應用程式中,而不是在庫中,當目標環境變更時會中斷。

OpenCV是圖像輸入的必要依賴。 PaddleSharp不能直接接受文件路徑或流。 每個圖像在到達OCR引擎之前,必須通過OpenCV的OpenCvSharp4.runtime.*包進入您的依賴圖。 更新一個平台運行時而不更新另一個平台運行時會導致運行時失敗,而這些失敗在不同環境中很難重現。

推理會話生命週期需要顯式設計。 PaddleOcrAll在構建時從磁碟載入三個模型二進制文件。這種成本(以毫秒為單位計算)意味著該物件無法按需實例化。團隊必須設計一個生命週期策略: 單例、池化或範圍。 在ASP.NET Core中,這通常意味著註冊服務並仔細進行執行緒安全分析,因為PaddleOcrAll共享底層的本地狀態。

表格識別需要單獨的模型下載。 PaddleSharp中的結構化文件提取除了標準的三段檢測/分類/識別管道外,還需要專門的表格識別模型。該模型是下載、版本管理和配置的第四個文件。 沒有統一的API表面——表格識別使用具有自身結果型別的單獨程式碼路徑。

無可搜尋的PDF輸出。 PaddleSharp生成文字字串。 它無法生成可搜尋的PDF文件。 需要將掃描文件歸檔為文字可搜尋的PDF的團隊必須整合單獨的PDF庫,管理該附加依賴並編寫轉換層。 輸出格式差距是完全的:無hOCR,無結構化的可搜尋PDF,無文字層覆蓋。

上游依賴鏈不屬於.NET社群。 PaddleSharp封裝了百度的PaddlePaddle推理框架。 PaddleOCR版本之間的模型格式更改曾經破壞過.NET綁定層。大多數問題跟踪、文件和發佈討論都是用中文進行的。 對於沒有普通話使用者監控上游項目的.NET團隊,革命性變革會毫無預警地到來。

根本問題

在PaddleSharp中選擇和初始化後端需要應屬於基礎設施的配置程式碼,而不是OCR邏輯:

// PaddleSharp: Backend selection sprawls into application startup
// Simplified — see Sdcb.PaddleInference documentation for full API
using Sdcb.PaddleInference;
using Sdcb.PaddleOCR;

// CPU-only deployment
var config = PaddleConfig.FromModelDir("models/det");
config.SetCpuMathLibraryNumThreads(4);

// GPU deployment — different package, different init path
// var config = PaddleConfig.FromModelDir("models/det");
// config.EnableGpu(500, 0);  // memoryMB, deviceId

// OpenVINO deployment — third conditional branch
// config.EnableMkldnn();

// Application code now owns the hardware topology decision
// PaddleSharp: Backend selection sprawls into application startup
// Simplified — see Sdcb.PaddleInference documentation for full API
using Sdcb.PaddleInference;
using Sdcb.PaddleOCR;

// CPU-only deployment
var config = PaddleConfig.FromModelDir("models/det");
config.SetCpuMathLibraryNumThreads(4);

// GPU deployment — different package, different init path
// var config = PaddleConfig.FromModelDir("models/det");
// config.EnableGpu(500, 0);  // memoryMB, deviceId

// OpenVINO deployment — third conditional branch
// config.EnableMkldnn();

// Application code now owns the hardware topology decision
Imports Sdcb.PaddleInference
Imports Sdcb.PaddleOCR

' PaddleSharp: Backend selection sprawls into application startup
' Simplified — see Sdcb.PaddleInference documentation for full API

' CPU-only deployment
Dim config = PaddleConfig.FromModelDir("models/det")
config.SetCpuMathLibraryNumThreads(4)

' GPU deployment — different package, different init path
' Dim config = PaddleConfig.FromModelDir("models/det")
' config.EnableGpu(500, 0)  ' memoryMB, deviceId

' OpenVINO deployment — third conditional branch
' config.EnableMkldnn()

' Application code now owns the hardware topology decision
$vbLabelText   $csharpLabel
// IronOCR:不是backend selection.不是config objects. Zero hardware decisions.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
// Runs on CPU, Linux, Docker, or ARM without a code change
// IronOCR:不是backend selection.不是config objects. Zero hardware decisions.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var result = new IronTesseract().Read("document.jpg");
Console.WriteLine(result.Text);
// Runs on CPU, Linux, Docker, or ARM without a code change
Imports IronOcr

' IronOCR:不是backend selection.不是config objects. Zero hardware decisions.
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim result = New IronTesseract().Read("document.jpg")
Console.WriteLine(result.Text)
' Runs on CPU, Linux, Docker, or ARM without a code change
$vbLabelText   $csharpLabel

IronOCR與 PaddleSharp OCR: 功能對比

這裡是一個在遷移過程中最為重要的能力維度的直接比較:

功能 PaddleSharp OCR IronOCR
需要 NuGet 套件 至少3–4 1
圖像輸入方法 OpenCV Cv2.ImRead() 直接路徑、流或字節陣列
PDF輸入(本機) 不是
受密碼保護的 PDF 不是
多頁TIFF 通過OpenCV 本地
可搜尋的 PDF 輸出 不是 是 (result.SaveAsSearchablePdf())
hOCR匯出 不是
後端選擇(CPU/GPU/OpenVINO) 手動 PaddleConfig 自動
預處理管道 手動OpenCV操作 內建 (Deskew, DeNoise, Contrast, 等)
推理會話生命週期管理 手動(代價高的構建) 輕量級 IronTesseract
表格識別模型 獨立下載和程式碼路徑 input.LoadImage() + 結構化結果
支持的語言 ~10–20 125+
語言安裝 模型文件下載 NuGet套件
同時多語言支持 有限 是 (OcrLanguage.French + OcrLanguage.German)
基於區域的OCR 無內建 CropRectangle
OCR期間的條碼讀取 不是 是 (ocr.Configuration.ReadBarCodes = true)
置信分數 每區域 每單詞,每行,每頁
結構化輸出層次 平坦的區域列表 頁 → 段落 → 行 → 單詞 → 字元
跨平台部署 複雜(平台運行時包) 單一NuGet,所有平台
Docker部署 多層,運行時包 單層
商業支持 GitHub問題(主要是中文) 電子郵件支援
授權模式 Apache 2.0 永久 ($999 Lite, $1,499 Pro, $2,999 Enterprise)

快速開始:PaddleSharp OCR到IronOCR遷移

步驟1:替換NuGet包

移除 PaddleSharp 及其 OpenCV 依賴項:

dotnet remove package Sdcb.PaddleOCR
dotnet remove package Sdcb.PaddleInference
dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
dotnet remove package Sdcb.PaddleOCR
dotnet remove package Sdcb.PaddleInference
dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
SHELL

NuGet安裝IronOCR:

dotnet add package IronOcr

步驟2:更新命名空間

用單一的IronOCR命名空間替換 PaddleSharp 命名空間:

// Before (PaddleSharp)
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using Sdcb.PaddleInference;
using OpenCvSharp;

// After (IronOCR)
using IronOcr;
// Before (PaddleSharp)
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using Sdcb.PaddleInference;
using OpenCvSharp;

// After (IronOCR)
using IronOcr;
Imports IronOcr
$vbLabelText   $csharpLabel

步驟3:初始化許可證

在應用程式啟動時一次性新增許可初始化,可以在Program.cs, Startup.cs或您的組合根中進行:

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
$vbLabelText   $csharpLabel

程式碼遷移範例

推理會話生命週期替代

PaddleSharp的PaddleOcrAll非常昂貴,因為在實例化時同步載入三個模型二進制文件。 生產應用必須將其視為長壽命物件,這驅動了一個具體的依賴注入模式。 釋放鏈也需要注意,因為必須按正確的順序釋放底層本地資源。

PaddleSharp OCR 方法:

// Simplified — see Sdcb.PaddleOCR documentation for full API
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using OpenCvSharp;
using Microsoft.Extensions.DependencyInjection;

// Expensive: loads 3 model files from disk on construction (~300–800ms)
public class PaddleOcrEngine : IDisposable
{
    private readonly PaddleOcrAll _ocr;
    private bool _disposed;

    public PaddleOcrEngine()
    {
        var detModel = LocalFullModels.ChineseV3.DetectionModel;
        var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
        var recModel = LocalFullModels.ChineseV3.RecognitionModel;

        // Must be singleton — cannot afford per-request construction
        _ocr = new PaddleOcrAll(detModel, clsModel, recModel);
    }

    public string Read(string imagePath)
    {
        using var mat = Cv2.ImRead(imagePath); // OpenCV required even for a file path
        var result = _ocr.Run(mat);
        return string.Join(" ", result.Regions.Select(r => r.Text));
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            _ocr?.Dispose();
            _disposed = true;
        }
    }
}

// Startup.cs — forced singleton because of construction cost
services.AddSingleton<PaddleOcrEngine>();
// Simplified — see Sdcb.PaddleOCR documentation for full API
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using OpenCvSharp;
using Microsoft.Extensions.DependencyInjection;

// Expensive: loads 3 model files from disk on construction (~300–800ms)
public class PaddleOcrEngine : IDisposable
{
    private readonly PaddleOcrAll _ocr;
    private bool _disposed;

    public PaddleOcrEngine()
    {
        var detModel = LocalFullModels.ChineseV3.DetectionModel;
        var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
        var recModel = LocalFullModels.ChineseV3.RecognitionModel;

        // Must be singleton — cannot afford per-request construction
        _ocr = new PaddleOcrAll(detModel, clsModel, recModel);
    }

    public string Read(string imagePath)
    {
        using var mat = Cv2.ImRead(imagePath); // OpenCV required even for a file path
        var result = _ocr.Run(mat);
        return string.Join(" ", result.Regions.Select(r => r.Text));
    }

    public void Dispose()
    {
        if (!_disposed)
        {
            _ocr?.Dispose();
            _disposed = true;
        }
    }
}

// Startup.cs — forced singleton because of construction cost
services.AddSingleton<PaddleOcrEngine>();
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models
Imports OpenCvSharp
Imports Microsoft.Extensions.DependencyInjection

' Expensive: loads 3 model files from disk on construction (~300–800ms)
Public Class PaddleOcrEngine
    Implements IDisposable

    Private ReadOnly _ocr As PaddleOcrAll
    Private _disposed As Boolean

    Public Sub New()
        Dim detModel = LocalFullModels.ChineseV3.DetectionModel
        Dim clsModel = LocalFullModels.ChineseV3.ClassifierModel
        Dim recModel = LocalFullModels.ChineseV3.RecognitionModel

        ' Must be singleton — cannot afford per-request construction
        _ocr = New PaddleOcrAll(detModel, clsModel, recModel)
    End Sub

    Public Function Read(imagePath As String) As String
        Using mat = Cv2.ImRead(imagePath) ' OpenCV required even for a file path
            Dim result = _ocr.Run(mat)
            Return String.Join(" ", result.Regions.Select(Function(r) r.Text))
        End Using
    End Function

    Public Sub Dispose() Implements IDisposable.Dispose
        If Not _disposed Then
            _ocr?.Dispose()
            _disposed = True
        End If
    End Sub
End Class

' Startup.vb — forced singleton because of construction cost
services.AddSingleton(Of PaddleOcrEngine)()
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;
using Microsoft.Extensions.DependencyInjection;

// IronTesseract has lightweight initialization — no model loading on construction
public class OcrEngine
{
    public string Read(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}

// Flexible registration — singleton, scoped, or transient all work
services.AddTransient<OcrEngine>();

// Or skip the wrapper entirely and inject IronTesseract directly
services.AddTransient<IronTesseract>();
using IronOcr;
using Microsoft.Extensions.DependencyInjection;

// IronTesseract has lightweight initialization — no model loading on construction
public class OcrEngine
{
    public string Read(string imagePath)
    {
        return new IronTesseract().Read(imagePath).Text;
    }
}

// Flexible registration — singleton, scoped, or transient all work
services.AddTransient<OcrEngine>();

// Or skip the wrapper entirely and inject IronTesseract directly
services.AddTransient<IronTesseract>();
Imports IronOcr
Imports Microsoft.Extensions.DependencyInjection

' IronTesseract has lightweight initialization — no model loading on construction
Public Class OcrEngine
    Public Function Read(imagePath As String) As String
        Return New IronTesseract().Read(imagePath).Text
    End Function
End Class

' Flexible registration — singleton, scoped, or transient all work
services.AddTransient(Of OcrEngine)()

' Or skip the wrapper entirely and inject IronTesseract directly
services.AddTransient(Of IronTesseract)()
$vbLabelText   $csharpLabel

從強制單例轉變為靈活壽命是具有重要意義的。 PaddleSharp的構建成本鎖定了您的服務壽命決策; IronOCR讓您可以根據應用程式的執行緒處理和請求隔離需求進行選擇。 IronTesseract 設置指南 涵蓋了在實例級別應用的配置選項。

OpenCV 預處理管道遷移

PaddleSharp 團隊通常會在調用OCR引擎之前構建一個OpenCV預處理管道。該管道要求了解OpenCV的API表面,這遠遠大於任何OCR預處理任務實際需要的。 常見操作—矯正、去噪、對比度伸縮—需要多個using塊的小心記憶體管理,以防止本地記憶體洩漏。

PaddleSharp OCR 方法:

// Simplified — see OpenCvSharp documentation for full API
using OpenCvSharp;
using Sdcb.PaddleOCR;

public string ReadWithPreprocessing(string imagePath, PaddleOcrAll ocr)
{
    using var original = Cv2.ImRead(imagePath);

    // Step 1: Grayscale conversion
    using var gray = new Mat();
    Cv2.CvtColor(original, gray, ColorConversionCodes.BGR2GRAY);

    // Step 2: Denoise (Gaussian blur to reduce noise)
    using var denoised = new Mat();
    Cv2.GaussianBlur(gray, denoised, new Size(3, 3), 0);

    // Step 3: Adaptive threshold for binarization
    using var binary = new Mat();
    Cv2.AdaptiveThreshold(denoised, binary, 255,
        AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 11, 2);

    // Step 4: Deskew — requires custom rotation detection logic (not shown)
    // Several dozen lines of custom Mat operations

    var result = ocr.Run(binary);
    return string.Join(" ", result.Regions.Select(r => r.Text));
    // Each Mat must be disposed; missing a using block leaks native memory
}
// Simplified — see OpenCvSharp documentation for full API
using OpenCvSharp;
using Sdcb.PaddleOCR;

public string ReadWithPreprocessing(string imagePath, PaddleOcrAll ocr)
{
    using var original = Cv2.ImRead(imagePath);

    // Step 1: Grayscale conversion
    using var gray = new Mat();
    Cv2.CvtColor(original, gray, ColorConversionCodes.BGR2GRAY);

    // Step 2: Denoise (Gaussian blur to reduce noise)
    using var denoised = new Mat();
    Cv2.GaussianBlur(gray, denoised, new Size(3, 3), 0);

    // Step 3: Adaptive threshold for binarization
    using var binary = new Mat();
    Cv2.AdaptiveThreshold(denoised, binary, 255,
        AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 11, 2);

    // Step 4: Deskew — requires custom rotation detection logic (not shown)
    // Several dozen lines of custom Mat operations

    var result = ocr.Run(binary);
    return string.Join(" ", result.Regions.Select(r => r.Text));
    // Each Mat must be disposed; missing a using block leaks native memory
}
Imports OpenCvSharp
Imports Sdcb.PaddleOCR

Public Function ReadWithPreprocessing(imagePath As String, ocr As PaddleOcrAll) As String
    Using original As Mat = Cv2.ImRead(imagePath)

        ' Step 1: Grayscale conversion
        Using gray As New Mat()
            Cv2.CvtColor(original, gray, ColorConversionCodes.BGR2GRAY)

            ' Step 2: Denoise (Gaussian blur to reduce noise)
            Using denoised As New Mat()
                Cv2.GaussianBlur(gray, denoised, New Size(3, 3), 0)

                ' Step 3: Adaptive threshold for binarization
                Using binary As New Mat()
                    Cv2.AdaptiveThreshold(denoised, binary, 255, AdaptiveThresholdTypes.GaussianC, ThresholdTypes.Binary, 11, 2)

                    ' Step 4: Deskew — requires custom rotation detection logic (not shown)
                    ' Several dozen lines of custom Mat operations

                    Dim result = ocr.Run(binary)
                    Return String.Join(" ", result.Regions.Select(Function(r) r.Text))
                End Using
            End Using
        End Using
    End Using
End Function
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public string ReadWithPreprocessing(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Named operations replace OpenCV knowledge requirements
    input.Deskew();
    input.DeNoise();
    input.Contrast();
    input.Binarize();

    var result = new IronTesseract().Read(input);
    return result.Text;
    // OcrInput implements IDisposable; using block handles cleanup
}
using IronOcr;

public string ReadWithPreprocessing(string imagePath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);

    // Named operations replace OpenCV knowledge requirements
    input.Deskew();
    input.DeNoise();
    input.Contrast();
    input.Binarize();

    var result = new IronTesseract().Read(input);
    return result.Text;
    // OcrInput implements IDisposable; using block handles cleanup
}
Imports IronOcr

Public Function ReadWithPreprocessing(imagePath As String) As String
    Using input As New OcrInput()
        input.LoadImage(imagePath)

        ' Named operations replace OpenCV knowledge requirements
        input.Deskew()
        input.DeNoise()
        input.Contrast()
        input.Binarize()

        Dim result = New IronTesseract().Read(input)
        Return result.Text
        ' OcrInput implements IDisposable; using block handles cleanup
    End Using
End Function
$vbLabelText   $csharpLabel

Mat分配。 無需了解自適應閾值參數。 無需自定義矯正旋轉數學。 同樣的預處理管道需要30–50行OpenCV程式碼,現在只需四次方法調用。 影像品質修正指南 記錄了每個可用的過濾器,並附有前後對比的例子。 對於背景噪音較重的文件,DeNoise(),無需其他參數。

對於預處理需求不標準的團隊,過濾器嚮導 提供了一個互動工具,用於在對特定文件型別進行測試之前評估各種過濾器組合。

後端選擇消除

PaddleSharp 將推理後端暴露為應用級關注點。 需要在僅CPU的雲VM上運行的部署使用的初始化程式碼與目標GPU工作站或Intel OpenVINO溢出的裝置不同。這種條件邏輯通常有最終應用程式啟動程式碼中的,而與從圖像中讀取文字無關的基礎設施工作無關。

PaddleSharp OCR 方法:

// Simplified — see Sdcb.PaddleInference documentation for full API
using Sdcb.PaddleInference;
using Sdcb.PaddleOCR;

public PaddleOcrAll CreateOcrEngine(string backendMode)
{
    // Each backend requires a different NuGet runtime package installed
    switch (backendMode)
    {
        case "gpu":
            // Requires: Sdcb.PaddleInference.runtime.win64.cuda
            // Requires: CUDA toolkit + cuDNN installed on host
            var gpuConfig = PaddleConfig.FromModelDir("models/");
            gpuConfig.EnableGpu(500, deviceId: 0); // Simplified
            break;

        case "openvino":
            // Requires: Sdcb.PaddleInference.runtime.win64.mkl
            var oviConfig = PaddleConfig.FromModelDir("models/");
            oviConfig.EnableMkldnn(); // Simplified
            break;

        default:
            // CPU-only — still requires platform-specific runtime package
            var cpuConfig = PaddleConfig.FromModelDir("models/");
            cpuConfig.SetCpuMathLibraryNumThreads(Environment.ProcessorCount);
            break;
    }

    // Backend-specific config passed to model constructors — Simplified
    var detModel = LocalFullModels.ChineseV3.DetectionModel;
    var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
    var recModel = LocalFullModels.ChineseV3.RecognitionModel;
    return new PaddleOcrAll(detModel, clsModel, recModel);
}
// Simplified — see Sdcb.PaddleInference documentation for full API
using Sdcb.PaddleInference;
using Sdcb.PaddleOCR;

public PaddleOcrAll CreateOcrEngine(string backendMode)
{
    // Each backend requires a different NuGet runtime package installed
    switch (backendMode)
    {
        case "gpu":
            // Requires: Sdcb.PaddleInference.runtime.win64.cuda
            // Requires: CUDA toolkit + cuDNN installed on host
            var gpuConfig = PaddleConfig.FromModelDir("models/");
            gpuConfig.EnableGpu(500, deviceId: 0); // Simplified
            break;

        case "openvino":
            // Requires: Sdcb.PaddleInference.runtime.win64.mkl
            var oviConfig = PaddleConfig.FromModelDir("models/");
            oviConfig.EnableMkldnn(); // Simplified
            break;

        default:
            // CPU-only — still requires platform-specific runtime package
            var cpuConfig = PaddleConfig.FromModelDir("models/");
            cpuConfig.SetCpuMathLibraryNumThreads(Environment.ProcessorCount);
            break;
    }

    // Backend-specific config passed to model constructors — Simplified
    var detModel = LocalFullModels.ChineseV3.DetectionModel;
    var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
    var recModel = LocalFullModels.ChineseV3.RecognitionModel;
    return new PaddleOcrAll(detModel, clsModel, recModel);
}
Imports Sdcb.PaddleInference
Imports Sdcb.PaddleOCR

Public Function CreateOcrEngine(ByVal backendMode As String) As PaddleOcrAll
    ' Each backend requires a different NuGet runtime package installed
    Select Case backendMode
        Case "gpu"
            ' Requires: Sdcb.PaddleInference.runtime.win64.cuda
            ' Requires: CUDA toolkit + cuDNN installed on host
            Dim gpuConfig As PaddleConfig = PaddleConfig.FromModelDir("models/")
            gpuConfig.EnableGpu(500, deviceId:=0) ' Simplified

        Case "openvino"
            ' Requires: Sdcb.PaddleInference.runtime.win64.mkl
            Dim oviConfig As PaddleConfig = PaddleConfig.FromModelDir("models/")
            oviConfig.EnableMkldnn() ' Simplified

        Case Else
            ' CPU-only — still requires platform-specific runtime package
            Dim cpuConfig As PaddleConfig = PaddleConfig.FromModelDir("models/")
            cpuConfig.SetCpuMathLibraryNumThreads(Environment.ProcessorCount)
    End Select

    ' Backend-specific config passed to model constructors — Simplified
    Dim detModel = LocalFullModels.ChineseV3.DetectionModel
    Dim clsModel = LocalFullModels.ChineseV3.ClassifierModel
    Dim recModel = LocalFullModels.ChineseV3.RecognitionModel
    Return New PaddleOcrAll(detModel, clsModel, recModel)
End Function
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

//不是backend selection.不是switch statement.不是environment variable check.
// The same code runs on CPU-only VMs, GPU workstations, and ARM devices.
public IronTesseract CreateOcrEngine()
{
    return new IronTesseract();
}

// Parallel processing across CPU cores — no GPU configuration required
public IEnumerable<string> ReadBatch(IEnumerable<string> imagePaths)
{
    var results = new System.Collections.Concurrent.ConcurrentBag<string>();
    Parallel.ForEach(imagePaths, path =>
    {
        var result = new IronTesseract().Read(path);
        results.Add(result.Text);
    });
    return results;
}
using IronOcr;

//不是backend selection.不是switch statement.不是environment variable check.
// The same code runs on CPU-only VMs, GPU workstations, and ARM devices.
public IronTesseract CreateOcrEngine()
{
    return new IronTesseract();
}

// Parallel processing across CPU cores — no GPU configuration required
public IEnumerable<string> ReadBatch(IEnumerable<string> imagePaths)
{
    var results = new System.Collections.Concurrent.ConcurrentBag<string>();
    Parallel.ForEach(imagePaths, path =>
    {
        var result = new IronTesseract().Read(path);
        results.Add(result.Text);
    });
    return results;
}
Imports IronOcr
Imports System.Collections.Concurrent
Imports System.Threading.Tasks

Public Class OcrProcessor

    '不是backend selection.不是switch statement.不是environment variable check.
    ' The same code runs on CPU-only VMs, GPU workstations, and ARM devices.
    Public Function CreateOcrEngine() As IronTesseract
        Return New IronTesseract()
    End Function

    ' Parallel processing across CPU cores — no GPU configuration required
    Public Function ReadBatch(imagePaths As IEnumerable(Of String)) As IEnumerable(Of String)
        Dim results As New ConcurrentBag(Of String)()
        Parallel.ForEach(imagePaths, Sub(path)
                                         Dim result = New IronTesseract().Read(path)
                                         results.Add(result.Text)
                                     End Sub)
        Return results
    End Function

End Class
$vbLabelText   $csharpLabel

Parallel.ForEach 模式本質上是執行緒安全的。 每個IronTesseract實例獨立,無共用本地狀態。 對於那些PaddleSharp部署花時間管理後端條件的團隊來說,這種簡化也改進了部署可靠性—相同的構建工件可以在不需要硬體檢測程式碼的情況下到處運行。 速度優化指南 涵蓋了針對吞吐量敏感場景的配置選項。

表格識別遷移

在PaddleSharp中,表格提取需要專用的表格識別模型—超出了標準檢測、分類和識別集的第四方面。 表格模型使用單獨的API調用並返回其自身的結果結構。 專門用於構建發票、表單或電子表格處理管道的團隊需要維護兩個平行的初始化路徑和兩個結果解析策略。

PaddleSharp OCR 方法:

// Simplified — see Sdcb.PaddleOCR documentation for full API
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using OpenCvSharp;

public class TableRecognitionService
{
    // Standard OCR engine — 3 models
    private readonly PaddleOcrAll _textOcr;

    // Table engine — 4th model, separate initialization
    // private readonly PaddleOcrTable _tableOcr; // Simplified

    public TableRecognitionService()
    {
        var detModel = LocalFullModels.ChineseV3.DetectionModel;
        var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
        var recModel = LocalFullModels.ChineseV3.RecognitionModel;
        _textOcr = new PaddleOcrAll(detModel, clsModel, recModel);

        // Table model: separate download, separate version tracking
        // var tableModel = LocalFullModels.TableEnV2.Model; // Simplified
        // _tableOcr = new PaddleOcrTable(tableModel); // Simplified
    }

    public void ProcessDocument(string imagePath)
    {
        using var image = Cv2.ImRead(imagePath);

        // Text extraction path
        var textResult = _textOcr.Run(image);
        var text = string.Join(" ", textResult.Regions.Select(r => r.Text));

        // Table extraction path — different API, different result structure
        // var tableResult = _tableOcr.Run(image); // Simplified
        // foreach (var cell in tableResult.Cells) { ... } // Simplified
    }
}
// Simplified — see Sdcb.PaddleOCR documentation for full API
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models;
using OpenCvSharp;

public class TableRecognitionService
{
    // Standard OCR engine — 3 models
    private readonly PaddleOcrAll _textOcr;

    // Table engine — 4th model, separate initialization
    // private readonly PaddleOcrTable _tableOcr; // Simplified

    public TableRecognitionService()
    {
        var detModel = LocalFullModels.ChineseV3.DetectionModel;
        var clsModel = LocalFullModels.ChineseV3.ClassifierModel;
        var recModel = LocalFullModels.ChineseV3.RecognitionModel;
        _textOcr = new PaddleOcrAll(detModel, clsModel, recModel);

        // Table model: separate download, separate version tracking
        // var tableModel = LocalFullModels.TableEnV2.Model; // Simplified
        // _tableOcr = new PaddleOcrTable(tableModel); // Simplified
    }

    public void ProcessDocument(string imagePath)
    {
        using var image = Cv2.ImRead(imagePath);

        // Text extraction path
        var textResult = _textOcr.Run(image);
        var text = string.Join(" ", textResult.Regions.Select(r => r.Text));

        // Table extraction path — different API, different result structure
        // var tableResult = _tableOcr.Run(image); // Simplified
        // foreach (var cell in tableResult.Cells) { ... } // Simplified
    }
}
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models
Imports OpenCvSharp

Public Class TableRecognitionService
    ' Standard OCR engine — 3 models
    Private ReadOnly _textOcr As PaddleOcrAll

    ' Table engine — 4th model, separate initialization
    ' Private ReadOnly _tableOcr As PaddleOcrTable ' Simplified

    Public Sub New()
        Dim detModel = LocalFullModels.ChineseV3.DetectionModel
        Dim clsModel = LocalFullModels.ChineseV3.ClassifierModel
        Dim recModel = LocalFullModels.ChineseV3.RecognitionModel
        _textOcr = New PaddleOcrAll(detModel, clsModel, recModel)

        ' Table model: separate download, separate version tracking
        ' Dim tableModel = LocalFullModels.TableEnV2.Model ' Simplified
        ' _tableOcr = New PaddleOcrTable(tableModel) ' Simplified
    End Sub

    Public Sub ProcessDocument(imagePath As String)
        Using image = Cv2.ImRead(imagePath)
            ' Text extraction path
            Dim textResult = _textOcr.Run(image)
            Dim text = String.Join(" ", textResult.Regions.Select(Function(r) r.Text))

            ' Table extraction path — different API, different result structure
            ' Dim tableResult = _tableOcr.Run(image) ' Simplified
            ' For Each cell In tableResult.Cells ' Simplified
            ' ... 
            ' Next
        End Using
    End Sub
End Class
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public class TableRecognitionService
{
    // One engine handles both text and table regions
    public void ProcessDocument(string imagePath)
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);

        // Structured hierarchy: pages → paragraphs → lines → words
        foreach (var page in result.Pages)
        {
            foreach (var paragraph in page.Paragraphs)
            {
                Console.WriteLine($"Block at ({paragraph.X},{paragraph.Y}): {paragraph.Text}");
            }
        }

        Console.WriteLine($"Full document text: {result.Text}");
    }
}
using IronOcr;

public class TableRecognitionService
{
    // One engine handles both text and table regions
    public void ProcessDocument(string imagePath)
    {
        var ocr = new IronTesseract();
        var result = ocr.Read(imagePath);

        // Structured hierarchy: pages → paragraphs → lines → words
        foreach (var page in result.Pages)
        {
            foreach (var paragraph in page.Paragraphs)
            {
                Console.WriteLine($"Block at ({paragraph.X},{paragraph.Y}): {paragraph.Text}");
            }
        }

        Console.WriteLine($"Full document text: {result.Text}");
    }
}
Imports IronOcr

Public Class TableRecognitionService
    ' One engine handles both text and table regions
    Public Sub ProcessDocument(imagePath As String)
        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(imagePath)

        ' Structured hierarchy: pages → paragraphs → lines → words
        For Each page In result.Pages
            For Each paragraph In page.Paragraphs
                Console.WriteLine($"Block at ({paragraph.X},{paragraph.Y}): {paragraph.Text}")
            Next
        Next

        Console.WriteLine($"Full document text: {result.Text}")
    End Sub
End Class
$vbLabelText   $csharpLabel

針對必需作為行和列提取的文件表結構,IronOCR提供專用的表提取功能:

using IronOcr;

var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("invoice-with-table.jpg");

var result = ocr.Read(input);

// Access structured page layout for table region extraction
foreach (var page in result.Pages)
{
    foreach (var line in page.Lines)
    {
        // Lines within a table region preserve spatial ordering
        Console.WriteLine($"Row text: {line.Text} | Y position: {line.Y}");
        foreach (var word in line.Words)
        {
            Console.WriteLine($"  Cell: '{word.Text}' at X={word.X}");
        }
    }
}
using IronOcr;

var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("invoice-with-table.jpg");

var result = ocr.Read(input);

// Access structured page layout for table region extraction
foreach (var page in result.Pages)
{
    foreach (var line in page.Lines)
    {
        // Lines within a table region preserve spatial ordering
        Console.WriteLine($"Row text: {line.Text} | Y position: {line.Y}");
        foreach (var word in line.Words)
        {
            Console.WriteLine($"  Cell: '{word.Text}' at X={word.X}");
        }
    }
}
Imports IronOcr

Dim ocr As New IronTesseract()
Using input As New OcrInput()
    input.LoadImage("invoice-with-table.jpg")

    Dim result = ocr.Read(input)

    ' Access structured page layout for table region extraction
    For Each page In result.Pages
        For Each line In page.Lines
            ' Lines within a table region preserve spatial ordering
            Console.WriteLine($"Row text: {line.Text} | Y position: {line.Y}")
            For Each word In line.Words
                Console.WriteLine($"  Cell: '{word.Text}' at X={word.X}")
            Next
        Next
    Next
End Using
$vbLabelText   $csharpLabel

消除了所需的一次模型下載。 消除了所需的一次初始化路徑。 IronOCR中的結構化結果層次結構具有單詞級X/Y坐標,提供了用於重建表行和列的位置資訊,而不需要單獨的識別模型。 表格讀取指南讀取結果指南涵蓋了完整的結構化輸出API。

從掃描文件生成可搜尋的PDF輸出

PaddleSharp只生成文字串,沒有其他。 打造一個可以搜尋的PDF存檔需要整合單獨的PDF庫,編寫一個文字覆蓋層,並協同管理兩個庫。 接受該約束的團隊通常發現遷移是一個觸發因素-兩庫整合的努力超過了更換OCR提供者的努力。

PaddleSharp OCR 方法:

// Simplified — PaddleSharp has no PDF output. Requires a separate PDF library.
// Example of what teams typically build:

// using Sdcb.PaddleOCR;
// using SomePdfLibrary; // Third dependency to produce searchable PDF

public void ArchiveScannedDocument(string imagePath, string outputPdfPath)
{
    // Step 1: OCR via PaddleSharp — produces text only
    // var text = _ocr.Run(Cv2.ImRead(imagePath));

    // Step 2: Build a PDF with text overlay using a separate PDF library
    // Requires: text positions mapped to PDF coordinate space
    // Requires: image embedded as background
    // Requires: invisible text layer positioned over image
    // ~50–100 lines of PDF construction code
    throw new NotImplementedException("Requires a separate PDF library");
}
// Simplified — PaddleSharp has no PDF output. Requires a separate PDF library.
// Example of what teams typically build:

// using Sdcb.PaddleOCR;
// using SomePdfLibrary; // Third dependency to produce searchable PDF

public void ArchiveScannedDocument(string imagePath, string outputPdfPath)
{
    // Step 1: OCR via PaddleSharp — produces text only
    // var text = _ocr.Run(Cv2.ImRead(imagePath));

    // Step 2: Build a PDF with text overlay using a separate PDF library
    // Requires: text positions mapped to PDF coordinate space
    // Requires: image embedded as background
    // Requires: invisible text layer positioned over image
    // ~50–100 lines of PDF construction code
    throw new NotImplementedException("Requires a separate PDF library");
}
Public Sub ArchiveScannedDocument(imagePath As String, outputPdfPath As String)
    ' Step 1: OCR via PaddleSharp — produces text only
    ' Dim text = _ocr.Run(Cv2.ImRead(imagePath))

    ' Step 2: Build a PDF with text overlay using a separate PDF library
    ' Requires: text positions mapped to PDF coordinate space
    ' Requires: image embedded as background
    ' Requires: invisible text layer positioned over image
    ' ~50–100 lines of PDF construction code
    Throw New NotImplementedException("Requires a separate PDF library")
End Sub
$vbLabelText   $csharpLabel

IronOCR方法:

using IronOcr;

public void ArchiveScannedDocument(string imagePath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    input.Deskew();   // Straighten scan before archiving
    input.DeNoise();  // Clean up scan artifacts

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    // One call: OCR + searchable PDF with text layer + image background
    result.SaveAsSearchablePdf(outputPdfPath);
}

// Multi-page document — same pattern
public void ArchiveMultiPageDocument(string[] imageFiles, string outputPdfPath)
{
    using var input = new OcrInput();
    foreach (var file in imageFiles)
        input.LoadImage(file);

    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
using IronOcr;

public void ArchiveScannedDocument(string imagePath, string outputPdfPath)
{
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    input.Deskew();   // Straighten scan before archiving
    input.DeNoise();  // Clean up scan artifacts

    var ocr = new IronTesseract();
    var result = ocr.Read(input);

    // One call: OCR + searchable PDF with text layer + image background
    result.SaveAsSearchablePdf(outputPdfPath);
}

// Multi-page document — same pattern
public void ArchiveMultiPageDocument(string[] imageFiles, string outputPdfPath)
{
    using var input = new OcrInput();
    foreach (var file in imageFiles)
        input.LoadImage(file);

    var result = new IronTesseract().Read(input);
    result.SaveAsSearchablePdf(outputPdfPath);
}
Imports IronOcr

Public Sub ArchiveScannedDocument(imagePath As String, outputPdfPath As String)
    Using input As New OcrInput()
        input.LoadImage(imagePath)
        input.Deskew()   ' Straighten scan before archiving
        input.DeNoise()  ' Clean up scan artifacts

        Dim ocr As New IronTesseract()
        Dim result = ocr.Read(input)

        ' One call: OCR + searchable PDF with text layer + image background
        result.SaveAsSearchablePdf(outputPdfPath)
    End Using
End Sub

' Multi-page document — same pattern
Public Sub ArchiveMultiPageDocument(imageFiles As String(), outputPdfPath As String)
    Using input As New OcrInput()
        For Each file In imageFiles
            input.LoadImage(file)
        Next

        Dim result = New IronTesseract().Read(input)
        result.SaveAsSearchablePdf(outputPdfPath)
    End Using
End Sub
$vbLabelText   $csharpLabel

無需PDF庫。 無需坐標映射。 無需文字層定。 IronOCR中的可搜尋PDF輸出格式將不可見的文字層嵌入到原始圖像上,生成的文件在視覺上忠於掃描文件且完全可搜尋。 可搜尋PDF的做法涵蓋了頁面選擇、質量選項和元資料控制。

PaddleSharp OCR API到IronOCR對應參考

PaddleSharp OCR IronOCR
Sdcb.PaddleOCR(命名空間) IronOcr(命名空間)
Sdcb.PaddleInference(命名空間) 不需要—自動配置
PaddleOcrAll IronTesseract
new PaddleOcrAll(det, cls, rec) new IronTesseract()
LocalFullModels.ChineseV3.DetectionModel 沒有等價物—沒有模型選擇
LocalFullModels.ChineseV3.ClassifierModel 沒有等價物—沒有模型選擇
LocalFullModels.ChineseV3.RecognitionModel 沒有等價物—沒有模型選擇
PaddleConfig.FromModelDir() 沒有等價物—沒有配置物件
config.EnableGpu(memMB, deviceId) 沒有等價物—後端是自動的
config.EnableMkldnn() 沒有等價物—後端是自動的
config.SetCpuMathLibraryNumThreads(n) 沒有等價物—內部管理
Cv2.ImRead(path)(OpenCV載入) input.LoadImage(path)
ocr.Run(mat) ocr.Read(input)ocr.Read("file.jpg")
result.Regions result.Pages[0].Wordsresult.Pages[0].Lines
region.Text word.Text, line.Text, paragraph.Text
region.Rect.Center.X/.Y word.X, word.Y
region.Score(信心) word.Confidence, result.Confidence
模型級語言切換 ocr.Language = OcrLanguage.French
表格模型(單獨下載) 內建結構化結果層次結構
Cv2.CvtColor(..., GRAY) input.Binarize()input.Contrast()
Cv2.GaussianBlur(...) input.DeNoise()
無可搜尋PDF輸出 result.SaveAsSearchablePdf("output.pdf")

常見的遷移問題与解決方案

問題1: OpenCV依賴無法解除安裝

PaddleSharp OCR:OpenCvSharp4.runtime.win和類似的特定平台運行時包安裝未托管的本地DLL。 這些DLL會阻止正確的清理阻止某些託管場景,例如IIS應用程式池回收並且在構建時引用錯誤的平台運行時包導致組件載入失敗。移除它們需要移除NuGet包和清除輸出目錄中的任何已快取本地二進制文件。

解決方案:在解除安裝OpenCvSharp4.runtime.*包後,清理構建輸出目錄並重新構建:

dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
dotnet clean
dotnet build
dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
dotnet clean
dotnet build
SHELL

IronOCR在內部打包了其本地依賴項,並處理未托管的生命週期。 不需要進行平台特定的運行時包選擇。 IronTesseract設置指南記錄了IronOCR自動處理的平台要求。

問題2: 遷移後磁碟上遺留的模型文件

PaddleSharp OCR:Padsharp下載的模型文件(檢測、分類、識別和任何表模型)通常儲存在靠近應用程式的models/目錄中或在配置路徑中。 當解除安裝NuGet包時,這些文件不會被刪除。 在Docker映像中,它們增加了不必要的層大小。在部署管道中,老路徑中的陳舊模型文件可能會導致啟動失敗。

解決方案:遷移時明確刪除模型目錄。 審核啟動配置以檢查任何路徑引用:

# Locate model directory references in application code
grep -r "LocalFullModels\|ModelPath\|models/" --include="*.cs" .
grep -r "DetectionModel\|RecognitionModel\|ClassifierModel" --include="*.cs" .
# Locate model directory references in application code
grep -r "LocalFullModels\|ModelPath\|models/" --include="*.cs" .
grep -r "DetectionModel\|RecognitionModel\|ClassifierModel" --include="*.cs" .
SHELL

在移除模型參考並初始化IronOCR後,從倉庫和Docker構建上下文中刪除模型目錄。

問題3: 單例生命週期假設遷移後中斷

PaddleSharp OCR:註冊為單例因其構建成本使得按需實例化不切實際。 將IronOCR抬升到單例註冊中引入了不必要的跨請求狀態分享。 雖然IronTesseract在並發使用時是執行緒安全的,但不必共享單個實例—每個實例都是獨立的。

解決方案:評估實例的設計是否超過性能: 對於大多數ASP.NET Core應用,使用IronOCR選擇轉瞬即逝的註冊是更為整潔的選擇:

// PaddleSharp — forced singleton due to construction cost
services.AddSingleton<PaddleOcrAll>(sp =>
{
    var det = LocalFullModels.ChineseV3.DetectionModel;  // Simplified
    var cls = LocalFullModels.ChineseV3.ClassifierModel; // Simplified
    var rec = LocalFullModels.ChineseV3.RecognitionModel; // Simplified
    return new PaddleOcrAll(det, cls, rec);
});

//IronOCR— transient works; no expensive construction
services.AddTransient<IronTesseract>();
// PaddleSharp — forced singleton due to construction cost
services.AddSingleton<PaddleOcrAll>(sp =>
{
    var det = LocalFullModels.ChineseV3.DetectionModel;  // Simplified
    var cls = LocalFullModels.ChineseV3.ClassifierModel; // Simplified
    var rec = LocalFullModels.ChineseV3.RecognitionModel; // Simplified
    return new PaddleOcrAll(det, cls, rec);
});

//IronOCR— transient works; no expensive construction
services.AddTransient<IronTesseract>();
Imports Microsoft.Extensions.DependencyInjection

' PaddleSharp — forced singleton due to construction cost
services.AddSingleton(Of PaddleOcrAll)(Function(sp)
    Dim det = LocalFullModels.ChineseV3.DetectionModel ' Simplified
    Dim cls = LocalFullModels.ChineseV3.ClassifierModel ' Simplified
    Dim rec = LocalFullModels.ChineseV3.RecognitionModel ' Simplified
    Return New PaddleOcrAll(det, cls, rec)
End Function)

' IronOCR— transient works; no expensive construction
services.AddTransient(Of IronTesseract)()
$vbLabelText   $csharpLabel

對於想要顯式實例重用的高吞吐量批量場景,單例或池化模式仍然可行—但這是一項性能選擇,而不是正確性要求。

問題4: 不再需要結果區域排序

PaddleSharp OCR:result.Regions按檢測順序返回檢測到的文字區域,這不一定與閱讀順序(從左到右,從上到下)相匹配。 團隊通常在連接區域文字之前按.Rect.Center.X進行排序—幾乎每個PaddleSharp文字提取實現中都出現的模式。 將此模式直接遷移到IronOCR會產生冗餘程式碼。

解決方案:IronOCR預設按閱讀順序返回結果。 刪除排序:

// PaddleSharp — manual reading-order sort required
var text = string.Join("\n", result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X)
    .Select(r => r.Text));

//IronOCR— result.Text is already in reading order; no sort needed
var text = result.Text;

// For word-level access with position, use the structured hierarchy directly
foreach (var word in result.Pages[0].Words)
{
    Console.WriteLine($"{word.Text} at ({word.X},{word.Y})");
}
// PaddleSharp — manual reading-order sort required
var text = string.Join("\n", result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X)
    .Select(r => r.Text));

//IronOCR— result.Text is already in reading order; no sort needed
var text = result.Text;

// For word-level access with position, use the structured hierarchy directly
foreach (var word in result.Pages[0].Words)
{
    Console.WriteLine($"{word.Text} at ({word.X},{word.Y})");
}
Imports System
Imports System.Linq

' PaddleSharp — manual reading-order sort required
Dim text = String.Join(vbLf, result.Regions _
    .OrderBy(Function(r) r.Rect.Center.Y) _
    .ThenBy(Function(r) r.Rect.Center.X) _
    .Select(Function(r) r.Text))

' IronOCR— result.Text is already in reading order; no sort needed
text = result.Text

' For word-level access with position, use the structured hierarchy directly
For Each word In result.Pages(0).Words
    Console.WriteLine($"{word.Text} at ({word.X},{word.Y})")
Next
$vbLabelText   $csharpLabel

問題5: 後端配置包中斷恢復

PaddleSharp OCR:某些PaddleSharp設置根據目標環境(如GPU的CUDA、OpenVINO的MKL、僅限CPU)有條件地引用不同的Sdcb.PaddleInference.runtime.*包。 這有時顯現為.csproj條件或按部署目標分開的項目文件。 錯誤的包集回复會中斷CI管道。

解決方案:在移除PaddleSharp包後,審計PackageReference條件:

grep -n "Sdcb\|OpenCvSharp\|PaddleInference" *.csproj
grep -n "Sdcb\|OpenCvSharp\|PaddleInference" *.csproj
SHELL

IronOCR使用單個IronOcr包引用,無平台條件。 同一個包在Windows、Linux和macOS上都能正確恢復。

問題6: 表結果結構無直接等效

PaddleSharp OCR:PaddleOcrTable 返回基於單元格的結構,每個被識別的單元格有行和列索引。 消費此結構的程式碼通常構建 (row, column) 為索引的二維陣列。 IronOCR没有提供一個相同的單元格索引結構—它提供單詞和線條坐標,這需要進行空間分組以重構單元格網格。

解決方案:從IronOCR單詞坐標中使用Y位置分組構建表格,並排序X位置以形成列。 對於常見的表格格式,表閱讀方法提供了一種空間分組的方法。 對於具有已知字段位置的結構化發票,基於區域的OCRCropRectangle直接模型相比是更乾淨的一種模式。

using IronOcr;

// Target specific table cells by region instead of full-page table detection
var totalAmountRegion = new CropRectangle(400, 600, 200, 30); // x, y, width, height
using var input = new OcrInput();
input.LoadImage("invoice.jpg", totalAmountRegion);

var result = new IronTesseract().Read(input);
Console.WriteLine($"Total: {result.Text}");
using IronOcr;

// Target specific table cells by region instead of full-page table detection
var totalAmountRegion = new CropRectangle(400, 600, 200, 30); // x, y, width, height
using var input = new OcrInput();
input.LoadImage("invoice.jpg", totalAmountRegion);

var result = new IronTesseract().Read(input);
Console.WriteLine($"Total: {result.Text}");
Imports IronOcr

' Target specific table cells by region instead of full-page table detection
Dim totalAmountRegion As New CropRectangle(400, 600, 200, 30) ' x, y, width, height
Using input As New OcrInput()
    input.LoadImage("invoice.jpg", totalAmountRegion)

    Dim result = New IronTesseract().Read(input)
    Console.WriteLine($"Total: {result.Text}")
End Using
$vbLabelText   $csharpLabel

PaddleSharp OCR遷移清單

遷移前

掃瞄程式碼庫中用的所有 PaddleSharp 參考文獻,然後再移除包:

# Find all PaddleSharp and PaddleInference usages
grep -rn "Sdcb\.PaddleOCR\|Sdcb\.PaddleInference" --include="*.cs" .

# Find OpenCV usages that will need replacement
grep -rn "OpenCvSharp\|Cv2\.\|using var.*Mat\b" --include="*.cs" .

# Find model path references and configuration
grep -rn "LocalFullModels\|ModelDir\|DetectionModel\|RecognitionModel\|ClassifierModel" --include="*.cs" .

# Find backend selection logic
grep -rn "EnableGpu\|EnableMkldnn\|PaddleConfig\|SetCpuMath" --include="*.cs" .

# Find table recognition usages
grep -rn "PaddleOcrTable\|TableModel\|table.*ocr\|ocr.*table" --include="*.cs" .

# Find result region access patterns that need updating
grep -rn "\.Regions\b\|Rect\.Center\|region\.Text" --include="*.cs" .
# Find all PaddleSharp and PaddleInference usages
grep -rn "Sdcb\.PaddleOCR\|Sdcb\.PaddleInference" --include="*.cs" .

# Find OpenCV usages that will need replacement
grep -rn "OpenCvSharp\|Cv2\.\|using var.*Mat\b" --include="*.cs" .

# Find model path references and configuration
grep -rn "LocalFullModels\|ModelDir\|DetectionModel\|RecognitionModel\|ClassifierModel" --include="*.cs" .

# Find backend selection logic
grep -rn "EnableGpu\|EnableMkldnn\|PaddleConfig\|SetCpuMath" --include="*.cs" .

# Find table recognition usages
grep -rn "PaddleOcrTable\|TableModel\|table.*ocr\|ocr.*table" --include="*.cs" .

# Find result region access patterns that need updating
grep -rn "\.Regions\b\|Rect\.Center\|region\.Text" --include="*.cs" .
SHELL

清點磁片中的模型文件並記下其路徑。 清點所有部署目標及是否有GPU或OpenVINO特定的NuGet扣押在.csproj中。 註記由於PaddleSharp構建成本而註冊為單例的任何服務。

程式碼遷移

  1. 從每個項目文件中移除所有OpenCvSharp4.runtime.* NuGet包。
  2. 安裝IronOcr NuGet包。
  3. 為所需語言安裝語言NuGet包(例如,IronOcr.Languages.ChineseSimplified)。
  4. IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";新增到應用啟動。
  5. 將所有using IronOcr
  6. PaddleOcrAll實例化和模型載入。
  7. 刪除所有PaddleConfig後端選擇區塊(CPU、GPU、OpenVINO條件)。
  8. 使用input.LoadImage(path)
  9. 利用Threshold等)。
  10. ocr.Run(mat)呼叫。
  11. result.Regions枚舉。
  12. 刪除.OrderBy(r => r.Rect.Center.Y).ThenBy(r => r.Rect.Center.X)排序鏈-閱讀順序是自動的。
  13. PaddleOcrTable初始化和結果解析。
  14. 在任何需要可搜尋PDF存檔的地方新增result.SaveAsSearchablePdf(path)
  15. 重新評估服務生命週期註冊:因PaddleSharp構建成本驅動的單例註冊通常可以成為過渡或範圍。
  16. 從磁片刪除模型文件,並從Docker構建上下文中移除模型目錄。
  17. 移除任何類似於.csproj的平台特定 Paddle 或 OpenCV 運行時包的條件PackageReference區塊。

遷移後

  • 驗證文字提取輸出是否匹配或超過代表性樣本的PaddleSharp輸出,從每個文件管道型別中取樣20–30個文件。
  • 確認未發現與OpenCvSharp相關的組件載入異常於應用啟動日誌中。
  • 使用相同的構建工件測試每個目標平台上的部署(Windows、Linux、Docker)— 不應需要平台特定的包選擇。
  • 驗證先前需要手動結果排序的文件使用result.Text生產正確排序的文字。
  • 確認可搜尋PDF輸出文件在Adobe Acrobat Reader或您選擇的PDF查看器中是文字可搜尋的。
  • 在負載下運行應用,確認PaddleOcrAll構建相當的記憶壓力。
  • 驗證作為NuGet包安裝的語言包在CI中正確恢復,無需額外的文件部署步驟。
  • 使用區域基於或坐標分組方法測試任何表格提取場景是否符合預期的行/列結構。
  • 確認在消除PaddleOcrAll單例構建後應用啟動時間有所減少。

遷移至IronOCR的主要好處

一個包取代四個包棧。 遷移後,OCR依賴包只需單一IronOcr NuGet引用。 四個包棧—OpenCvSharp4和一個平台專用運行時—成為項目文件中的一個條目。現在,同一個面板覆蓋依賴性審核、許可證掃描和漏洞檢測工作,而不是四重。

部署工件在不同環境中是統一的。 後端選擇條件—CPU對比GPU對比OpenVINO—已消失。 相同的構建工件部署到開發者筆記型電腦、CI執行器、Linux容器和雲VM,無需進行環境專享的包選擇或初始化分支。 因為沒有要COPY的模型文件,也沒有需要安裝的運行時平台包,所以Docker映像縮小了。

文件存檔管道不再需要第二個庫。 result.SaveAsSearchablePdf()消除了大多數PaddleSharp團隊使用的PDF庫依賴,以生成可以搜尋的存檔。 OCR遍及和可搜尋PDF寫入是單次API調用。 對於每天處理數千個掃描文件的團隊來說,這種簡化消除了一整類的庫間版本衝突。 可搜尋PDF部落格文章涵蓋了生產規模的考慮因素。

服務生命週期決策反映了應用程式需求,而不是庫限制。 IronTesseract建設輕量。 PaddleSharp昂貴的模型載入驅動的單一模式不再必要。 服務可以在ASP.NET Core中按每次請求來設置範圍,創造更乾淨的並發使用者隔離,消除共享狀態的執行緒關注。 有關更多部署選項,請參閱ASP.NET OCR使用案例頁面。

語言擴展是一個包安裝,而不是研究項目。 125+語言目錄 涵蓋歐洲、亞洲、中東和特殊字元集,作為NuGet包提供。 在最初僅支持中文的管道中新增法語、德語、阿拉伯語或日語是dotnet add package IronOcr.Languages.French和一行配置。無需模型文件攝取、上游研究、手動文件部署。

預處理是OCR API的一部分。 PaddleSharp預處理所需的OpenCV知識—理解過濾器內核、管理Mat釋放、選擇自適性閾值參數—不再是OCR工作的前提。 OcrInput提供具有合理預設值的命名操作。 不是OpenCV專家但不斷維持OpenCV預處理程式碼的團隊可以刪除這些程式碼而不替換它。 預處理功能頁面列出了每個可用過濾器,並附有何時應用每個過濾器的文件。

請注意Adobe Acrobat、PaddleOCR和Tesseract是其各自所有者的註冊商標。 此網站與Adobe Inc.、百度、谷歌或PaddlePaddle無關,也未經其認可或贊助。 所有產品名稱、標誌和品牌均為其各自所有者的財產。 比較僅供資訊用途,並反映撰寫時獲得的公開資訊。

常見問題

為什麼我應該從PaddleSharp OCR遷移到IronOCR?

常見的驅動因素包括消除COM互操作複雜性、更換基於文件的許可證管理、避免按頁收費、啟用Docker/容器部署,以及採取與標準.NET工具整合的NuGet本地工作流。

從PaddleSharp OCR遷移到IronOCR的主要程式碼變更有哪些?

用IronTesseract實例化替換PaddleSharp初始化序列,移除COM生命週期管理(顯式Create/Load/Close模式),並更新結果屬性名稱。結果是顯著減少了樣板程式碼行數。

如何安裝IronOCR以開始遷移?

在套件管理器控制台中運行 'Install-Package IronOcr' 或在CLI中運行 'dotnet add package IronOcr'。語言包是單獨的包:例如 'dotnet add package IronOcr.Languages.French' 安裝法語支持。

IronOCR是否匹配PaddleSharp OCR在標準商業文件中的OCR準確性?

IronOCR在包括發票、合同、收據和鍵入的表單等標準業務內容上達到高準確性。圖像預處理過濾器(糾偏、噪音去除、對比度增強)進一步提高了變質輸入的識別。

IronOCR如何處理PaddleSharp OCR單獨安裝的語言資料?

IronOCR中的語言資料分發為NuGet包。'dotnet add package IronOcr.Languages.German' 安裝德語支持。不涉及手動文件放置或目錄路徑。

從PaddleSharp OCR遷移到IronOCR是否需要更改部署基礎設施?

IronOCR需要的基礎設施更改比PaddleSharp OCR少。沒有SDK二進制路徑、授權文件擺放或授權伺服器配置。NuGet包包含完整的OCR引擎,授權金鑰是應用程式程式碼中設定的字串。

遷移後如何配置IronOCR許可證?

在應用啟動程式碼中分配IronOcr.License.LicenseKey = "YOUR-KEY"。在Docker或Kubernetes中,將金鑰儲存為環境變數並在啟動時讀取。在接受流量之前,使用License.IsValidLicense驗證。

IronOCR能否以PaddleSharp相同的方式處理PDF?

是的。IronOCR能讀取本地和掃描的PDF。實例化IronTesseract,調用ocr.Read(input),其中input是PDF路徑或OcrPdfInput,並迭代OcrResult頁面。不需要單獨的PDF渲染管道。

IronOCR如何處理大批量處理中的多執行緒?

IronTesseract可以安全地在每個執行緒中實例化。在Parallel.ForEach或Task池中為每個執行緒建立一個實例,並發併運行OCR,當完成時處置每個實例。不需要全域狀態或鎖定。

IronOCR在文字提取後支持哪些輸出格式?

IronOCR返回結構化結果,包括文字、單詞坐標、信心分數和頁面結構。導出選項包括純文字、可搜索PDF以及下游處理的結構化結果物件。

IronOCR的定價是否比PaddleSharp OCR在工作負載擴展時更具可預測性?

IronOCR使用固定費率的永久性許可證,沒有按頁或按量收費。無論您處理10000頁還是1000萬頁,許可證費用保持不變。團隊和批量許可證選項可在IronOCR定價頁面上找到。

從PaddleSharp OCR遷移到IronOCR後,我現有的測試會發生什麼變化?

遷移後,斷言提取的文字內容的測試應繼續通過。需要更新的測試是驗證API調用模式或COM物件生命週期,這需要反映IronOCR較簡單的初始化和結果模型。

Kannaopat Udonpant
軟體工程師
在成為軟體工程師之前,Kannapat在日本北海道大學完成了環境資源博士學位。在攻讀學位期間,Kannapat還成為車輛機器人實驗室的一員,該實驗室隸屬於生產工程系。在2022年,他憑藉C#技能加入了Iron Software的工程團隊,專注於IronPDF。Kannapat珍視他的工作,因為他能直接向撰寫大部分IronPDF程式碼的開發者學習。除了同儕學習,Kannapat還喜歡在Iron Software工作的社交方面。不寫程式碼或文件時,Kannapat通常在他的PS5上玩遊戲或重看The Last of Us。

Iron 支援團隊

我們線上24小時,每週5天。
聊天
電子郵件
給我打電話