Saltar al pie de página
VIDEOS

Cómo mejorar la calidad de la imagen para obtener mejores resultados de OCR con C#

Esta guía guía a los desarrolladores de .NET a través de una migración completa desde la familia de paquetes Sdcb.PaddleOCR a IronOCR. Cubre todo el proceso de reemplazo: eliminar la pila de múltiples paquetes PaddlePaddle, eliminar la gestión de archivos de modelo y la configuración de la GPU, y reemplazar la canalización de inferencia dependiente de OpenCV con una única instalación de NuGet . Cada sección es independiente; no es necesario leer previamente el artículo comparativo.

¿Por qué migrar desde PaddleOCR?

El contenedor Sdcb.PaddleOCR es un puente mantenido por la comunidad entre el ecosistema de aprendizaje profundo en Python de PaddlePaddle y .NET. Cumple su función, pero conlleva todo el peso de ese puente: archivos de modelo, binarios de inferencia nativos, OpenCV para la carga de imágenes e infraestructura CUDA opcional. Para la mayoría de las cargas de trabajo de OCR en .NET , esa es una infraestructura que el proyecto nunca necesitó.

Tres directorios de modelos antes de leer un solo carácter. El proceso de inferencia de PaddleOCR encadena tres redes neuronales: un modelo de detección, un modelo de clasificación de dirección y un modelo de reconocimiento. Cada red es un directorio separado de archivos .pdmodel y .pdiparams que deben existir en disco antes de que new PaddleOcrAll(models) compile a un motor funcional. Ya sea que esos archivos lleguen mediante una llamada de descarga asíncrona, que conecta al almacenamiento de bj.bcebos.com de Baidu en China, o mediante un árbol de directorio mantenido manualmente models/, el desarrollador es permanentemente responsable de la versionado de modelos. Cuando Sdcb.PaddleOCR se actualiza, los modelos pre-descargados de la versión anterior pueden requerir una re-descarga.IronOCR no tiene archivos de modelo, ni directorios de modelo, ni problemas de sincronización de versiones. El motor viene incluido en el paquete NuGet .

OpenCV no es opcional. No hay un camino desde una ruta de archivo a la inferencia de PaddleOCR que pase por alto OpenCvSharp. Cada imagen, independientemente del formato, debe pasar a través de Cv2.ImRead(path) para convertirse en un objeto Mat antes de que ocr.Run(mat) pueda aceptarlo. Eso significa dos paquetes NuGet adicionales (OpenCvSharp4 y OpenCvSharp4.runtime.win), DLLs nativas específicas de plataforma en el resultado de implementación y una línea apt-get install libopencv-dev en el Dockerfile.IronOCR acepta rutas de archivo, flujos, matrices de bytes y System.Drawing.Bitmap directamente. No existe el intermediario Mat.

La configuración de la GPU es un proyecto que lleva varios días. Las cifras de rendimiento de la GPU que anuncia PaddleOCR (50-100 ms por imagen frente a 300-500 ms en la CPU) son reales. Para ello se requieren controladores NVIDIA de una versión específica, CUDA Toolkit 11.8 (no 12.x), cuDNN 8.6+ ubicado en las rutas PATH correctas y un paquete NuGet de tiempo de ejecución de GPU independiente. En Docker, la imagen base debe ser nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04 y el host debe tener instalado nvidia-container-toolkit. Los equipos que no disponen de infraestructura de GPU invierten entre 2 y 8 horas en la configuración de CUDA por entorno.IronOCR está diseñado para la inferencia por CPU, ofrece un tiempo de procesamiento de 150 a 300 ms por imagen en hardware estándar y no requiere ninguna configuración de GPU.

Los artefactos de implementación son 4-6x más grandes. El resultado de implementación de PaddleOCR incluye paddle_inference.dll (~200MB), paddle2onnx.dll (~5MB), archivos opencv_world*.dll (~50MB combinados) y los directorios de modelo (~21MB). Una imagen de Docker ocupa aproximadamente 1,5 GB. El tamaño total de una instalación de IronOCR es de aproximadamente 80 MB. La imagen de Docker ocupa aproximadamente 400 MB. La diferencia se agrava en CI/CD: cada ejecución del pipeline que restaura paquetes NuGet debe descargar los modelos de Baidu o extraerlos de una capa de caché mantenida por separado.

No genera archivos PDF con capacidad de búsqueda. PaddleOCR extrae regiones de texto de las imágenes, pero no dispone de ningún mecanismo para incrustar el texto reconocido en un PDF como una capa con capacidad de búsqueda. Para crear un PDF con capacidad de búsqueda a partir de la salida de PaddleOCR, se requiere una biblioteca de PDF de terceros, la inyección de capas de texto página por página y la reasignación de coordenadas.IronOCR produce un PDF completamente buscable con una línea: result.SaveAsSearchablePdf("output.pdf").

El problema fundamental

PaddleOCR requiere que se configuren tres directorios de modelos antes de que pueda comenzar la inferencia:

// PaddleOCR: three model directories, all must exist and match the wrapper version
FullOcrModel models = new FullOcrModel(
    LocalDetectionModel.FromDirectory("models/ch_PP-OCRv4_det_infer"),       // ~5MB
    LocalClassificationModel.FromDirectory("models/ch_ppocr_mobile_v2.0_cls_infer"), // ~2MB
    LocalRecognitionModel.FromDirectory("models/ch_PP-OCRv4_rec_infer")      // ~15MB
);
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("document.png");  // OpenCvSharp required for every image
PaddleOcrResult result = ocr.Run(mat);
// PaddleOCR: three model directories, all must exist and match the wrapper version
FullOcrModel models = new FullOcrModel(
    LocalDetectionModel.FromDirectory("models/ch_PP-OCRv4_det_infer"),       // ~5MB
    LocalClassificationModel.FromDirectory("models/ch_ppocr_mobile_v2.0_cls_infer"), // ~2MB
    LocalRecognitionModel.FromDirectory("models/ch_PP-OCRv4_rec_infer")      // ~15MB
);
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("document.png");  // OpenCvSharp required for every image
PaddleOcrResult result = ocr.Run(mat);
Imports OpenCvSharp
Imports PaddleOCR

' PaddleOCR: three model directories, all must exist and match the wrapper version
Dim models As New FullOcrModel(
    LocalDetectionModel.FromDirectory("models/ch_PP-OCRv4_det_infer"),       ' ~5MB
    LocalClassificationModel.FromDirectory("models/ch_ppocr_mobile_v2.0_cls_infer"), ' ~2MB
    LocalRecognitionModel.FromDirectory("models/ch_PP-OCRv4_rec_infer")      ' ~15MB
)

Using ocr As New PaddleOcrAll(models)
    Using mat As Mat = Cv2.ImRead("document.png")  ' OpenCvSharp required for every image
        Dim result As PaddleOcrResult = ocr.Run(mat)
    End Using
End Using
$vbLabelText   $csharpLabel

IronOCR no tiene archivos de modelo, ni directorios de modelo, ni dependencia de OpenCV:

// IronOCR: one package, zero model management
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("document.png");
var result = ocr.Read(input);
Console.WriteLine(result.Text);
// IronOCR: one package, zero model management
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadImage("document.png");
var result = ocr.Read(input);
Console.WriteLine(result.Text);
Imports IronOcr

Dim ocr As New IronTesseract()
Using input As New OcrInput()
    input.LoadImage("document.png")
    Dim result = ocr.Read(input)
    Console.WriteLine(result.Text)
End Using
$vbLabelText   $csharpLabel

IronOCR vs PaddleOCR (.NET): Comparación de características

La tabla que aparece a continuación recoge las dimensiones más importantes a la hora de planificar la migración.

