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);
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 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 | Sí |
| 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
Si el entorno de ejecución de la GPU estaba instalado, elimínelo también:
dotnet remove package Sdcb.PaddleInference.runtime.win64.cuda118
Instale IronOCR desde la página del paquete NuGet :
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;
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"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);
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);
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})");
}
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}%)");
}
}
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);
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);
}
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}");
}
}
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.");
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}%");
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());
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");
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);
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);
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);
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;
}
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')}}
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" .
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
- Elimine
Sdcb.PaddleOCR,Sdcb.PaddleOCR.Models.Online,Sdcb.PaddleInference.runtime.*,OpenCvSharp4yOpenCvSharp4.runtime.*del archivo.csproj - Agregue
IronOcral archivo.csproj - Agregue paquetes
IronOcr.Languages.*para cada idioma no inglés descargado previamente como modelo PaddleOCR - Reemplace todas las directivas
using Sdcb.PaddleOCR*yusing OpenCvSharpporusing IronOcr - Agregue
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";al inicio de la aplicación - Reemplace
FullOcrModel models = await OnlineFullModels.*.DownloadAsync()con nada — elimine completamente la línea - Reemplace
new PaddleOcrAll(models)connew IronTesseract() - Reemplace
new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0))connew IronTesseract() - Replace
Mat mat = Cv2.ImRead(path)withvar input = new OcrInput(); input.LoadImage(ruta); - Reemplace
ocr.Run(mat)conocr.Read(input) - Reemplace el acceso
result.Regionsconresult.Pages[0].Linesoresult.Pages[0].Words - Reemplace
region.Score >= thresholdconword.Confidence >= threshold * 100 - Reemplace
region.Rect.Center.X / .Center.Yconword.X / word.Y - Eliminar la lógica de ordenación manual: la salida de IronOCR ya está en orden de lectura.
- Elimine el directorio
models/y todos los archivos de modelo del repositorio y los scripts de implementación
Posmigración
- Verifique que
dotnet buildtenga éxito con cero referencias aSdcb.*,OpenCvSharpoPaddleInferenceen 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.
