Przejdź do treści stopki
FILMY

Jak odczytywać pliki GIF i TIFF z wieloma ramkami w języku C#

Ten przewodnik prowadzi programistów .NET przez pełną migrację zPaddleSharp OCR(Sdcb.PaddleOCR) na IronOCR. Obejmuje to zastąpienie zarządzania sesjami wnioskowania, wyeliminowanie zależności od przetwarzania wstępnego OpenCV, usunięcie logiki wyboru zaplecza dla procesorów CPU, GPU i OpenVINO oraz migrację procesów rozpoznawania tabel. Każda sekcja zawiera kod przed i po przetworzeniu, zaczerpnięty z wzorców specyficznych dla PaddleSharp, które nie pojawiają się w ogólnych porównaniach OCR.

Dlaczego warto przejść z PaddleSharp OCR

PaddleSharp udostępnia potok wnioskowania oparty na głębokim uczeniu się na poziomie warstwy aplikacji. Architektura ta zapewnia dostęp do wydajności modeli PaddlePaddle, ale wymaga, aby aplikacja zarządzała kwestiami, które w innym przypadku należałyby do infrastruktury. Następujące problemy skłaniają większość zespołów .NET do poszukiwania alternatyw.

Konfiguracja Backend Inference to kod aplikacji. Wybór między backendami CPU, GPU i OpenVINO w PaddleSharp wymaga konstrukcji i konfiguracji obiektów PaddleConfig, wybrania odpowiedniego pakietu NuGet dla natywnego środowiska uruchomieniowego na docelową platformę wdrożeniową oraz warunkowego rozgałęzienia kodu inicjalizacyjnego w zależności od dostępnego sprzętu podczas uruchamiania. Ta logika znajduje się w aplikacji, a nie w bibliotece, i przestaje działać, gdy zmienia się docelowe środowisko.

OpenCV jest wymaganym elementem zależności dla danych wejściowych obrazu. PaddleSharp nie może bezpośrednio akceptować ścieżki pliku ani strumienia. Każdy obraz przechodzi przez Cv2.ImRead() OpenCV zanim dotrze do silnika OCR. To wymusza OpenCvSharp4 oraz specyficzny dla platformy pakiet OpenCvSharp4.runtime.* do grafu zależności. Aktualizacja środowiska uruchomieniowego jednej platformy bez aktualizacji drugiej powoduje awarie środowiska uruchomieniowego, które trudno odtworzyć w różnych środowiskach.

Żywotność sesji inferencji wymaga wyraźnego projektowania. PaddleOcrAll ładuje trzy binaria modelu z dysku przy konstrukcji. Ten koszt — mierzony w setkach milisekund — oznacza, że obiekt nie może być instancjonowany per-żądanie. Zespoły muszą zaprojektować strategię cyklu życia: singleton, puli, lub zakres. W ASP.NET Core zazwyczaj oznacza to zarejestrowaną usługę z dokładną analizą bezpieczeństwa wątków, ponieważ PaddleOcrAll dzieli się podstawowym stanem natywnym.

Rozpoznawanie tabel wymaga pobrania oddzielnych modeli. Ekstrakcja dokumentów strukturalnych w PaddleSharp wymaga dedykowanego modelu rozpoznawania tabel oprócz standardowego trzyetapowego procesu wykrywania/klasyfikacji/rozpoznawania. Model ten jest czwartym plikiem, który należy pobrać, zaktualizować i skonfigurować. Nie ma ujednoliconego interfejsu API — rozpoznawanie tabel wykorzystuje odrębną ścieżkę kodu z własnym typem wyniku.

Brak możliwości tworzenia plików PDF z funkcją wyszukiwania. PaddleSharp generuje ciągi tekstowe. Nie może tworzyć plików PDF z możliwością wyszukiwania. Zespoły, które muszą archiwizować zeskanowane dokumenty jako pliki PDF z możliwością wyszukiwania tekstu, muszą zintegrować oddzielną bibliotekę PDF, zarządzać tą dodatkową zależnością i napisać warstwę konwersji. Luka w formacie wyjściowym jest całkowita: brak hOCR, brak strukturalnego, przeszukiwalnego pliku PDF, brak nakładki warstwy tekstowej.

Łańcuch zależności upstream nie jest własnością społeczności .NET. PaddleSharp stanowi nakładkę na framework wnioskowania PaddlePaddle firmy Baidu. Zmiany formatu modelu między wersjami PaddleOCR spowodowały w przeszłości uszkodzenie warstwy powiązania .NET. Większość działań związanych ze śledzeniem problemów, dokumentacją i dyskusjami na temat wydań odbywa się w języku chińskim. Dla zespołu .NET, w którym nie ma osób posługujących się językiem mandaryńskim monitorujących projekty nadrzędne, przełomowe zmiany pojawiają się bez ostrzeżenia.