Característica PaddleOCR (Sdcb) IronOCR
Se requieren paquetes NuGet 4-5 1
Se requieren archivos de modelo Sí (3 directorios, ~21 MB) No (incluido en el paquete)
Fuente de descarga del modelo Servidores de Baidu (bj.bcebos.com) Restauración de NuGet (Iron Software)
dependencia de OpenCV Requerido (OpenCvSharp4) None
Entrada de imagen A través de Mat mat = Cv2.ImRead() Ruta de archivo directa, flujo, matriz de bytes
Entrada nativa de PDF No Sí (input.LoadPdf())
Salida en PDF con capacidad de búsqueda No Sí (result.SaveAsSearchablePdf())
Entrada TIFF multifotograma Bucle manual por fotograma input.LoadImageFrames()
Compatibilidad con GPU Sí (se requiere CUDA 11.8 + cuDNN) Optimizado para CPU (no requiere GPU)
Preprocesamiento integrado No (la red neuronal maneja la asimetría/el ruido) Sí (Desinclinar, Reducir ruido, Contraste, Binarizar, Nitidez)
Idiomas compatibles 14 125+
Método de instalación del idioma DownloadAsync() por modelo de idioma dotnet add package IronOcr.Languages.*
Multilingüe simultáneo No (modelo independiente por idioma) Sí (OcrLanguage.English + OcrLanguage.French)
Salida estructurada result.Regions (espacial, desordenado) Páginas, párrafos, líneas, palabras, caracteres
Puntuación de confianza Valor flotante por región (0-1) Porcentaje por palabra (0-100)
Lectura de códigos de barras No Sí (ocr.Configuration.ReadBarCodes = true)
Exportación hOCR No
Tamaño de despliegue 300-500 MB ~80MB
Tamaño de la imagen de Docker ~1,5 GB (con base CUDA) ~400 MB
Tiempo de arranque en frío 3-5 segundos (carga del modelo) Menos de 1 segundo
Plataforma cruzada Windows, Linux (parcial) Windows, Linux, macOS, Docker, Azure, AWS
Compatibilidad con .NET .NET 6+ (envoltorio comunitario) .NET Framework 4.6.2+, .NET 5/6/7/8/9
Apoyo comercial Problemas de la comunidad/GitHub Sí (Iron Software, con SLA)
Licencia Apache 2.0 (gratuito) Perpetual ($999 Lite / $1,499 Pro / $2,999 Enterprise)

Inicio rápido: Migración de PaddleOCR (.NET) a IronOCR

Paso 1: Sustituir paquetes NuGet

Elimine los cinco paquetes relacionados con PaddleOCR:

dotnet remove package Sdcb.PaddleOCR
dotnet remove package Sdcb.PaddleOCR.Models.Online
dotnet remove package Sdcb.PaddleInference.runtime.win64.mkl
dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
dotnet remove package Sdcb.PaddleOCR
dotnet remove package Sdcb.PaddleOCR.Models.Online
dotnet remove package Sdcb.PaddleInference.runtime.win64.mkl
dotnet remove package OpenCvSharp4
dotnet remove package OpenCvSharp4.runtime.win
SHELL

Si el entorno de ejecución de la GPU estaba instalado, elimínelo también:

dotnet remove package Sdcb.PaddleInference.runtime.win64.cuda118
dotnet remove package Sdcb.PaddleInference.runtime.win64.cuda118
SHELL

Instale IronOCR desde la página del paquete NuGet :

dotnet add package IronOcr

Paso 2: Actualizar los espacios de nombres

Reemplace todas las importaciones de espacios de nombres de PaddleOCR y OpenCvSharp:

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

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

// After (IronOCR)
using IronOcr;
Imports IronOcr
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models
Imports Sdcb.PaddleOCR.Models.Online
Imports Sdcb.PaddleInference
Imports OpenCvSharp
$vbLabelText   $csharpLabel

Paso 3: Inicializar licencia

Agrega la inicialización de la licencia una vez al inicio de la aplicación, antes de que se cree cualquier instancia de IronTesseract:

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

Puede obtener una clave de prueba gratuita en la página de licencias de IronOCR . La versión de prueba genera un resultado con marca de agua y permite probar todas las funciones antes de la compra.

Ejemplos de migración de código

Eliminación de la configuración de la ruta del modelo local

Los proyectos que descargan previamente los archivos del modelo PaddleOCR para evitar conexiones con el servidor Baidu durante la ejecución deben configurar tres rutas de directorio separadas. Esta configuración debe actualizarse cada vez que cambie la versión del envoltorio.

Enfoque PaddleOCR:

// Local model configuration — developer owns the directory structure
// Each wrapper update may require re-downloading model files
string modelsRoot = Path.Combine(AppContext.BaseDirectory, "models");

FullOcrModel models = new FullOcrModel(
    LocalDetectionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_det_infer")),
    LocalClassificationModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_ppocr_mobile_v2.0_cls_infer")),
    LocalRecognitionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_rec_infer"))
);

// Fails at runtime if any of the three directories is missing or stale
using PaddleOcrAll ocr = new PaddleOcrAll(models)
{
    AllowRotateDetection = true,
    Enable180Classification = true
};

using Mat mat = Cv2.ImRead("document.png");
PaddleOcrResult result = ocr.Run(mat);
Console.WriteLine(result.Text);
// Local model configuration — developer owns the directory structure
// Each wrapper update may require re-downloading model files
string modelsRoot = Path.Combine(AppContext.BaseDirectory, "models");

FullOcrModel models = new FullOcrModel(
    LocalDetectionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_det_infer")),
    LocalClassificationModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_ppocr_mobile_v2.0_cls_infer")),
    LocalRecognitionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_rec_infer"))
);

// Fails at runtime if any of the three directories is missing or stale
using PaddleOcrAll ocr = new PaddleOcrAll(models)
{
    AllowRotateDetection = true,
    Enable180Classification = true
};

using Mat mat = Cv2.ImRead("document.png");
PaddleOcrResult result = ocr.Run(mat);
Console.WriteLine(result.Text);
Imports System
Imports System.IO

' Local model configuration — developer owns the directory structure
' Each wrapper update may require re-downloading model files
Dim modelsRoot As String = Path.Combine(AppContext.BaseDirectory, "models")

Dim models As New FullOcrModel(
    LocalDetectionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_det_infer")),
    LocalClassificationModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_ppocr_mobile_v2.0_cls_infer")),
    LocalRecognitionModel.FromDirectory(
        Path.Combine(modelsRoot, "ch_PP-OCRv4_rec_infer"))
)

' Fails at runtime if any of the three directories is missing or stale
Using ocr As New PaddleOcrAll(models) With {
    .AllowRotateDetection = True,
    .Enable180Classification = True
}

    Using mat As Mat = Cv2.ImRead("document.png")
        Dim result As PaddleOcrResult = ocr.Run(mat)
        Console.WriteLine(result.Text)
    End Using

End Using
$vbLabelText   $csharpLabel

Enfoque IronOCR:

// No model directories, no path configuration, no version matching
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("document.png");

var result = ocr.Read(input);
Console.WriteLine(result.Text);
// No model directories, no path configuration, no version matching
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("document.png");

var result = ocr.Read(input);
Console.WriteLine(result.Text);
Imports IronOcr

' No model directories, no path configuration, no version matching
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr = New IronTesseract()

Using input As New OcrInput()
    input.LoadImage("document.png")

    Dim result = ocr.Read(input)
    Console.WriteLine(result.Text)
End Using
$vbLabelText   $csharpLabel

El árbol de directorio models/, las tres llamadas FromDirectory() y la preocupación de sincronización de versiones desaparecen. El motor IronOCR viene incluido en el paquete NuGet en el momento de la restauración y no requiere resolución de ruta en tiempo de ejecución. Consulta la guía de configuración de IronTesseract para opciones de inicialización, incluyendo la colocación de la llave de licencia en appsettings.json.

Consolidación del sistema de detección y reconocimiento en dos etapas

La canalización de rotación y orientación de PaddleOCR se configura a través de propiedades en PaddleOcrAll. Replicar este comportamiento en IronOCR utiliza los métodos de preprocesamiento de OcrInput, que manejan los mismos problemas del documento con una superficie de llamada más simple.

Enfoque PaddleOCR:

using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;

// Separate async initialization step — blocks startup for 3-5 seconds on cold run
FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();

using PaddleOcrAll ocr = new PaddleOcrAll(models)
{
    AllowRotateDetection = true,        // Enables 0/90/180/270 degree rotation detection
    Enable180Classification = true      // Additional pass for upside-down text
};

// OpenCV Mat required — no direct file path support
using Mat mat = Cv2.ImRead("rotated-scan.png");

if (mat.Empty())
{
    throw new FileNotFoundException("Image could not be loaded by OpenCvSharp");
}

// Three neural network passes: detection → classification → recognition
PaddleOcrResult result = ocr.Run(mat);

// Regions arrive in spatial order, not reading order
// Manual sort required for top-to-bottom, left-to-right output
var orderedRegions = result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X);

foreach (var region in orderedRegions)
{
    Console.WriteLine($"{region.Text} (confidence: {region.Score:P1})");
}
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;

// Separate async initialization step — blocks startup for 3-5 seconds on cold run
FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();

using PaddleOcrAll ocr = new PaddleOcrAll(models)
{
    AllowRotateDetection = true,        // Enables 0/90/180/270 degree rotation detection
    Enable180Classification = true      // Additional pass for upside-down text
};

// OpenCV Mat required — no direct file path support
using Mat mat = Cv2.ImRead("rotated-scan.png");

if (mat.Empty())
{
    throw new FileNotFoundException("Image could not be loaded by OpenCvSharp");
}

// Three neural network passes: detection → classification → recognition
PaddleOcrResult result = ocr.Run(mat);

// Regions arrive in spatial order, not reading order
// Manual sort required for top-to-bottom, left-to-right output
var orderedRegions = result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X);

foreach (var region in orderedRegions)
{
    Console.WriteLine($"{region.Text} (confidence: {region.Score:P1})");
}
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models.Online
Imports OpenCvSharp

' Separate async initialization step — blocks startup for 3-5 seconds on cold run
Dim models As FullOcrModel = Await OnlineFullModels.EnglishV4.DownloadAsync()

Using ocr As New PaddleOcrAll(models) With {
    .AllowRotateDetection = True,        ' Enables 0/90/180/270 degree rotation detection
    .Enable180Classification = True      ' Additional pass for upside-down text
}

    ' OpenCV Mat required — no direct file path support
    Using mat As Mat = Cv2.ImRead("rotated-scan.png")

        If mat.Empty() Then
            Throw New FileNotFoundException("Image could not be loaded by OpenCvSharp")
        End If

        ' Three neural network passes: detection → classification → recognition
        Dim result As PaddleOcrResult = ocr.Run(mat)

        ' Regions arrive in spatial order, not reading order
        ' Manual sort required for top-to-bottom, left-to-right output
        Dim orderedRegions = result.Regions _
            .OrderBy(Function(r) r.Rect.Center.Y) _
            .ThenBy(Function(r) r.Rect.Center.X)

        For Each region In orderedRegions
            Console.WriteLine($"{region.Text} (confidence: {region.Score:P1})")
        Next
    End Using
End Using
$vbLabelText   $csharpLabel

Enfoque IronOCR:

using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("rotated-scan.png");
input.Deskew();    // Corrects rotation and skew automatically

var result = ocr.Read(input);

// Output is already in reading order — no sort needed
foreach (var page in result.Pages)
{
    foreach (var line in page.Lines)
    {
        Console.WriteLine($"{line.Text} (confidence: {line.Confidence}%)");
    }
}
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("rotated-scan.png");
input.Deskew();    // Corrects rotation and skew automatically

var result = ocr.Read(input);

// Output is already in reading order — no sort needed
foreach (var page in result.Pages)
{
    foreach (var line in page.Lines)
    {
        Console.WriteLine($"{line.Text} (confidence: {line.Confidence}%)");
    }
}
Imports IronOcr

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr As New IronTesseract()

Using input As New OcrInput()
    input.LoadImage("rotated-scan.png")
    input.Deskew() ' Corrects rotation and skew automatically

    Dim result = ocr.Read(input)

    ' Output is already in reading order — no sort needed
    For Each page In result.Pages
        For Each line In page.Lines
            Console.WriteLine($"{line.Text} (confidence: {line.Confidence}%)")
        Next
    Next
End Using
$vbLabelText   $csharpLabel

El método Deskew() de IronOCR maneja la detección de rotación como parte de la canalización de preprocesamiento. La colección de resultados Lines se entrega en orden de lectura por el motor de diseño Tesseract, eliminando el patrón de ordenamiento manual. La guía de corrección de la orientación de la imagen documenta toda la gama de opciones de rotación y corrección de la inclinación.

Eliminación de la selección de dispositivos GPU y CPU

Las aplicaciones de PaddleOCR que ejecutan inferencia en GPU tienen la mayor superficie de migración: el paquete NuGet de tiempo de ejecución de GPU, los requisitos previos del entorno CUDA/cuDNN y la llamada de configuración PaddleDevice.Gpu(). Todo esto se elimina durante la migración.

Enfoque PaddleOCR:

using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using Sdcb.PaddleInference;    // GPU configuration namespace
using OpenCvSharp;

// Prerequisites must exist on every deployment environment:
// - NVIDIA Driver 452.39+ (Windows) / 450.80.02+ (Linux)
// - CUDA Toolkit 11.8 (not 12.x — version must match exactly)
// - cuDNN 8.6.0+ placed in CUDA bin directory
// - dotnet add package Sdcb.PaddleInference.runtime.win64.cuda118

FullOcrModel models = await OnlineFullModels.ChineseV4.DownloadAsync();

// GPU device 0, 1000MB initial memory pool
// Throws native load exception if CUDA_PATH not set or cuDNN DLL missing
using PaddleOcrAll ocr = new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0))
{
    AllowRotateDetection = true,
    Enable180Classification = true
};

using Mat mat = Cv2.ImRead("scanned-batch.png");
PaddleOcrResult result = ocr.Run(mat);

Console.WriteLine($"Text regions: {result.Regions.Length}");
Console.WriteLine(result.Text);
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using Sdcb.PaddleInference;    // GPU configuration namespace
using OpenCvSharp;

// Prerequisites must exist on every deployment environment:
// - NVIDIA Driver 452.39+ (Windows) / 450.80.02+ (Linux)
// - CUDA Toolkit 11.8 (not 12.x — version must match exactly)
// - cuDNN 8.6.0+ placed in CUDA bin directory
// - dotnet add package Sdcb.PaddleInference.runtime.win64.cuda118

FullOcrModel models = await OnlineFullModels.ChineseV4.DownloadAsync();

// GPU device 0, 1000MB initial memory pool
// Throws native load exception if CUDA_PATH not set or cuDNN DLL missing
using PaddleOcrAll ocr = new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0))
{
    AllowRotateDetection = true,
    Enable180Classification = true
};

using Mat mat = Cv2.ImRead("scanned-batch.png");
PaddleOcrResult result = ocr.Run(mat);

Console.WriteLine($"Text regions: {result.Regions.Length}");
Console.WriteLine(result.Text);
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models.Online
Imports Sdcb.PaddleInference    ' GPU configuration namespace
Imports OpenCvSharp

' Prerequisites must exist on every deployment environment:
' - NVIDIA Driver 452.39+ (Windows) / 450.80.02+ (Linux)
' - CUDA Toolkit 11.8 (not 12.x — version must match exactly)
' - cuDNN 8.6.0+ placed in CUDA bin directory
' - dotnet add package Sdcb.PaddleInference.runtime.win64.cuda118

Dim models As FullOcrModel = Await OnlineFullModels.ChineseV4.DownloadAsync()

' GPU device 0, 1000MB initial memory pool
' Throws native load exception if CUDA_PATH not set or cuDNN DLL missing
Using ocr As New PaddleOcrAll(models, PaddleDevice.Gpu(deviceId:=0)) With {
    .AllowRotateDetection = True,
    .Enable180Classification = True
}

    Using mat As Mat = Cv2.ImRead("scanned-batch.png")
        Dim result As PaddleOcrResult = ocr.Run(mat)

        Console.WriteLine($"Text regions: {result.Regions.Length}")
        Console.WriteLine(result.Text)
    End Using
End Using
$vbLabelText   $csharpLabel

Enfoque IronOCR:

El enfoque de IronOCR es idéntico al ejemplo anterior: IronTesseract maneja este escenario con la misma llamada API. No se requieren paquetes de GPU, ni requisitos previos de CUDA, ni selección de dispositivo. Reemplace new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0)) con new IronTesseract() y elimine toda la configuración relacionada con GPU.

IronOCR ofrece un tiempo de procesamiento de 150 a 300 ms por imagen en la CPU, más rápido que PaddleOCR en la CPU (300-500 ms) y suficiente para la mayoría de las cargas de trabajo de API web y procesamiento de documentos sin necesidad de infraestructura de GPU. Para escenarios de alto rendimiento, la guía de optimización de velocidad abarca opciones de configuración que incluyen la gestión de subprocesos y el ajuste del modo de segmentación de páginas.

Extracción de datos de documentos estructurados

PaddleOCR devuelve una matriz plana de objetos PaddleOcrResultRegion ordenados espacialmente, no por flujo de lectura. La extracción de la estructura a nivel de párrafo o de línea requiere una lógica de agrupación manual basada en la proximidad de los cuadros delimitadores.IronOCR proporciona un árbol de resultados jerárquico con el orden de lectura garantizado.

Enfoque PaddleOCR:

using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
using System.Collections.Generic;

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("invoice.png");

PaddleOcrResult result = ocr.Run(mat);

// No paragraph or line grouping — must implement manually
// Group regions into lines by proximity on the Y axis
var lineGroups = new Dictionary<int, List<PaddleOcrResultRegion>>();