Podstawowy problem

Wybór i inicjalizacja backendu w PaddleSharp wymaga kodu konfiguracyjnego, który należy do infrastruktury, a nie do logiki 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: Nie backend selection. Nie 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: Nie backend selection. Nie 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: Nie backend selection. Nie 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 a PaddleSharp OCR: porównanie funkcji

Oto bezpośrednie porównanie możliwości w wymiarach, które mają największe znaczenie podczas migracji:

Funkcja PaddleSharp OCR IronOCR
Wymagane pakiety NuGet Minimum 3–4 1
Metoda wprowadzania obrazów OpenCV Cv2.ImRead() Ścieżka bezpośrednia, strumień lub tablica bajtów
Wejście PDF (natywne) Nie Tak
Plik PDF chroniony hasłem Nie Tak
Wielostronicowy plik TIFF Za pośrednictwem OpenCV Język ojczysty
Wynik w formacie PDF z możliwością wyszukiwania Nie Tak (result.SaveAsSearchablePdf())
eksport hOCR Nie Tak
Wybór zaplecza (CPU/GPU/OpenVINO) Ręczny PaddleConfig Automatyczne
Potok przetwarzania wstępnego Ręczne operacje OpenCV Wbudowany (Deskew, DeNoise, Contrast, itd.)
Zarządzanie cyklem życia sesji wnioskowania Podręcznik (kosztowna konstrukcja) Lekki IronTesseract
Model rozpoznawania tabel Oddzielna ścieżka pobierania i kodu input.LoadImage() + uporządkowany wynik
Obsługiwane języki ~10–20 125+
Instalacja języka Pobierz plik wzorcowy Pakiet NuGet
Wielojęzyczne tłumaczenie symultaniczne Ograniczone Tak (OcrLanguage.French + OcrLanguage.German)
OCR oparte na regionie Brak wbudowanych CropRectangle
Odczytywanie BarCode podczas OCR Nie Tak (ocr.Configuration.ReadBarCodes = true)
Wyniki pewności W podziale na regiony Za słowo, za wiersz, za stronę
Strukturalna hierarchia wyników Lista regionów płaskich Strony → Akapity → Wiersze → Słowa → Znaki
Wdrażanie wielopłatformowe Złożone (pakiety środowiska uruchomieniowego platformy) Pojedynczy pakiet NuGet, wszystkie platformy
Wdrożenie Docker Wiele warstw, pakiety uruchomieniowe Pojedyncza warstwa
Wsparcie komercyjne Zgłoszenia na GitHubie (głównie w języku chińskim) Wsparcie e-mail
Model licencji Apache 2.0 Wieczysty ($999 Lite, 1 499 $ Pro, 2 999 $ Enterprise)

Szybki start: Migracja zPaddleSharp OCRdo IronOCR

Krok 1: Zastąp pakiet NuGet

Usuń PaddleSharp i jego zależność od 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

Zainstaluj IronOCR z NuGet:

dotnet add package IronOcr

Krok 2: Aktualizacja przestrzeni nazw

Zastąp przestrzenie nazw PaddleSharp pojedynczą przestrzenią nazw IronOCR:

// 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

Krok 3: Inicjalizacja licencji

Dodaj inicjalizację licencji raz podczas uruchamiania aplikacji — w Program.cs, Startup.cs, lub w korzeniu kompozycji:

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

Przykłady migracji kodu

Wymiana cyklu życia sesji wnioskowania

Konstrukcja PaddleOcrAll PaddleSharp jest kosztowna, ponieważ ładuje trzy binaria modelu synchronicznie przy instancji. Aplikacje produkcyjne muszą traktować go jako obiekt długotrwały, co determinuje konkretny wzorzec wstrzykiwania zależności. Należy również zwrócić uwagę na łańcuch usuwania, ponieważ podstawowe zasoby natywne muszą być zwalniane we właściwej kolejności.

Podejście 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

Podejście 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

Shift od wymuszonego singletonu do elastycznego cyklu życia jest znaczące. Koszt budowy PaddleSharp determinuje decyzję dotyczącą okresu eksploatacji usługi;IronOCR pozwala dokonać wyboru w oparciu o wymagania aplikacji dotyczące wielowątkowości i izolacji żądań. Podręcznik konfiguracji IronTesseract obejmuje opcje konfiguracyjne, które mają zastosowanie na poziomie instancji.

Migracja potoku przetwarzania wstępnego OpenCV

Zespoły korzystające z PaddleSharp w przypadku skanów o niskiej jakości zazwyczaj tworzą potok przetwarzania wstępnego OpenCV przed uruchomieniem silnika OCR. Potok ten wymaga znajomości interfejsu API OpenCV, który jest znacznie większy niż to, czego faktycznie wymaga jakiekolwiek zadanie przetwarzania wstępnego OCR. Typowe operacje — deskew, denoise, rozciąganie kontrastu — wymagają wielu operacji Mat i dokładnego zarządzania pamięcią z użyciem bloków using, aby zapobiec wyciekom pamięci natywnej.