foreach (var region in result.Regions)
{
    // Round Y center to nearest 15 pixels to approximate line grouping
    int lineKey = (int)(region.Rect.Center.Y / 15) * 15;

    if (!lineGroups.ContainsKey(lineKey))
        lineGroups[lineKey] = new List<PaddleOcrResultRegion>();

    lineGroups[lineKey].Add(region);
}

// Sort lines top to bottom, then regions left to right within each line
foreach (var line in lineGroups.OrderBy(kv => kv.Key))
{
    var lineText = string.Join(" ", line.Value
        .OrderBy(r => r.Rect.Center.X)
        .Select(r => r.Text));

    Console.WriteLine(lineText);
}
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
using System.Collections.Generic;

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("invoice.png");

PaddleOcrResult result = ocr.Run(mat);

// No paragraph or line grouping — must implement manually
// Group regions into lines by proximity on the Y axis
var lineGroups = new Dictionary<int, List<PaddleOcrResultRegion>>();

foreach (var region in result.Regions)
{
    // Round Y center to nearest 15 pixels to approximate line grouping
    int lineKey = (int)(region.Rect.Center.Y / 15) * 15;

    if (!lineGroups.ContainsKey(lineKey))
        lineGroups[lineKey] = new List<PaddleOcrResultRegion>();

    lineGroups[lineKey].Add(region);
}

// Sort lines top to bottom, then regions left to right within each line
foreach (var line in lineGroups.OrderBy(kv => kv.Key))
{
    var lineText = string.Join(" ", line.Value
        .OrderBy(r => r.Rect.Center.X)
        .Select(r => r.Text));

    Console.WriteLine(lineText);
}
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models.Online
Imports OpenCvSharp
Imports System.Collections.Generic

Dim models As FullOcrModel = Await OnlineFullModels.EnglishV4.DownloadAsync()
Using ocr As New PaddleOcrAll(models)
    Using mat As Mat = Cv2.ImRead("invoice.png")
        Dim result As PaddleOcrResult = ocr.Run(mat)

        ' No paragraph or line grouping — must implement manually
        ' Group regions into lines by proximity on the Y axis
        Dim lineGroups As New Dictionary(Of Integer, List(Of PaddleOcrResultRegion))()

        For Each region In result.Regions
            ' Round Y center to nearest 15 pixels to approximate line grouping
            Dim lineKey As Integer = CInt(region.Rect.Center.Y / 15) * 15

            If Not lineGroups.ContainsKey(lineKey) Then
                lineGroups(lineKey) = New List(Of PaddleOcrResultRegion)()
            End If

            lineGroups(lineKey).Add(region)
        Next

        ' Sort lines top to bottom, then regions left to right within each line
        For Each line In lineGroups.OrderBy(Function(kv) kv.Key)
            Dim lineText As String = String.Join(" ", line.Value _
                .OrderBy(Function(r) r.Rect.Center.X) _
                .Select(Function(r) r.Text))

            Console.WriteLine(lineText)
        Next
    End Using
End Using
$vbLabelText   $csharpLabel

Enfoque IronOCR:

using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("invoice.png");

var result = ocr.Read(input);

// Hierarchical structure: Pages → Paragraphs → Lines → Words → Characters
// All delivered in reading order by the layout engine
foreach (var page in result.Pages)
{
    Console.WriteLine($"Page {page.PageNumber} — {page.Words.Count} words");

    foreach (var paragraph in page.Paragraphs)
    {
        Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):");
        Console.WriteLine($"  {paragraph.Text}");
    }
}
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("invoice.png");

var result = ocr.Read(input);

// Hierarchical structure: Pages → Paragraphs → Lines → Words → Characters
// All delivered in reading order by the layout engine
foreach (var page in result.Pages)
{
    Console.WriteLine($"Page {page.PageNumber} — {page.Words.Count} words");

    foreach (var paragraph in page.Paragraphs)
    {
        Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):");
        Console.WriteLine($"  {paragraph.Text}");
    }
}
Imports IronOcr

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr As New IronTesseract()

Using input As New OcrInput()
    input.LoadImage("invoice.png")

    Dim result = ocr.Read(input)

    ' Hierarchical structure: Pages → Paragraphs → Lines → Words → Characters
    ' All delivered in reading order by the layout engine
    For Each page In result.Pages
        Console.WriteLine($"Page {page.PageNumber} — {page.Words.Count} words")

        For Each paragraph In page.Paragraphs
            Console.WriteLine($"  Paragraph at ({paragraph.X}, {paragraph.Y}):")
            Console.WriteLine($"  {paragraph.Text}")
        Next
    Next
End Using
$vbLabelText   $csharpLabel

La aproximación manual de agrupación de líneas —que consiste en redondear las coordenadas Y al tamaño de un cubo de píxeles— se sustituye por la segmentación de párrafos integrada del motor de maquetación Tesseract. Las coordenadas de cuadro delimitador están disponibles en cada nivel de la jerarquía a través de paragraph.X, paragraph.Y, paragraph.Width y paragraph.Height. Consulte la guía de resultados estructurados y el tutorial sobre cómo leer texto de imágenes para obtener una cobertura completa del árbol de resultados.

Generación de PDF con capacidad de búsqueda

PaddleOCR no genera ningún archivo PDF. Generar un PDF buscable a partir de los resultados de PaddleOCR requiere una biblioteca PDF separada, mapeo manual de coordenadas de region.Rect a unidades de página PDF y una inyección de capa de texto invisible.IronOCR genera un PDF con capacidad de búsqueda directamente a partir del resultado del OCR.

Enfoque PaddleOCR:

using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
// Requires additional package: PdfSharp, iTextSharp, or similar
// Manual coordinate remapping from OpenCV pixel space to PDF point space

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("scanned-page.png");

PaddleOcrResult paddleResult = ocr.Run(mat);

// No built-in searchable PDF output — must build with external library
// region.Rect coordinates are in pixel space, PDF uses points (1 point = 1/72 inch)
// DPI conversion required for coordinate mapping
float dpiScale = 72.0f / 96.0f;  // Assuming 96 DPI source image

// ... hundreds of lines of PDF construction code using external library ...
// This is permanent maintenance, not a one-time cost
Console.WriteLine("Searchable PDF output requires external PDF library and coordinate mapping.");
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
// Requires additional package: PdfSharp, iTextSharp, or similar
// Manual coordinate remapping from OpenCV pixel space to PDF point space

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);
using Mat mat = Cv2.ImRead("scanned-page.png");

PaddleOcrResult paddleResult = ocr.Run(mat);

// No built-in searchable PDF output — must build with external library
// region.Rect coordinates are in pixel space, PDF uses points (1 point = 1/72 inch)
// DPI conversion required for coordinate mapping
float dpiScale = 72.0f / 96.0f;  // Assuming 96 DPI source image

// ... hundreds of lines of PDF construction code using external library ...
// This is permanent maintenance, not a one-time cost
Console.WriteLine("Searchable PDF output requires external PDF library and coordinate mapping.");
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models.Online
Imports OpenCvSharp
' Requires additional package: PdfSharp, iTextSharp, or similar
' Manual coordinate remapping from OpenCV pixel space to PDF point space

Dim models As FullOcrModel = Await OnlineFullModels.EnglishV4.DownloadAsync()
Using ocr As New PaddleOcrAll(models)
    Using mat As Mat = Cv2.ImRead("scanned-page.png")
        Dim paddleResult As PaddleOcrResult = ocr.Run(mat)
    End Using
End Using

' No built-in searchable PDF output — must build with external library
' region.Rect coordinates are in pixel space, PDF uses points (1 point = 1/72 inch)
' DPI conversion required for coordinate mapping
Dim dpiScale As Single = 72.0F / 96.0F  ' Assuming 96 DPI source image

' ... hundreds of lines of PDF construction code using external library ...
' This is permanent maintenance, not a one-time cost
Console.WriteLine("Searchable PDF output requires external PDF library and coordinate mapping.")
$vbLabelText   $csharpLabel

Enfoque IronOCR:

using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("scanned-page.png");
input.Deskew();
input.DeNoise();

var result = ocr.Read(input);

// Searchable PDF in one line — no external PDF library, no coordinate mapping
result.SaveAsSearchablePdf("searchable-output.pdf");

Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImage("scanned-page.png");
input.Deskew();
input.DeNoise();

var result = ocr.Read(input);

// Searchable PDF in one line — no external PDF library, no coordinate mapping
result.SaveAsSearchablePdf("searchable-output.pdf");

Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%");
Imports IronOcr

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr As New IronTesseract()

Using input As New OcrInput()
    input.LoadImage("scanned-page.png")
    input.Deskew()
    input.DeNoise()

    Dim result = ocr.Read(input)

    ' Searchable PDF in one line — no external PDF library, no coordinate mapping
    result.SaveAsSearchablePdf("searchable-output.pdf")

    Console.WriteLine($"Searchable PDF created. Confidence: {result.Confidence}%")
End Using
$vbLabelText   $csharpLabel

El problema del mapeo de coordenadas —convertir las coordenadas de píxeles de OpenCV al espacio de puntos PDF con la resolución DPI correcta— no existe en IronOCR. La guía en formato PDF, que permite realizar búsquedas, abarca la impresión de documentos de varias páginas, los archivos PDF protegidos con contraseña y la configuración de la calidad de impresión. Para los equipos que digitalizan archivos escaneados o que crean sistemas de conversión de fax a PDF con capacidad de búsqueda, esta única llamada a un método sustituye lo que de otro modo sería un proyecto de integración sustancial.

Procesamiento por lotes de TIFF multifotograma

Los archivos TIFF de varias páginas aparecen con frecuencia en los flujos de trabajo de escaneo de documentos. PaddleOCR no tiene soporte directo para múltiples marcos TIFF — cada marco debe extraerse individualmente usando una biblioteca de imágenes externa y cargarse como un Mat separado.IronOCR maneja archivos TIFF multifotograma de forma nativa.

Enfoque PaddleOCR:

using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
using System.Drawing;  // For multi-frame TIFF extraction
using System.Drawing.Imaging;
using System.Text;

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);

var fullText = new StringBuilder();

// Must use System.Drawing to extract individual TIFF frames
// OpenCvSharp cannot enumerate TIFF frames directly
using var tiff = Image.FromFile("multipage-scan.tiff");
FrameDimension dimension = new FrameDimension(tiff.FrameDimensionsList[0]);
int frameCount = tiff.GetFrameCount(dimension);

for (int i = 0; i < frameCount; i++)
{
    tiff.SelectActiveFrame(dimension, i);

    // Save frame to temp file — OpenCvSharp needs a file path
    string tempPath = Path.GetTempFileName() + ".png";
    tiff.Save(tempPath, ImageFormat.Png);

    try
    {
        using Mat mat = Cv2.ImRead(tempPath);
        PaddleOcrResult result = ocr.Run(mat);
        fullText.AppendLine($"=== Frame {i + 1} ===");
        fullText.AppendLine(result.Text);
    }
    finally
    {
        File.Delete(tempPath);  // Must clean up temp files
    }
}

Console.WriteLine(fullText.ToString());
using Sdcb.PaddleOCR;
using Sdcb.PaddleOCR.Models.Online;
using OpenCvSharp;
using System.Drawing;  // For multi-frame TIFF extraction
using System.Drawing.Imaging;
using System.Text;

FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
using PaddleOcrAll ocr = new PaddleOcrAll(models);

var fullText = new StringBuilder();

// Must use System.Drawing to extract individual TIFF frames
// OpenCvSharp cannot enumerate TIFF frames directly
using var tiff = Image.FromFile("multipage-scan.tiff");
FrameDimension dimension = new FrameDimension(tiff.FrameDimensionsList[0]);
int frameCount = tiff.GetFrameCount(dimension);

for (int i = 0; i < frameCount; i++)
{
    tiff.SelectActiveFrame(dimension, i);

    // Save frame to temp file — OpenCvSharp needs a file path
    string tempPath = Path.GetTempFileName() + ".png";
    tiff.Save(tempPath, ImageFormat.Png);

    try
    {
        using Mat mat = Cv2.ImRead(tempPath);
        PaddleOcrResult result = ocr.Run(mat);
        fullText.AppendLine($"=== Frame {i + 1} ===");
        fullText.AppendLine(result.Text);
    }
    finally
    {
        File.Delete(tempPath);  // Must clean up temp files
    }
}

Console.WriteLine(fullText.ToString());
Imports Sdcb.PaddleOCR
Imports Sdcb.PaddleOCR.Models.Online
Imports OpenCvSharp
Imports System.Drawing  ' For multi-frame TIFF extraction
Imports System.Drawing.Imaging
Imports System.Text

Dim models As FullOcrModel = Await OnlineFullModels.EnglishV4.DownloadAsync()
Using ocr As New PaddleOcrAll(models)
    Dim fullText As New StringBuilder()

    ' Must use System.Drawing to extract individual TIFF frames
    ' OpenCvSharp cannot enumerate TIFF frames directly
    Using tiff As Image = Image.FromFile("multipage-scan.tiff")
        Dim dimension As New FrameDimension(tiff.FrameDimensionsList(0))
        Dim frameCount As Integer = tiff.GetFrameCount(dimension)

        For i As Integer = 0 To frameCount - 1
            tiff.SelectActiveFrame(dimension, i)

            ' Save frame to temp file — OpenCvSharp needs a file path
            Dim tempPath As String = Path.GetTempFileName() & ".png"
            tiff.Save(tempPath, ImageFormat.Png)

            Try
                Using mat As Mat = Cv2.ImRead(tempPath)
                    Dim result As PaddleOcrResult = ocr.Run(mat)
                    fullText.AppendLine($"=== Frame {i + 1} ===")
                    fullText.AppendLine(result.Text)
                End Using
            Finally
                File.Delete(tempPath)  ' Must clean up temp files
            End Try
        Next
    End Using

    Console.WriteLine(fullText.ToString())
End Using
$vbLabelText   $csharpLabel

Enfoque IronOCR:

using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImageFrames("multipage-scan.tiff");  // All frames in one call

var result = ocr.Read(input);

foreach (var page in result.Pages)
{
    Console.WriteLine($"=== Frame {page.PageNumber} ===");
    Console.WriteLine(page.Text);
}

// Optionally save the entire multi-frame result as searchable PDF
result.SaveAsSearchablePdf("multipage-searchable.pdf");
using IronOcr;

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";

var ocr = new IronTesseract();

using var input = new OcrInput();
input.LoadImageFrames("multipage-scan.tiff");  // All frames in one call

var result = ocr.Read(input);

foreach (var page in result.Pages)
{
    Console.WriteLine($"=== Frame {page.PageNumber} ===");
    Console.WriteLine(page.Text);
}

// Optionally save the entire multi-frame result as searchable PDF
result.SaveAsSearchablePdf("multipage-searchable.pdf");
Imports IronOcr

IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"

Dim ocr As New IronTesseract()

Using input As New OcrInput()
    input.LoadImageFrames("multipage-scan.tiff")  ' All frames in one call

    Dim result = ocr.Read(input)

    For Each page In result.Pages
        Console.WriteLine($"=== Frame {page.PageNumber} ===")
        Console.WriteLine(page.Text)
    Next

    ' Optionally save the entire multi-frame result as searchable PDF
    result.SaveAsSearchablePdf("multipage-searchable.pdf")
End Using
$vbLabelText   $csharpLabel

El bucle de extracción de cuadros, la dependencia System.Drawing, la creación de archivos temporales y la lógica de limpieza son eliminados.IronOCR carga todos los marcos en una sola llamada LoadImageFrames() y expone cada marco como Page en el resultado. La guía de entrada de archivos TIFF y GIF abarca las opciones de carga de múltiples fotogramas, los rangos de fotogramas selectivos y las consideraciones de memoria para archivos TIFF grandes.

Referencia de mapeo de la API de PaddleOCR (.NET) a IronOCR

PaddleOCR (Sdcb) IronOCR Notas
Sdcb.PaddleOCR IronOcr Espacio de nombres
Sdcb.PaddleOCR.Models.Online N/A No se necesita espacio de nombres para la adquisición del modelo.
Sdcb.PaddleInference N/A No se necesita espacio de nombres de backend de inferencia
FullOcrModel N/A No existe un equivalente: los modelos se ofrecen en paquetes.
OnlineFullModels.ChineseV4.DownloadAsync() dotnet add package IronOcr.Languages.ChineseSimplified La adquisición de modelos se reemplaza por NuGet.
LocalDetectionModel.FromDirectory(path) N/A Sin gestión de rutas de modelos
LocalClassificationModel.FromDirectory(path) N/A Sin gestión de rutas de modelos
LocalRecognitionModel.FromDirectory(path) N/A Sin gestión de rutas de modelos
new PaddleOcrAll(models) new IronTesseract() Instanciación del motor
new PaddleOcrAll(models, PaddleDevice.Gpu(0)) N/A Se eliminó por completo la selección del dispositivo GPU.
PaddleDevice.Cpu() N/A La CPU es el único modo; no es necesario seleccionar
ocr.AllowRotateDetection = true input.Deskew() Corrección de rotación
ocr.Enable180Classification = true Automático La detección de posición invertida está integrada.
Cv2.ImRead(path) input.LoadImage(path) Carga de imágenes: no se requiere OpenCV.
ocr.Run(mat) ocr.Read(input) Ejecutar OCR
result.Text result.Text Cadena de texto completa del documento
result.Regions result.Pages[0].Lines o .Words Regiones de texto estructurado
region.Text word.Text / line.Text Contenido de texto de una región
region.Score (flotar 0-1) word.Confidence (entero 0-100) Valor de confianza: la escala difiere.
region.Rect.Center.X word.X Posición horizontal
region.Rect.Center.Y word.Y Posición vertical
region.Rect.Size.Width word.Width Ancho del cuadro delimitador
region.Rect.Size.Height word.Height Altura del cuadro delimitador
N/A input.LoadPdf(path) Entrada de PDF nativa (sin equivalente en PaddleOCR)
N/A input.LoadImageFrames(path) TIFF multifotograma (sin equivalente en PaddleOCR)
N/A result.SaveAsSearchablePdf(path) Salida PDF con capacidad de búsqueda (sin equivalente en PaddleOCR)