Podejście 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

Podejście 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

Brak przydziałów Mat. Brak wiedzy na temat parametrów progu adaptacyjnego. Bez niestandardowych obliczeń matematycznych dotyczących obracania w celu wyprostowania. Ten sam proces przetwarzania wstępnego, który wymagał 30–50 linii kodu OpenCV, sprowadza się teraz do czterech wywołań metod. Przewodnik po korekcji jakości obrazu dokumentuje każdy dostępny filtr wraz z przykładami przed i po. Dla dokumentów z dużym szumem tła, input.DeepCleanBackgroundNoise() idzie dalej niż DeNoise() bez żadnych dodatkowych parametrów.

Dla zespołów, których wymagania dotyczące przetwarzania wstępnego są niestandardowe, kreator filtrów zapewnia interaktywne narzędzie do oceny kombinacji filtrów na konkretnych typach dokumentów przed zatwierdzeniem kodu.

Eliminacja wyboru backendu

PaddleSharp udostępnia backend wnioskowania jako element na poziomie aplikacji. Wdrożenie, które musi działać na maszynie wirtualnej w chmurze wyposażonej wyłącznie w procesor, wykorzystuje inny kod inicjalizacyjny niż to przeznaczone dla stacji roboczej z procesorem graficznym lub urządzenia brzegowego obsługującego Intel OpenVINO. Ta logika warunkowa zazwyczaj znajduje się w kodzie uruchamiającym aplikację, sprawdzaniu zmiennych środowiskowych lub flagach funkcji — czyli w elementach infrastruktury, które nie mają nic wspólnego z odczytywaniem tekstu z obrazów.

Podejście 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

Podejście IronOCR:

using IronOcr;

// Nie backend selection. Nie switch statement. Nie 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;

// Nie backend selection. Nie switch statement. Nie 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

    ' Nie backend selection. Nie switch statement. Nie 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

Wzorzec Parallel.ForEach tutaj jest wątkowo-bezpieczny prosto z pudełka. Każda instancja IronTesseract jest niezależna i nie współdzieli stanu natywnego. Dla zespołów, których wdrożenie PaddleSharp wymaga poświęcania czasu na zarządzanie warunkami backendowymi, uproszczenie to oznacza również poprawę niezawodności wdrożenia — ten sam artefakt kompilacji działa wszędzie bez kodu wykrywającego sprzęt. Przewodnik po optymalizacji szybkości obejmuje opcje konfiguracyjne dla scenariuszy, w których ważna jest przepustowość.

Migracja rozpoznawania tabel

Wyodrębnianie tabel w PaddleSharp wymaga dedykowanego modelu rozpoznawania tabel — czwartego pliku modelu, wykraczającego poza standardowy zestaw wykrywania, klasyfikacji i rozpoznawania. Model tabelowy wykorzystuje oddzielne wywołanie API i zwraca własną strukturę wyników. Zespoły tworzące potoki przetwarzania faktur, formularzy lub arkuszy kalkulacyjnych utrzymują dwie równoległe ścieżki inicjalizacji i dwie strategie analizowania wyników.

Podejście 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

Podejście 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

W przypadku dokumentów, w których sama struktura tabeli musi zostać wyodrębniona jako wiersze i kolumny,IronOCR zapewnia dedykowaną funkcję wyodrębniania tabel:

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

Usunięto jedno pobranie modelu. Wyeliminowano jedną ścieżkę inicjalizacji. Strukturalna hierarchia wyników w IronOCR— z współrzędnymi X/Y na poziomie słów — zapewnia dane pozycyjne potrzebne do odtworzenia wierszy i kolumn tabeli bez oddzielnego modelu rozpoznawania. Przewodnik po odczytywaniu tabeli oraz przewodnik po wynikach odczytu obejmują pełny, ustrukturyzowany interfejs API.

Wyszukiwalny plik PDF z zeskanowanych dokumentów

PaddleSharp generuje ciągi tekstowe i nic więcej. Stworzenie archiwum dokumentów, w którym zeskanowane pliki PDF umożliwiają wyszukiwanie tekstu, wymaga zintegrowania oddzielnej biblioteki PDF, napisania warstwy nakładki tekstowej oraz współdziałania dwóch bibliotek. Zespoły, które zaakceptowały to ograniczenie, często uznają je za czynnik decydujący o migracji — wysiłek związany z integracją dwóch bibliotek przewyższa wysiłek związany ze zmianą dostawcy usług OCR.

Podejście 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

Podejście 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