Problemas comunes de migración y soluciones

Problema 1: Discrepancia en la escala de confianza

PaddleOCR: La confianza de la región es un float de 0.0 a 1.0. Un umbral común es region.Score >= 0.8 para filtrar detecciones de baja calidad.

Solución: La confianza de IronOCR es un porcentaje de int de 0 a 100. Multiplique el umbral de PaddleOCR por 100:

// PaddleOCR: filter at 0.8
var highConfidence = result.Regions.Where(r => r.Score >= 0.8);

//IronOCR equivalent: filter at 80
var highConfidence = result.Pages
    .SelectMany(p => p.Words)
    .Where(w => w.Confidence >= 80);
// PaddleOCR: filter at 0.8
var highConfidence = result.Regions.Where(r => r.Score >= 0.8);

//IronOCR equivalent: filter at 80
var highConfidence = result.Pages
    .SelectMany(p => p.Words)
    .Where(w => w.Confidence >= 80);
' PaddleOCR: filter at 0.8
Dim highConfidence = result.Regions.Where(Function(r) r.Score >= 0.8)

' IronOCR equivalent: filter at 80
Dim highConfidence = result.Pages _
    .SelectMany(Function(p) p.Words) _
    .Where(Function(w) w.Confidence >= 80)
$vbLabelText   $csharpLabel

La confianza a nivel de documento está disponible como result.Confidence para un filtrado rápido de calidad. La guía de puntuaciones de confianza abarca umbrales por palabra y a nivel de documento.

Número 2: Supuestos sobre el orden de lectura

PaddleOCR: result.Regions se ordena por secuencia de detección, no por orden de lectura. Cualquier código que consuma result.Text esperando salida de arriba hacia abajo, de izquierda a derecha, depende del patrón de ordenamiento manual utilizado en los ejemplos de PaddleOCR.

Solución: El de IronOCRresult.Text ya está en orden de lectura. Eliminar la clasificación manual. Para los casos donde el ordenamiento se utilizó para construir una salida línea por línea, utilice result.Pages[0].Lines directamente:

// PaddleOCR: manual sort required for reading order
var lines = result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X)
    .Select(r => r.Text);

// IronOCR: reading order is the default
var lines = result.Pages[0].Lines.Select(l => l.Text);
// PaddleOCR: manual sort required for reading order
var lines = result.Regions
    .OrderBy(r => r.Rect.Center.Y)
    .ThenBy(r => r.Rect.Center.X)
    .Select(r => r.Text);

// IronOCR: reading order is the default
var lines = result.Pages[0].Lines.Select(l => l.Text);
Imports System.Linq

' PaddleOCR: manual sort required for reading order
Dim lines = result.Regions _
    .OrderBy(Function(r) r.Rect.Center.Y) _
    .ThenBy(Function(r) r.Rect.Center.X) _
    .Select(Function(r) r.Text)

' IronOCR: reading order is the default
Dim lines = result.Pages(0).Lines.Select(Function(l) l.Text)
$vbLabelText   $csharpLabel

Problema 3: Código de conversión de matriz de OpenCV

PaddleOCR: Algunas bases de código contienen métodos de ayuda que cargan imágenes desde flujos o matrices de bytes primero escribiendo en un archivo temporal y luego llamando a Cv2.ImRead(). Estos patrones existen porque Cv2.ImRead() solo acepta rutas de archivo.

Solución: OcrInput de IronOCR acepta flujos y matrices de bytes directamente. Elimine el archivo intermedio temporal:

// PaddleOCR: stream → temp file → Mat → OCR
string tempPath = Path.GetTempFileName() + ".png";
using (var fs = File.Create(tempPath))
    await imageStream.CopyToAsync(fs);
using Mat mat = Cv2.ImRead(tempPath);
PaddleOcrResult result = ocr.Run(mat);
File.Delete(tempPath);

// IronOCR: stream → OCR (no temp file)
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = ocr.Read(input);
// PaddleOCR: stream → temp file → Mat → OCR
string tempPath = Path.GetTempFileName() + ".png";
using (var fs = File.Create(tempPath))
    await imageStream.CopyToAsync(fs);
using Mat mat = Cv2.ImRead(tempPath);
PaddleOcrResult result = ocr.Run(mat);
File.Delete(tempPath);

// IronOCR: stream → OCR (no temp file)
using var input = new OcrInput();
input.LoadImage(imageStream);
var result = ocr.Read(input);
Imports System.IO
Imports OpenCvSharp
Imports IronOcr

' PaddleOCR: stream → temp file → Mat → OCR
Dim tempPath As String = Path.GetTempFileName() & ".png"
Using fs = File.Create(tempPath)
    Await imageStream.CopyToAsync(fs)
End Using
Using mat As Mat = Cv2.ImRead(tempPath)
    Dim result As PaddleOcrResult = ocr.Run(mat)
End Using
File.Delete(tempPath)

' IronOCR: stream → OCR (no temp file)
Using input As New OcrInput()
    input.LoadImage(imageStream)
    Dim result = ocr.Read(input)
End Using
$vbLabelText   $csharpLabel

La guía de entrada de flujos abarca la carga de flujos desde respuestas HTTP, blobs de bases de datos y flujos en memoria.

Problema 4: Eliminación del patrón de inicialización asíncrona

PaddleOCR: La inicialización del motor es asíncrona porque la descarga del modelo implica E/S de red. Esto fuerza la asincronía en toda la cadena de llamadas, lo que puede resultar problemático en contextos síncronos como constructores o controladores de eventos no asíncronos.

Solución: La inicialización de IronOCR es síncrona. new IronTesseract() no realiza E/S. Elimine el await y el modificador async de cualquier método cuya única operación asíncrona fuera la descarga del modelo:

// PaddleOCR: async forced by model download
public async Task<string> ExtractTextAsync(string imagePath)
{
    FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
    using PaddleOcrAll ocr = new PaddleOcrAll(models);
    using Mat mat = Cv2.ImRead(imagePath);
    return ocr.Run(mat).Text;
}

// IronOCR: synchronous — no async required unless the caller needs it
public string ExtractText(string imagePath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    return ocr.Read(input).Text;
}
// PaddleOCR: async forced by model download
public async Task<string> ExtractTextAsync(string imagePath)
{
    FullOcrModel models = await OnlineFullModels.EnglishV4.DownloadAsync();
    using PaddleOcrAll ocr = new PaddleOcrAll(models);
    using Mat mat = Cv2.ImRead(imagePath);
    return ocr.Run(mat).Text;
}

// IronOCR: synchronous — no async required unless the caller needs it
public string ExtractText(string imagePath)
{
    var ocr = new IronTesseract();
    using var input = new OcrInput();
    input.LoadImage(imagePath);
    return ocr.Read(input).Text;
}
Imports System.Threading.Tasks

' PaddleOCR: async forced by model download
Public Async Function ExtractTextAsync(imagePath As String) As Task(Of String)
    Dim models As FullOcrModel = Await OnlineFullModels.EnglishV4.DownloadAsync()
    Using ocr As New PaddleOcrAll(models)
        Using mat As Mat = Cv2.ImRead(imagePath)
            Return ocr.Run(mat).Text
        End Using
    End Using
End Function

' IronOCR: synchronous — no async required unless the caller needs it
Public Function ExtractText(imagePath As String) As String
    Dim ocr As New IronTesseract()
    Using input As New OcrInput()
        input.LoadImage(imagePath)
        Return ocr.Read(input).Text
    End Using
End Function
$vbLabelText   $csharpLabel

IronOCR también proporciona soporte asíncrono nativo a través de ocr.ReadAsync(input) cuando se necesita ejecución no bloqueante en un contexto asíncrono.

Problema 5: Limpieza del paso de compilación de Docker

PaddleOCR: El Dockerfile contiene apt-get install libopencv-dev, una instrucción COPY models/ /app/models/ y a menudo un paso de pre-descarga del modelo RUN. La imagen base es con frecuencia la imagen NVIDIA CUDA para implementaciones GPU.

Solución: Eliminar todas las instrucciones del Dockerfile específicas de PaddleOCR. La imagen Docker de IronOCR no requiere ninguna imagen base especial ni ningún paso de copia de modelo:

# PaddleOCR Dockerfile (remove all of this)
FROM nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04
RUN apt-get update && apt-get install -y libopencv-dev libgdiplus
COPY models/ /app/models/
COPY . /app

#IronOCR Dockerfile (clean)
FROM mcr.microsoft.com/dotnet/aspnet:8.0
COPY . /app
WORKDIR /app
ENTRYPOINT ["dotnet", "YourApp.dll"]

La imagen resultante reduce su tamaño de aproximadamente 1,5 GB a aproximadamente 400 MB. La guía de implementación de Docker cubre los requisitos de las bibliotecas de Linux y las compilaciones multiarquitectura.

Problema 6: Invalidación de la caché del modelo CI/CD

PaddleOCR: Las canalizaciones de CI/CD que almacenan en caché el paso de restauración de NuGet deben gestionar por separado el almacenamiento en caché de los archivos del modelo. Un patrón común es almacenar en caché una carpeta models/ entre ejecuciones. Cuando se actualiza la versión del envoltorio, la clave de caché cambia y los modelos deben volver a descargarse de los servidores de Baidu, lo que añade entre 30 y 60 segundos al proceso.

Solución:IronOCR no tiene directorio de caché de modelos. La única caché necesaria es la caché estándar de paquetes NuGet . Sin paso de caché separado, sin invalidación de caché en actualizaciones de envoltura, sin descarga desde servidores de terceros durante la CI:

# Remove from CI/CD pipeline:
# - name: Cache PaddleOCR models
#   uses: actions/cache@v3
#   with:
#     path: models/
#     key: paddleocr-models-${{env.PADDLEOCR_VERSION}}

#IronOCR only needs standard NuGet caching:
- name: Cache NuGet packages
  uses: actions/cache@v3
  with:
    path: ~/.nuget/packages
    key: nuget-${{hashFiles('**/*.csproj')}}
# Remove from CI/CD pipeline:
# - name: Cache PaddleOCR models
#   uses: actions/cache@v3
#   with:
#     path: models/
#     key: paddleocr-models-${{env.PADDLEOCR_VERSION}}

#IronOCR only needs standard NuGet caching:
- name: Cache NuGet packages
  uses: actions/cache@v3
  with:
    path: ~/.nuget/packages
    key: nuget-${{hashFiles('**/*.csproj')}}
YAML

Lista de verificación para la migración de PaddleOCR (.NET)

Pre-Migración

Antes de realizar cualquier cambio, revise el código fuente para identificar todos los usos de PaddleOCR:

# Find all PaddleOCR namespace imports
grep -rn "using Sdcb.PaddleOCR" --include="*.cs" .

# Find all OpenCvSharp imports (added as PaddleOCR dependency)
grep -rn "using OpenCvSharp" --include="*.cs" .

# Find all Mat usage patterns
grep -rn "Cv2\.ImRead\|new Mat\|Mat mat" --include="*.cs" .

# Find all async model download calls
grep -rn "DownloadAsync\|OnlineFullModels\|LocalDetectionModel" --include="*.cs" .

# Find all GPU device configuration
grep -rn "PaddleDevice\|EnableUseGpu\|cuda" --include="*.cs" .

# Find all result region access patterns
grep -rn "result\.Regions\|region\.Score\|region\.Rect" --include="*.cs" .

# Locate model directory references in configuration files
grep -rn "PP-OCRv4\|cls_infer\|det_infer\|rec_infer" --include="*.cs" --include="*.json" --include="*.yaml" .
# Find all PaddleOCR namespace imports
grep -rn "using Sdcb.PaddleOCR" --include="*.cs" .

# Find all OpenCvSharp imports (added as PaddleOCR dependency)
grep -rn "using OpenCvSharp" --include="*.cs" .

# Find all Mat usage patterns
grep -rn "Cv2\.ImRead\|new Mat\|Mat mat" --include="*.cs" .

# Find all async model download calls
grep -rn "DownloadAsync\|OnlineFullModels\|LocalDetectionModel" --include="*.cs" .

# Find all GPU device configuration
grep -rn "PaddleDevice\|EnableUseGpu\|cuda" --include="*.cs" .

# Find all result region access patterns
grep -rn "result\.Regions\|region\.Score\|region\.Rect" --include="*.cs" .

# Locate model directory references in configuration files
grep -rn "PP-OCRv4\|cls_infer\|det_infer\|rec_infer" --include="*.cs" --include="*.json" --include="*.yaml" .
SHELL

Inventarie los directorios del modelo y anote el tamaño total. Identifique qué modelos de idioma están en uso (chino, inglés, japonés, etc.) para determinar qué paquetes IronOcr.Languages.* agregar. Tenga en cuenta si la configuración de la GPU está presente; esos archivos son los que tienen mayor superficie que limpiar.

Migración de código

  1. Elimine Sdcb.PaddleOCR, Sdcb.PaddleOCR.Models.Online, Sdcb.PaddleInference.runtime.*, OpenCvSharp4 y OpenCvSharp4.runtime.* del archivo .csproj
  2. Agregue IronOcr al archivo .csproj
  3. Agregue paquetes IronOcr.Languages.* para cada idioma no inglés descargado previamente como modelo PaddleOCR
  4. Reemplace todas las directivas using Sdcb.PaddleOCR* y using OpenCvSharp por using IronOcr
  5. Agregue IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"; al inicio de la aplicación
  6. Reemplace FullOcrModel models = await OnlineFullModels.*.DownloadAsync() con nada — elimine completamente la línea
  7. Reemplace new PaddleOcrAll(models) con new IronTesseract()
  8. Reemplace new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0)) con new IronTesseract()
  9. Replace Mat mat = Cv2.ImRead(path) with var input = new OcrInput(); input.LoadImage(ruta);
  10. Reemplace ocr.Run(mat) con ocr.Read(input)
  11. Reemplace el acceso result.Regions con result.Pages[0].Lines o result.Pages[0].Words
  12. Reemplace region.Score >= threshold con word.Confidence >= threshold * 100
  13. Reemplace region.Rect.Center.X / .Center.Y con word.X / word.Y
  14. Eliminar la lógica de ordenación manual: la salida de IronOCR ya está en orden de lectura.
  15. Elimine el directorio models/ y todos los archivos de modelo del repositorio y los scripts de implementación

Posmigración

  • Verifique que dotnet build tenga éxito con cero referencias a Sdcb.*, OpenCvSharp o PaddleInference en el resultado de la compilación
  • Ejecutar el OCR en el mismo conjunto de documentos representativos utilizado para validar la salida de PaddleOCR y comparar la precisión del texto.
  • Confirme que los valores de confianza se estén leyendo como números enteros de 0 a 100 (no como números de coma flotante de 0 a 1) en todos los puntos de filtrado.
  • Verifique que el orden de lectura sea correcto sin ordenar manualmente; revise específicamente los diseños de varias columnas y de facturas.
  • Pruebe que la compilación de la imagen muy Docker se complete sin la imagen base de CUDA o apt-get install libopencv-dev
  • Confirma que el tamaño de la imagen de Docker sea inferior a 500 MB.
  • Ejecuta la canalización de CI/CD de principio a fin y verifica que no se produzcan descargas externas durante la compilación.
  • Prueba de implementación aislada: verifica que la aplicación se inicie y procese documentos sin conexiones de red salientes.
  • Para cualquier entrada TIFF de múltiples fotogramas, verifique que todos los fotogramas se procesen y que el número de fotogramas coincida con el archivo de origen.
  • Para cualquier entrada de PDF, verifique que input.LoadPdf() produzca la misma cantidad de páginas y contenido de texto que la conversión anterior basada en PdfiumViewer

Principales ventajas de migrar a IronOCR

Los artefactos de implementación se reducen en un 80 por ciento. La huella de implementación de PaddleOCR — paddle_inference.dll, DLLs de OpenCV, y tres directorios de modelo — añade 300-500 MB a cada destino de implementación. Tras la migración, el despliegue de IronOCR ocupa aproximadamente 80 MB. Las imágenes de Docker se reducen de aproximadamente 1,5 GB a aproximadamente 400 MB. El inicio de los contenedores es más rápido, los costes de almacenamiento son menores y las canalizaciones de despliegue que antes transferían 500 MB de artefactos ahora transfieren 80 MB.