Brak biblioteki PDF. Bez mapowania współrzędnych. Brak pozycjonowania warstw tekstowych. Format wyjściowy PDF z możliwością wyszukiwania w IronOCR osadza niewidoczną warstwę tekstową na oryginalnym obrazie, tworząc plik, który jest zarówno wierny wizualnie zeskanowanemu dokumentówi, jak i w pełni przeszukiwalny pod kątem tekstu. Poradnik w formacie PDF z funkcją wyszukiwania obejmuje wybór stron, opcje jakości oraz kontrolę metadanych.

Odnośnik do dokumentacji APIPaddleSharp OCRdo IronOCR

PaddleSharp OCR IronOCR
Sdcb.PaddleOCR (namespace) IronOcr (namespace)
Sdcb.PaddleInference (namespace) Nie jest wymagane — konfiguracja automatyczna
PaddleOcrAll IronTesseract
new PaddleOcrAll(det, cls, rec) new IronTesseract()
LocalFullModels.ChineseV3.DetectionModel Brak odpowiednika — brak wyboru modelu
LocalFullModels.ChineseV3.ClassifierModel Brak odpowiednika — brak wyboru modelu
LocalFullModels.ChineseV3.RecognitionModel Brak odpowiednika — brak wyboru modelu
PaddleConfig.FromModelDir() Brak odpowiednika — brak obiektu konfiguracyjnego
config.EnableGpu(memMB, deviceId) Brak odpowiednika — backend jest automatyczny
config.EnableMkldnn() Brak odpowiednika — backend jest automatyczny
config.SetCpuMathLibraryNumThreads(n) Brak odpowiednika — zarządzane wewnętrznie
Cv2.ImRead(path) (OpenCV load) input.LoadImage(path)
ocr.Run(mat) ocr.Read(input) lub ocr.Read("file.jpg")
result.Regions result.Pages[0].Words lub result.Pages[0].Lines
region.Text word.Text, line.Text, paragraph.Text
region.Rect.Center.X/.Y word.X, word.Y
region.Score (confidence) word.Confidence, result.Confidence
Zmiana języka na poziomie modelu ocr.Language = OcrLanguage.French
Model tabelaryczny (do pobrania osobno) Wbudowana hierarchia wyników strukturalnych
Cv2.CvtColor(..., GRAY) input.Binarize() lub input.Contrast()
Cv2.GaussianBlur(...) input.DeNoise()
Brak możliwości wyszukiwania w pliku PDF result.SaveAsSearchablePdf("output.pdf")

Typowe problemy związane z migracją i ich rozwiązania

Problem 1: Nieudane wyładowanie zależności OpenCV

PaddleSharp OCR: OpenCvSharp4.runtime.win i podobne specyficzne dla platformy pakiety uruchomieniowe instalują nienadzorowane natywne biblioteki DLL. Te biblioteki DLL mogą uniemożliwić prawidłowe czyszczenie w niektórych scenariuszach hostingu — w szczególności podczas recyklingu puli aplikacji IIS — i powodować błędy ładowania zestawów, gdy w czasie kompilacji odwołuje się do niewłaściwego pakietu środowiska uruchomieniowego platformy. Ich usunięcie wymaga zarówno usunięcia pakietu NuGet, jak i wyczyszczenia wszelkich buforowanych plików binarnych w katalogu wyjściowym.

Rozwiązanie: Po usunięciu pakietów OpenCvSharp4 oraz OpenCvSharp4.runtime.*, wyczyść katalog wyjściowy build przed ponownym zbudowaniem:

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 wewnętrznie łączy swoje natywne zależności i obsługuje niezarządzany cykl życia. Nie jest wymagany wybór pakietu uruchomieniowego specyficznego dla danej platformy. Podręcznik konfiguracji IronTesseract zawiera informacje o wymaganiach platformy, które IronOCR obsługuje automatycznie.

Problem 2: Pliki modeli pozostawione na dysku po migracji

PaddleSharp OCR: Pliki modeli pobrane przez PaddleSharp (wykrywanie, klasyfikacja, rozpoznawanie oraz wszelkie modele tabel) są zazwyczaj przechowywane w katalogu models/ względnym do aplikacji lub w skonfigurowanej ścieżce. Pliki te nie są usuwane po odinstalowaniu pakietu NuGet. W obrazie Docker zwiększają one niepotrzebnie rozmiar warstwy. W potoku wdrażania nieaktualne pliki modeli znajdujące się w starych ścieżkach mogą powodować błędy uruchamiania, jeśli jakikolwiek pozostały kod inicjalizacyjny odwołuje się do nich.

Rozwiązanie: Wyraźnie usuń katalogi modeli w ramach migracji. Sprawdź konfigurację startową pod kątem wszelkich odniesień do ścieżek:

# 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

Po usunięciu odniesień do modeli i zainicjowaniu IronOCR należy usunąć katalog modelu z repozytorium i kontekstu kompilacji Docker.

Problem 3: Założenie dotyczące czasu życia singletonu przestaje obowiązywać po migracji

PaddleSharp OCR: PaddleOcrAll był zarejestrowany jako singleton, ponieważ koszt jego konstrukcji sprawiał, że instancjonowanie per-żądanie było niepraktyczne. Kod migracyjny, który przenosi IronOCR do tej samej rejestracji singletonowej, wprowadza niepotrzebne współdzielenie stanu między żądaniami. Podczas gdy IronTesseract jest wątkowo-bezpieczny, gdy jest używany równocześnie, nie ma potrzeby udostępniać jednej instancji — każda instancja jest niezależna.

Rozwiązanie: Należy ocenić, czy rejestracja singletonów służy celom wykraczającym poza wydajność. W przypadku większości aplikacji ASP.NET Core rejestracja tymczasowa jest lepszym wyborem w przypadku 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

W scenariuszach przetwarzania wsadowego o dużej przepustowości, w których wymagane jest wyraźne ponowne wykorzystanie instancji, wzorzec singleton lub wzorzec puli nadal działa — jest to jednak wybór związany z wydajnością, a nie wymóg poprawności.

Problem 4: Kolejność regionów wyników nie jest już wymagana

PaddleSharp OCR: result.Regions zwraca wykryte regiony tekstowe w kolejności wykrycia, która niekoniecznie odpowiada kolejności czytania (od lewej do prawej, z góry do dołu). Zespoły zazwyczaj stosują sortowanie według .Rect.Center.Y, a następnie .Rect.Center.X zanim połączą tekst regionu — wzorzec ten pojawia się w prawie każdym wdrożeniu ekstrakcji tekstu PaddleSharp. Dosłowne przeniesienie tego wzorca do IronOCR powoduje powstanie zbędnego kodu.

Rozwiązanie:IronOCR domyślnie zwraca wyniki w kolejności odczytu. Usuń sortowanie:

// 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

Problem 5: Przywracanie uszkodzonych pakietów zależnych od backendu

PaddleSharp OCR: Niektóre konfiguracje PaddleSharp warunkowo odwołują się do różnych pakietów Sdcb.PaddleInference.runtime.* w zależności od docelowego środowiska (CUDA dla GPU, MKL dla OpenVINO, tylko CPU). Czasami pojawia się to jako warunki .csproj lub jako oddzielne pliki projektu na docelowe wdrożenie. Powstała w ten sposób macierz kompilacji powoduje przerwanie działania potoków CI, gdy przywracany jest niewłaściwy zestaw pakietów.

Rozwiązanie: Po usunięciu pakietów PaddleSharp, przeprowadź audyt pliku .csproj dla warunkowych bloków PackageReference odwołujących się do jakichkolwiek pakietów Sdcb.* lub OpenCvSharp* i usuń je całkowicie:

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

IronOCR używa pojedynczego odniesienia do pakietu IronOcr bez warunków platformowych. Ten sam pakiet działa poprawnie w systemach Windows, Linux i macOS.

Problem 6: Struktura wyników tabeli nie ma bezpośredniego odpowiednika

PaddleSharp OCR: PaddleOcrTable zwraca strukturę opartą na komórkach z indeksami wierszy i kolumn dla każdej rozpoznanej komórki. Kod, który konsumuje tę strukturę, zazwyczaj buduje dwuwymiarową tablicę indeksowaną przez (row, column).IronOCR nie zapewnia identycznej struktury indeksu komórek — dostarcza współrzędne słów i wierszy, które wymagają grupowania przestrzennego w celu odtworzenia siatki komórek.

Rozwiązanie: Odtworzyć strukturę tabeli na podstawie współrzędnych słów z IronOCR, stosując grupowanie według pozycji Y dla wierszy i sortowanie według pozycji X dla kolumn. W przypadku popularnych formatów tabel instrukcja czytania tabel przedstawia podejście oparte na grupowaniu przestrzennym. Dla ustrukturyzowanych faktur z znanymi pozycjami pól, regionowe OCR z CropRectangle jest czystszym wzorcem niż pełne wyodrębnianie tabeli na stronie:

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

Lista kontrolna migracji PaddleSharp OCR

Przed migracją

Przed usunięciem pakietów sprawdź wszystkie odwołania do PaddleSharp w kodzie źródłowym:

# 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

Zrób spis plików modeli na dysku i zanotuj ich ścieżki. Zinwentaryzuj wszystkie docelowe wdrożenia i czy jakiekolwiek mają specyficzne dla GPU lub OpenVINO warunki NuGet w .csproj. Należy zwrócić uwagę na usługi zarejestrowane jako singletony ze względu na koszt konstrukcji PaddleSharp.

Migracja kodu

  1. Usuń wszystkie pakiety NuGet Sdcb.PaddleOCR, Sdcb.PaddleInference, OpenCvSharp4 i OpenCvSharp4.runtime.* ze wszystkich plików projektów.
  2. Zainstaluj pakiet NuGet IronOcr.
  3. Zainstaluj pakiety językowe NuGet dla wymaganych języków (np. IronOcr.Languages.ChineseSimplified).
  4. Dodaj IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; do uruchamiania aplikacji.
  5. Zastąp wszystkie instrukcje using Sdcb.PaddleOCR, using Sdcb.PaddleInference, i using OpenCvSharp z using IronOcr.
  6. Zastąp instancjonowanie i ładowanie modelu PaddleOcrAll z new IronTesseract().
  7. Usuń wszystkie bloki wyboru backendu PaddleConfig (warunki CPU, GPU, OpenVINO).
  8. Zastąp wywołania Cv2.ImRead(path) używając input.LoadImage(path) i OcrInput.
  9. Zastąp operacje przedprzetwarzania OpenCV (CvtColor, GaussianBlur, Threshold, itp.) metodami filtrów OcrInput (Deskew(), DeNoise(), Contrast(), Binarize()).
  10. Zastąp wywołania ocr.Run(mat) z ocr.Read(input).
  11. Zastąp enumerację result.Regions z result.Pages, result.Pages[n].Lines, lub result.Pages[n].Words.
  12. Usuń łańcuchy sortowania .OrderBy(r => r.Rect.Center.Y).ThenBy(r => r.Rect.Center.X) — kolejność czytania jest automatyczna.
  13. Zastąp inicjalizację i parsowanie wyników PaddleOcrTable z ukierunkowaniem na region lub grupowaniem słów za pomocą współrzędnych.
  14. Dodaj result.SaveAsSearchablePdf(path) wszędzie tam, gdzie wymagane jest archiwum przeszukiwalne PDF.
  15. Ponowna ocena rejestracji na cały okres użytkowania usługi: rejestracje singletonów oparte na kosztach konstrukcji PaddleSharp mogą zazwyczaj stać się przejściowe lub ograniczone zakresem.
  16. Usuń pliki modeli z dysku i usuń katalogi modeli z kontekstów kompilacji Docker.
  17. Usuń wszystkie warunkowe bloki .csproj dla specyficznych dla platformy Paddle lub OpenCV pakietów uruchomieniowych.

Po migracji

  • Sprawdź, czy wyniki ekstrakcji tekstu są zgodne z wynikami PaddleSharp lub je przewyższają na reprezentatywnej próbie 20–30 dokumentów z każdego typu dokumentu w potoku.
  • Potwierdź brak żadnych wyjątków ładowania zestawów związanych z OpenCvSharp w logach startowych aplikacji.
  • Przetestuj wdrożenie na każdej platformie docelowej (Windows, Linux, Docker) przy użyciu tego samego artefaktu kompilacji — nie powinno być konieczne wybieranie pakietów specyficznych dla danej platformy.
  • Zweryfikuj, że dokumenty, które wcześniej wymagały ręcznego sortowania wyników, produkują poprawnie uporządkowany tekst przez result.Text.
  • Sprawdź, czy pliki wyjściowe w formacie PDF z możliwością wyszukiwania umożliwiają wyszukiwanie tekstu w programie Adobe Acrobat Reader lub innej przeglądarce plików PDF.
  • Uruchom aplikację pod obciążeniem, aby potwierdzić, że instancje IronTesseract tworzone per-żądanie nie wywołują presji na pamięć porównywalnej do konstrukcji PaddleOcrAll per-żądanie.
  • Sprawdź, czy pakiety językowe zainstalowane jako pakiety NuGet przywracają się poprawnie w CI bez dodatkowych kroków wdrażania plików.
  • Przetestuj wszystkie scenariusze wyodrębniania tabel pod kątem oczekiwanej struktury wierszy/kolumn, stosując podejście oparte na regionach lub grupowaniu współrzędnych.
  • Potwierdź, że czas uruchamiania aplikacji maleje po wyeliminowaniu konstrukcji singletonu PaddleOcrAll ze ścieżki startowej.

Kluczowe korzyści z migracji do IronOCR

Jeden pakiet zastępuje stos czterech pakietów. Po migracji, ślad zależności OCR to pojedyncze odniesienie NuGet IronOcr. Stos czterech pakietów — Sdcb.PaddleOCR, Sdcb.PaddleInference, OpenCvSharp4 i specyficzne dla platformy środowisko uruchomieniowe — staje się jednym wpisem w pliku projektu. Audyty zależności, skany licencji i monitorowanie podatności pokrywają teraz jedną powierzchnię zamiast czterech.

Artefakty wdrożeniowe są jednolite we wszystkich środowiskach. Warunki wyboru backendu — CPU kontra GPU kontra OpenVINO — zostały usunięte. Ten sam artefakt kompilacji jest wdrażany na laptopie programisty, w środowisku CI, kontenerze Linux oraz maszynie wirtualnej w chmurze bez konieczności dokonywania wyboru pakietów specyficznych dla danego środowiska lub rozgałęzień inicjalizacyjnych. Obrazy Dockera zmniejszają się, ponieważ nie ma plików modeli do COPY i nie ma pakietów środowiska uruchomieniowego do zainstalowania.

Rurociągi archiwizacji dokumentów nie wymagają już drugiej biblioteki. result.SaveAsSearchablePdf() eliminuje zależność od biblioteki PDF, którą większość zespołów PaddleSharp dodała, aby tworzyć przeszukiwalne archiwa. Przeprowadzenie OCR i zapisanie pliku PDF z możliwością wyszukiwania to jedno wywołanie API. Dla zespołów przetwarzających tysiące zeskanowanych dokumentów dziennie to uproszczenie eliminuje całą klasę konfliktów między wersjami bibliotek. Wpis na blogu dotyczący plików PDF z funkcją wyszukiwania omawia kwestie związane ze skalą produkcyjną.

Decyzje dotyczące żywotności usług odzwierciedlają wymagania aplikacji, a nie ograniczenia biblioteki. IronTesseract ma lekką konstrukcję. Wzorzec wymuszonego singletonu, wynikający z kosztownego ładowania modeli przez PaddleSharp, nie jest już konieczny. W .NET Core zakres usług można określać na żądanie, co pozwala na wyraźniejsze oddzielenie współbieżnych użytkowników i eliminuje problemy związane z wątkami o współdzielonym stanie. Więcej informacji na temat opcji wdrażania można znaleźć na stronie poświęconej przypadkom użycia ASP.NET OCR.

Rozszerzenie językowe to instalacja pakietu, a nie projekt badawczy. Katalog ponad 125 języków obejmuje skrypty europejskie, azjatyckie, bliskowschodnie oraz specjalistyczne w postaci pakietów NuGet. Dodanie francuskiego, niemieckiego, arabskiego lub japońskiego do rurociągu, który zaczynał tylko od chińskiego, to dotnet add package IronOcr.Languages.French i jedna linia konfiguracji. Bez źródeł plików modeli, bez badań dostępności w górnym biegu, bez ręcznego wdrażania plików.

Przetwarzanie wstępne jest częścią API OCR. Wiedza o OpenCV, której wymagało przetwarzanie wstępne PaddleSharp — zrozumienie jąder filtrów, zarządzanie usuwaniem Mat, wybór parametrów adaptacyjnego progu — nie jest już warunkiem wstępnym dla pracy OCR. OcrInput zapewnia nazwane operacje z rozsądnymi domyślnymi ustawieniami. Zespoły, które nie były specjalistami w zakresie OpenCV, ale utrzymywały kod przetwarzania wstępnego OpenCV, mogą usunąć ten kod bez konieczności jego zastępowania. Strona poświęcona funkcjom przetwarzania wstępnego zawiera listę wszystkich dostępnych filtrów wraz z dokumentacją dotyczącą tego, kiedy należy je stosować.

Zwróć uwagęAdobe Acrobat, PaddleOCR, i Tesseract są zarejestrowanymi znakami towarowymi ich właścicieli. Ta strona nie jest powiązana ze strony Adobe Inc., Baidu, Google lub PaddlePaddle. Wszystkie nazwy produktów, logo i marki są własnością ich odpowiednich właścicieli. Porównania mają charakter wyłącznie informacyjny i odzwierciedlają informacje dostępne publicznie w momencie pisania.

Często Zadawane Pytania

Dlaczego warto przejść z PaddleSharp OCR na IronOCR?

Typowe czynniki motywujące to eliminacja złożoności interoperacyjności COM, zastąpienie zarządzania licencjami opartego na plikach, uniknięcie rozliczeń za stronę, umożliwienie wdrażania w Dockerze/kontenerach oraz przyjęcie natywnego dla NuGet przepływu pracy, który integruje się ze standardowymi narzędziami .NET.

Jakie są główne zmiany w kodzie podczas migracji z PaddleSharp OCR do IronOCR?

Zastąp sekwencje inicjalizacji PaddleSharp instancjonowaniem IronTesseract, usuń zarządzanie cyklem życia COM (jawne wzorce Create/Load/Close) i zaktualizuj nazwy właściwości wyników. W rezultacie znacznie zmniejsza się liczba powtarzających się linii kodu.

Jak zainstalować IronOCR, aby rozpocząć migrację?

Uruchom polecenie „Install-Package IronOcr” w konsoli menedżera pakietów lub „dotnet add package IronOcr” w interfejsie CLI. Pakiety językowe są oddzielnymi pakietami: na przykład „dotnet add package IronOcr.Languages.French” dla języka francuskiego.

Czy IronOCR dorównuje dokładnością OCR bibliotece PaddleSharp OCR w przypadku standardowych dokumentów biznesowych?

IronOCR zapewnia wysoką dokładność w przypadku standardowych treści biznesowych, w tym faktur, umów, paragonów i formularzy wypełnionych na komputerze. Filtry przetwarzania wstępnego obrazu (prostowanie, usuwanie szumów, wzmacnianie kontrastu) dodatkowo poprawiają rozpoznawanie w przypadku pogorszonej jakości danych wejściowych.

W jaki sposób IronOCR obsługuje dane językowe, które PaddleSharp OCR instaluje oddzielnie?

Dane językowe w IronOCR są dystrybuowane jako pakiety NuGet. Polecenie „dotnet add package IronOcr.Languages.German” instaluje obsługę języka niemiećkiego. Nie wymaga to ręcznego umieszczania plików ani podawania ścieżek katalogów.

Czy migracja z PaddleSharp OCR do IronOCR wymaga zmian w infrastrukturze wdrożeniowej?

IronOCR wymaga mniej zmian w infrastrukturze niż PaddleSharp OCR. Nie ma ścieżek binarnych SDK, lokalizacji plików licencyjnych ani konfiguracji serwerów licencyjnych. Pakiet NuGet zawiera kompletny silnik OCR, a klucz licencyjny jest ciągiem znaków ustawionym w kodzie aplikacji.

Jak skonfigurować licencjonowanie IronOCR po migracji?

W kodzie uruchamiającym aplikację przypisz IronOcr.License.LicenseKey = „YOUR-KEY”. W Dockerze lub Kubernetesie zapisz klucz jako zmienną środowiskową i odczytaj go podczas uruchamiania. Użyj License.IsValidLicense do sprawdzenia ważności przed przyjęciem ruchu.

Czy IronOCR może przetwarzać pliki PDF w taki sam sposób jak PaddleSharp?

Tak. IronOCR odczytuje zarówno natywne, jak i zeskanowane pliki PDF. Należy utworzyć instancję IronTesseract, wywołać ocr.Read(input), gdzie input jest ścieżką do pliku PDF lub obiektem OcrPdfInput, a następnie iterować strony OcrResult. Nie jest wymagany oddzielny proces renderowania plików PDF.

W jaki sposób IronOCR radzi sobie z wątkami podczas przetwarzania dużych ilości danych?

IronTesseract można bezpiecznie instancjonować dla każdego wątku. Uruchom jedną instancję na wątek w Parallel.ForEach lub puli zadań, uruchom OCR równolegle i usuń każdą instancję po zakończeniu. Nie jest wymagany żaden stan globalny ani blokowanie.

Jakie formaty wyjściowe obsługuje IronOCR po wyodrębnieniu tekstu?

IronOCR zwraca ustrukturyzowane wyniki, w tym tekst, współrzędne słów, wyniki pewności i strukturę strony. Opcje eksportu obejmują zwykły tekst, PDF z możliwością wyszukiwania oraz obiekty wyników ustrukturyzowanych do dalszego przetwarzania.

Czy ceny IronOCR są bardziej przewidywalne niż PaddleSharp OCR w przypadku skalowania obciążeń?

IronOCR stosuje licencję wieczystą z opłatą ryczałtową, bez opłat za stronę lub wolumen. Niezależnie od tego, czy przetwarzasz 10 000, czy 10 milionów stron, koszt licencji pozostaje stały. Opcje licencji wolumenowych i zespołowych znajdują się na stronie z cennikiem IronOCR.

Co stanie się z moimi istniejącymi testami po migracji z PaddleSharp OCR do IronOCR?

Testy sprawdzające wyodrębnioną treść tekstową powinny nadal przechodzić pomyślnie po migracji. Testy weryfikujące wzorce wywołań API lub cykl życia obiektów COM będą wymagały aktualizacji, aby odzwierciedlały prostszy model inicjalizacji i wyników IronOCR.

Kannaopat Udonpant
Inżynier oprogramowania
Zanim stał się inżynierem oprogramowania, Kannapat ukończył doktorat z zasobów środowiskowych na Uniwersytecie Hokkaido w Japonii. W czasie studiowania, Kannapat również został członkiem Laboratorium Robotyki Pojazdów, które jest częścią Wydziału Inżynierii Bioprodukcji. W 2022 roku wykorzystał swoje umiejętności w ...
Czytaj więcej

Zespół wsparcia Iron

Jesteśmy online 24 godziny, 5 dni w tygodniu.
Czat
E-mail
Zadzwoń do mnie