El tiempo de arranque en frío se reduce de segundos a milisegundos. PaddleOCR carga tres archivos de modelo de red neuronal desde el disco en la primera inferencia, añadiendo una pausa de 3 a 5 segundos antes de que finalice la primera llamada. En funciones sin servidor, escenarios de escalado automático o cualquier contexto donde se inicien nuevas instancias bajo demanda, ese arranque en frío se paga repetidamente. El motor de IronOCR viene integrado y se inicializa en menos de un segundo. El ejemplo básico de OCR demuestra el patrón de inicialización.

La cobertura lingüística se amplía de 14 a 125 sin necesidad de infraestructura adicional. PaddleOCR admite 14 idiomas. Agregar cualquiera de los 111 idiomas que admite IronOCR más allá del límite de PaddleOCR requiere la adición de un único paquete NuGet por idioma; no se requiere la descarga del modelo, la gestión de directorios ni la sincronización de versiones. Los equipos cuyo volumen de documentos se expande a nuevos mercados no tienen que reescribir el texto ni iniciar un nuevo proyecto de infraestructura para añadir compatibilidad con OCR en polaco, vietnamita, griego o hebreo. El catálogo completo de idiomas muestra los más de 125 paquetes disponibles.

La salida PDF con capacidad de búsqueda requiere una línea. PaddleOCR devuelve regiones de texto. Convertir esas regiones en una capa PDF con capacidad de búsqueda requiere una biblioteca PDF independiente, una conversión de coordenadas de píxeles a puntos y un código de inyección de texto invisible que implica un mantenimiento permanente. Después de la migración, result.SaveAsSearchablePdf("output.pdf") reemplaza todo ese subsistema. Los flujos de trabajo de archivo de documentos escaneados, las canalizaciones de fax a PDF y las integraciones de gestión documental se benefician directamente. El tutorial en formato PDF con función de búsqueda y la entrada del blog sobre la extracción de datos en PDF cubren todas las opciones de salida.

No hay conexiones de red externas en ninguna etapa. PaddleOCR se conecta al almacenamiento de bj.bcebos.com de Baidu para descargas de modelos. En entornos donde las conexiones salientes están restringidas (redes gubernamentales, sistemas aislados, infraestructura de servicios financieros), esa conexión requiere una excepción en el firewall o un flujo de trabajo previo a la descarga que añade complejidad a la integración y entrega continuas (CI/CD).IronOCR no realiza conexiones externas en tiempo de ejecución. Los modelos se restauran como parte de dotnet restore desde NuGet y están presentes en el resultado de implementación. La guía de implementación de AWS y la guía de implementación de Azure cubren la configuración específica de la nube para entornos con restricciones de red.

Un único contacto de soporte comercial para toda la pila OCR. Los problemas de PaddleOCR abarcan el contenedor Sdcb.PaddleOCR (GitHub comunitario), el framework PaddlePaddle (Baidu), OpenCvSharp (comunitario), y CUDA/cuDNN (NVIDIA). Cada capa tiene un canal de soporte diferente, sin garantía de tiempo de respuesta.IronOCR es un producto único de Iron Software con soporte comercial por correo electrónico y niveles de respuesta prioritaria. El centro de documentación de IronOCR consolida toda la documentación de la API, las guías prácticas y los recursos para la resolución de problemas en un solo lugar.

Por favor notaPDFium, PaddleOCR, PDFSharp, Tesseract e iText son marcas registradas de sus respectivos propietarios. Este sitio no está afiliado, respaldado ni patrocinado por Baidu, Chromium Project, Google, PaddlePaddle, empira Software GmbH ni iText Group. Todos los nombres de productos, logotipos y marcas son propiedad de sus respectivos dueños. Las comparaciones son solo para fines informativos y reflejan información públicamente disponible en el momento de la redacción.

Preguntas Frecuentes

¿Por qué debería migrar de PaddleOCR a IronOCR?

Los impulsores comunes incluyen la eliminación de la complejidad de la interoperabilidad COM, la sustitución de la gestión de licencias basada en archivos, la evitación de la facturación por página, la habilitación de la implementación de Docker/contenedores y la adopción de un flujo de trabajo nativo de NuGet que se integre con las herramientas .NET estándar.

¿Cuáles son los principales cambios en el código al migrar de PaddleOCR a IronOCR?

Sustituya las secuencias de inicialización de PaddleOCR por la instanciación de IronTesseract, elimine la gestión del ciclo de vida COM (patrones explícitos Create/Load/Close) y actualice los nombres de las propiedades de los resultados. El resultado es un número significativamente menor de líneas repetitivas.

¿Cómo instalo IronOCR para comenzar la migración?

Ejecute 'Install-Package IronOcr' en la consola del gestor de paquetes o 'dotnet add package IronOcr' en la CLI. Los paquetes de idiomas son paquetes independientes: 'dotnet add package IronOcr.Languages.French' para el francés, por ejemplo.

¿IronOCR tiene la misma precisión de OCR que PaddleOCR para documentos comerciales estándar?

IronOCR consigue una gran precisión para contenido empresarial estándar, como facturas, contratos, recibos y formularios mecanografiados. Los filtros de preprocesamiento de imágenes (eliminación de distorsiones, eliminación de ruido, mejora del contraste) mejoran aún más el reconocimiento en entradas degradadas.

¿Cómo gestiona IronOCR los datos de idioma que PaddleOCR instala por separado?

Los datos de idiomas en IronOCR se distribuyen como paquetes NuGet. dotnet add package IronOcr.Languages.German' instala la compatibilidad con el alemán. No es necesario colocar manualmente los archivos ni las rutas de los directorios.

¿Requiere la migración de PaddleOCR a IronOCR cambios en la infraestructura de despliegue?

IronOCR requiere menos cambios de infraestructura que PaddleOCR. No hay rutas binarias del SDK, ubicaciones de archivos de licencia ni configuraciones del servidor de licencias. El paquete NuGet contiene el motor OCR completo, y la clave de licencia es una cadena establecida en el código de la aplicación.

¿Cómo configuro las licencias de IronOCR después de la migración?

Asigne IronOcr.License.LicenseKey = "YOUR-KEY" en el código de inicio de la aplicación. En Docker o Kubernetes, almacene la clave como una variable de entorno y léala en el inicio. Utilice License.IsValidLicense para validar antes de aceptar tráfico.

¿Puede IronOCR procesar archivos PDF del mismo modo que PaddleOCR?

Sí, IronOCR lee PDF nativos y escaneados. Instancie IronTesseract, llame a ocr.Read(input) donde input es una ruta PDF u OcrPdfInput, e itere las páginas OcrResult. No es necesario un proceso de renderizado de PDF independiente.

¿Cómo gestiona IronOCR los hilos en el procesamiento de grandes volúmenes?

IronTesseract puede instanciarse de forma segura por subproceso. Gire una instancia por hilo en un Parallel.ForEach o Task pool, ejecute OCR concurrentemente, y disponga de cada instancia cuando termine. No se requiere estado global o bloqueo.

¿Qué formatos de salida admite IronOCR tras la extracción de texto?

IronOCR devuelve resultados estructurados que incluyen texto, coordenadas de palabras, puntuaciones de confianza y estructura de páginas. Las opciones de exportación incluyen texto sin formato, PDF con opción de búsqueda y objetos de resultados estructurados para su procesamiento posterior.

¿Es el precio de IronOCR más predecible que el de PaddleOCR para escalar cargas de trabajo?

IronOCR utiliza licencias perpetuas de tarifa plana sin cargos por página o volumen. Tanto si procesa 10.000 como 10 millones de páginas, el coste de la licencia permanece constante. Las opciones de licencias por volumen y por equipo se encuentran en la página de precios de IronOCR.

¿Qué pasa con mis pruebas existentes después de migrar de PaddleOCR a IronOCR?

Las pruebas que validan el contenido de texto extraído deben seguir superándose tras la migración. Las pruebas que validan patrones de llamada a API o el ciclo de vida de objetos COM deberán actualizarse para reflejar el modelo de inicialización y resultados más sencillo de IronOCR.

Kannaopat Udonpant
Ingeniero de Software
Antes de convertirse en Ingeniero de Software, Kannapat completó un doctorado en Recursos Ambientales de la Universidad de Hokkaido en Japón. Mientras perseguía su grado, Kannapat también se convirtió en miembro del Laboratorio de Robótica de Vehículos, que es parte del Departamento de Ingeniería ...
Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame