C#을 사용하여 OCR 결과 향상을 위한 이미지 품질 개선 방법
이 가이드는 .NET 개발자가 Sdcb.PaddleOCR 패키지 패밀리에서 IronOCR로 완전히 마이그레이션할 수 있도록 안내합니다. 이는 전체 교체 경로를 다룹니다. 여러 패키지로 구성된 PaddlePaddle 스택을 제거하고, 모델 파일 관리 및 GPU 구성을 없애고, OpenCV에 의존하는 추론 파이프라인을 단일 NuGet 설치로 대체합니다. 각 섹션은 독립적이므로 비교 기사를 미리 읽을 필요가 없습니다.
PaddleOCR에서 마이그레이션해야 하는 이유
Sdcb.PaddleOCR 래퍼는 PaddlePaddle의 Python 딥러닝 에코시스템과 .NET 사이의 커뮤니티 유지 브리지입니다. 이 기능은 제 역할을 하지만, 모델 파일, 네이티브 추론 바이너리, 이미지 로딩을 위한 OpenCV, 그리고 선택적인 CUDA 인프라 등 브리지에 필요한 모든 것을 혼자서 처리해야 합니다. 대부분의 .NET OCR 워크로드의 경우, 이는 프로젝트에 필요하지 않은 인프라입니다.
한 글자를 읽기 전에 세 개의 모델 디렉토리를 거칩니다. PaddleOCR의 추론 파이프라인은 탐지 모델, 방향 분류 모델, 인식 모델이라는 세 가지 신경망을 연결합니다. 각 네트워크는 .pdmodel 및 .pdiparams 파일의 개별 디렉토리이며, 이 파일들은 new PaddleOcrAll(models)가 작동 가능한 엔진으로 컴파일되기 전에 디스크에 존재해야 합니다. 이러한 파일들이 Baidu의 bj.bcebos.com 스토리지(중국)에 접속하여 비동기 다운로드 호출을 통해 도착하든 수동으로 유지되는 models/ 디렉토리 트리를 통해 도착하든, 개발자는 모델 버전 관리에 영구적으로 책임이 있습니다. Sdcb.PaddleOCR가 업데이트될 때, 이전 버전의 사전 다운로드 모델은 재다운로드가 필요할 수 있습니다.IronOCR에는 모델 파일도 없고, 모델 디렉터리도 없으며, 버전 동기화 문제도 없습니다. 엔진은 NuGet 패키지 내에 포함되어 있습니다.
OpenCV는 선택 사항이 아닙니다. 파일 경로에서 PaddleOCR 추론으로 직행하는 경로는 OpenCvSharp을 우회할 수 없습니다. 모든 이미지는 형식에 관계없이 Cv2.ImRead(path)를 통해 Mat 객체로 처리된 후에야 ocr.Run(mat)가 수용할 수 있습니다. 이는 두 개의 추가 NuGet 패키지(OpenCvSharp4 및 OpenCvSharp4.runtime.win), 플랫폼별 사용 DLL이 배포 출력에 포함되며, Dockerfile에 apt-get install libopencv-dev 라인이 추가된다는 것을 의미합니다. IronOCR는 파일 경로, 스트림, 바이트 배열 및 System.Drawing.Bitmap을 직접 수용합니다. Mat 중간자는 존재하지 않습니다.
GPU 설정은 며칠이 걸리는 작업입니다. PaddleOCR에서 광고하는 GPU 성능 수치(이미지당 50~100ms 대 CPU 300~500ms)는 실제입니다. 이를 위해서는 특정 버전의 NVIDIA 드라이버, CUDA 툴킷 11.8(12.x 버전 아님), cuDNN 8.6 이상 버전이 올바른 PATH 환경에 배치되어 있어야 하며, 별도의 GPU 런타임 NuGet 패키지가 필요합니다. Docker에서는 베이스 이미지가 nvidia/cuda:11.8.0-cudnn8-runtime-ubuntu22.04여야 하며 호스트는 nvidia-container-toolkit를 설치해야 합니다. 기존에 GPU 인프라가 없는 팀은 환경당 CUDA 구성에 2~8시간을 소요합니다.IronOCR CPU 추론에 최적화되어 있으며, 표준 하드웨어에서 이미지당 150~300ms의 처리 시간을 제공하고 GPU 설정이 전혀 필요하지 않습니다.
배포 아티팩트가 4-6배 더 큽니다. PaddleOCR 배포 출력에는 paddle_inference.dll(~200MB), paddle2onnx.dll(~5MB), opencv_world*.dll파일(~50MB 결합), 그리고 모델 디렉토리(~21MB)가 포함됩니다. Docker 이미지 하나의 크기는 약 1.5GB입니다.IronOCR배포 용량은 총 약 80MB입니다. Docker 이미지의 크기는 약 400MB입니다. CI/CD 환경에서는 이러한 차이가 더욱 두드러집니다. NuGet 패키지를 복원하는 모든 파이프라인 실행은 Baidu에서 모델을 다운로드하거나 별도로 관리되는 캐시 계층에서 가져와야 합니다.
검색 가능한 PDF 출력을 제공하지 않습니다. PaddleOCR은 이미지에서 텍스트 영역을 추출하며, 인식된 텍스트를 검색 가능한 레이어로 PDF에 삽입하는 기능을 제공하지 않습니다. PaddleOCR 출력에서 검색 가능한 PDF를 생성하려면 타사 PDF 라이브러리, 페이지별 텍스트 레이어 삽입 및 좌표 재매핑이 필요합니다. IronOCR는 한 줄로 완전히 검색 가능한 PDF를 생성합니다: result.SaveAsSearchablePdf("output.pdf").
근본적인 문제
PaddleOCR은 추론을 시작하기 전에 세 개의 모델 디렉터리를 구성해야 합니다.
// 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
IronOCR 에는 모델 파일, 모델 디렉터리, 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
IronOCR과 PaddleOCR(.NET): 기능 비교
아래 표는 마이그레이션 계획 수립 시 가장 중요한 요소들을 다루고 있습니다.
| 기능 | 패들OCR(Sdcb) | IronOCR |
|---|---|---|
| NuGet 패키지가 필요합니다. | 4-5 | 1 |
| 모델 파일이 필요합니다 | 예 (3개 디렉토리, 약 21MB) | 아니요 (패키지에 포함되어 있지 않음) |
| 모델 다운로드 소스 | 바이두 서버(bj.bcebos.com) | NuGet 복원(Iron Software) |
| OpenCV 종속성 | 필수 (OpenCvSharp4) | None |
| 이미지 입력 | Mat mat = Cv2.ImRead()을 통해 |
직접 파일 경로, 스트림, 바이트 배열 |
| 네이티브 PDF 입력 | 아니요 | 예 (input.LoadPdf()) |
| 검색 가능한 PDF 출력 | 아니요 | 예 (result.SaveAsSearchablePdf()) |
| 다중 프레임 TIFF 입력 | 프레임별 수동 루프 | input.LoadImageFrames() |
| GPU 지원 | 예 (CUDA 11.8 + cuDNN 필요) | CPU 최적화 (GPU 불필요) |
| 내장 전처리 기능 | 아니요 (신경망이 왜곡/잡음을 처리합니다) | 예 (왜곡 제거, 노이즈 제거, 대비 조정, 이진화, 선명도 향상) |
| 지원되는 언어 | 14 | 125+ |
| 언어 설치 방법 | 언어 모델당 DownloadAsync() |
dotnet add package IronOcr.Languages.* |
| 다국어 동시 | 아니요 (언어별로 별도의 모델이 있습니다) | 예 (OcrLanguage.English + OcrLanguage.French) |
| 구조화된 출력 | result.Regions (공간, 정렬되지 않음) |
페이지, 단락, 줄, 단어, 문자 |
| 자신감 점수 | 지역별 부동 소수점 값(0-1) | 단어당 백분율(0-100) |
| 바코드 판독 | 아니요 | 예 (ocr.Configuration.ReadBarCodes = true) |
| hOCR 내보내기 | 아니요 | 예 |
| 배포 규모 | 300-500MB | ~80MB |
| Docker 이미지 크기 | 약 1.5GB (CUDA 기본 사양 기준) | 약 400MB |
| 콜드 스타트 시간 | 3-5초 (모델 로딩) | 1초 미만 |
| 크로스 플랫폼 | 윈도우, 리눅스(일부) | 윈도우, 리눅스, macOS, Docker, Azure, AWS |
| .NET 호환성 | .NET 6 이상 (커뮤니티 래퍼) | .NET Framework 4.6.2 이상, .NET 5/6/7/8/9 |
| 상업적 지원 | 커뮤니티/ GitHub 이슈 | 예 (Iron Software, SLA 포함) |
| 라이선스 | Apache 2.0 (무료) | 영구 ($999 Lite / $1,499 Pro / $2,999 Enterprise) |
빠른 시작: PaddleOCR(.NET)에서IronOCR로 마이그레이션
단계 1: NuGet 패키지 교체
PaddleOCR 관련 패키지 5개를 모두 제거하세요.
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
GPU 런타임이 설치되어 있다면 그것도 제거하십시오.
dotnet remove package Sdcb.PaddleInference.runtime.win64.cuda118
dotnet remove package Sdcb.PaddleInference.runtime.win64.cuda118
NuGet 패키지 페이지 에서IronOCR설치하세요.
dotnet add package IronOcr
단계 2: 네임스페이스 업데이트
PaddleOCR 및 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
단계 3: 라이선스 초기화
애플리케이션 시작 시, 어떤 IronTesseract 인스턴스가 생성되기 전에 라이선스 초기화를 추가하십시오:
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY"
IronOCR 라이선스 페이지 에서 무료 평가판 키를 다운로드할 수 있습니다. 체험판을 사용하면 워터마크가 표시된 결과물을 얻을 수 있으며 구매 전에 모든 기능을 테스트할 수 있습니다.
코드 마이그레이션 예제
로컬 모델 경로 구성 제거
실행 시 Baidu 서버 연결을 피하기 위해 PaddleOCR 모델 파일을 미리 다운로드하는 프로젝트는 세 개의 별도 디렉터리 경로를 구성해야 합니다. 래퍼 버전이 변경될 때마다 이 설정을 업데이트해야 합니다.
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
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
models/ 디렉토리 트리, 세 개의 FromDirectory() 호출 및 버전 동기화 문제는 모두 사라집니다.IronOCR엔진은 복원 시 NuGet 패키지 내에 포함되어 있으며 런타임 경로 확인이 필요하지 않습니다. IronTesseract 설정 가이드에서 appsettings.json에 라이선스 키를 배치하는 초기화 옵션을 확인하십시오.
2단계 탐지 및 인식 파이프라인 통합
PaddleOCR의 회전 및 방향 파이프라인은 PaddleOcrAll의 속성을 통해 구성됩니다. IronOCR에서 이 행동을 복제하려면 간단한 호출 표면으로 동일한 문서 문제를 처리하는 OcrInput 전처리 방법을 사용합니다.
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
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
IronOCR의 Deskew() 메서드는 전처리 파이프라인의 일부로 회전 감지를 처리합니다. 결과의 Lines 컬렉션은 Tesseract 레이아웃 엔진에 의해 읽기 순서로 제공되어 수동 정렬 패턴을 제거합니다. 이미지 방향 보정 가이드에는 회전 및 기울기 보정 옵션의 전체 범위가 설명되어 있습니다.
GPU 및 CPU 장치 선택 제거
GPU 추론을 실행하는 PaddleOCR 애플리케이션은 가장 큰 마이그레이션 표면을 가집니다: GPU 런타임 NuGet 패키지, CUDA/cuDNN 환경 선행 조건, PaddleDevice.Gpu() 구성 호출. 이 모든 것은 마이그레이션 과정에서 제거됩니다.
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
IronOCR 접근 방식:
IronOCR 접근 방식은 위의 예와 동일합니다 — IronTesseract은 동일한 API 호출로 이 시나리오를 처리합니다. GPU 패키지, CUDA 필수 조건, 장치 선택이 필요하지 않습니다. new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0))를 new IronTesseract()로 교체하고 모든 GPU 관련 구성을 제거하십시오.
IronOCR CPU에서 이미지당 150~300ms의 처리 속도를 제공합니다. 이는 CPU에서 PaddleOCR(300~500ms)보다 빠르며, GPU 인프라 없이도 대부분의 웹 API 및 문서 파이프라인 워크로드에 충분합니다. 높은 처리량 시나리오의 경우, 속도 최적화 가이드에서는 스레드 관리 및 페이지 분할 모드 조정과 같은 구성 옵션을 다룹니다.
구조화된 문서 데이터 추출
PaddleOCR는 공간적으로 정렬된 PaddleOcrResultRegion 객체의 플랫 배열을 반환하며, 읽기 순서로 정렬되지 않습니다. 단락 수준 또는 행 수준 구조를 추출하려면 경계 상자 근접성을 기반으로 하는 수동 그룹화 논리가 필요합니다.IronOCR읽기 순서가 보장되는 계층적 결과 트리를 제공합니다.
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
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
수동으로 줄을 그룹화하는 근사 방식(Y 좌표를 픽셀 버킷 크기로 반올림하는 방식)은 테서랙트 레이아웃 엔진에 내장된 단락 분할 기능으로 대체되었습니다. 계층의 모든 수준에서 paragraph.X, paragraph.Y, paragraph.Width, 및 paragraph.Height를 통해 경계 상자 좌표를 사용할 수 있습니다. 전체 결과 트리 구조에 대한 자세한 내용은 구조화된 결과 가이드 와 이미지에서 텍스트 읽기 튜토리얼을 참조하세요.
검색 가능한 PDF 생성
PaddleOCR은 PDF 출력을 생성하지 않습니다. PaddleOCR 결과로부터 검색 가능한 PDF를 생성하려면 개별 PDF 라이브러리, region.Rect에서 PDF 페이지 단위로의 수동 좌표 매핑 및 보이지 않는 텍스트 레이어 삽입이 필요합니다.IronOCR OCR 결과에서 바로 검색 가능한 PDF 파일을 생성합니다.
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.")
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
좌표 매핑 문제, 즉 OpenCV 픽셀 좌표를 올바른 DPI의 PDF 포인트 공간으로 변환하는 문제는IronOCR에서는 발생하지 않습니다. 검색 가능한 PDF 가이드 에는 여러 페이지 출력, 암호로 보호된 PDF 및 출력 품질 설정에 대한 내용이 포함되어 있습니다. 스캔한 아카이브를 디지털화하거나 팩스를 검색 가능한 PDF로 변환하는 파이프라인을 구축하는 팀의 경우, 이 단일 메서드 호출만으로 상당한 통합 프로젝트가 필요했을 작업을 대체할 수 있습니다.
다중 프레임 TIFF 일괄 처리
여러 페이지로 구성된 TIFF 파일은 문서 스캔 워크플로에서 자주 등장합니다. PaddleOCR는 다중 프레임을 직접 지원하지 않습니다 — 각 프레임은 외부 이미지 라이브러리를 사용해 개별적으로 추출하고 별도의 Mat로 로드해야 합니다.IronOCR멀티프레임 TIFF 파일을 기본적으로 처리합니다.
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
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
프레임 추출 루프, System.Drawing 의존성, 임시 파일 생성 및 정리 로직은 모두 제거됩니다. IronOCR는 한 LoadImageFrames() 호출로 모든 프레임을 로드하고 결과에서 각 프레임을 Page로 노출합니다. TIFF 및 GIF 입력 가이드 에서는 다중 프레임 로딩 옵션, 선택적 프레임 범위, 대용량 TIFF 아카이브에 대한 메모리 고려 사항을 다룹니다.
PaddleOCR(.NET) API와IronOCR매핑 참조
| 패들OCR(Sdcb) | IronOCR | 노트 |
|---|---|---|
Sdcb.PaddleOCR |
IronOcr |
네임스페이스 |
Sdcb.PaddleOCR.Models.Online |
해당 없음 | 모델 획득 네임스페이스가 필요하지 않습니다. |
Sdcb.PaddleInference |
해당 없음 | 추론 백엔드 네임스페이스는 필요하지 않습니다. |
FullOcrModel |
해당 없음 | 동등한 모델이 없습니다. 모델들은 번들로 제공됩니다. |
OnlineFullModels.ChineseV4.DownloadAsync() |
dotnet add package IronOcr.Languages.ChineseSimplified |
모델 획득 방식이 NuGet 으로 대체되었습니다. |
LocalDetectionModel.FromDirectory(path) |
해당 없음 | 모델 경로 관리 없음 |
LocalClassificationModel.FromDirectory(path) |
해당 없음 | 모델 경로 관리 없음 |
LocalRecognitionModel.FromDirectory(path) |
해당 없음 | 모델 경로 관리 없음 |
new PaddleOcrAll(models) |
new IronTesseract() |
엔진 인스턴스화 |
new PaddleOcrAll(models, PaddleDevice.Gpu(0)) |
해당 없음 | GPU 장치 선택 기능이 완전히 제거되었습니다. |
PaddleDevice.Cpu() |
해당 없음 | CPU 모드만 지원합니다. 선택 사항 없음 |
ocr.AllowRotateDetection = true |
input.Deskew() |
회전 보정 |
ocr.Enable180Classification = true |
자동 | 거꾸로 된 물체를 감지하는 기능이 내장되어 있습니다. |
Cv2.ImRead(path) |
input.LoadImage(path) |
이미지 로딩 - OpenCV 필요 없음 |
ocr.Run(mat) |
ocr.Read(input) |
OCR 실행 |
result.Text |
result.Text |
전체 문서 텍스트 문자열 |
result.Regions |
result.Pages[0].Lines 또는 .Words |
구조화된 텍스트 영역 |
region.Text |
word.Text / line.Text |
지역의 텍스트 콘텐츠 |
region.Score (float 0-1) |
word.Confidence (int 0-100) |
신뢰도 값 - 척도에 따라 다름 |
region.Rect.Center.X |
word.X |
수평 위치 |
region.Rect.Center.Y |
word.Y |
수직 위치 |
region.Rect.Size.Width |
word.Width |
경계 상자 너비 |
region.Rect.Size.Height |
word.Height |
경계 상자 높이 |
| 해당 없음 | input.LoadPdf(path) |
PDF 원본 입력 (PaddleOCR과 같은 기능은 없음) |
| 해당 없음 | input.LoadImageFrames(path) |
멀티프레임 TIFF (PaddleOCR과 동등한 형식 없음) |
| 해당 없음 | result.SaveAsSearchablePdf(path) |
검색 가능한 PDF 출력 (PaddleOCR과 같은 기능은 없음) |
일반적인 마이그레이션 문제와 해결책
문제 1: 신뢰도 척도 불일치
PaddleOCR: 영역 신뢰도는 0.0에서 1.0까지의 float입니다. 저품질 감지를 필터링하기 위한 일반적인 임계값은 region.Score >= 0.8입니다.
솔루션:IronOCR신뢰도는 0에서 100까지의 int 비율입니다. PaddleOCR 임계값에 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)
문서 레벨 신뢰도는 빠른 품질 게이팅을 위해 result.Confidence로 사용할 수 있습니다. 신뢰도 점수 가이드는 단어별 및 문서 수준의 임계값을 다룹니다.
2번 문제: 읽기 순서에 대한 가정
PaddleOCR: result.Regions는 읽기 순서가 아닌 감지 순서로 정렬됩니다. 위에서 아래로, 왼쪽에서 오른쪽으로 출력을 기대하는 어떤 코드도 PaddleOCR 예제 전반에 사용된 수동 정렬 패턴에 의존합니다.
솔루션: IronOCR의 result.Text는 이미 읽기 순서에 있습니다. 수동 정렬 기능을 제거하세요. 줄별 출력을 빌드하기 위해 정렬이 사용된 경우, result.Pages[0].Lines을 직접 사용하십시오:
// 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)
문제 3: OpenCV Mat 변환 코드
PaddleOCR: 일부 코드베이스는 스트림 또는 바이트 배열에서 이미지를 로드하는 도움 메서드를 포함하여 먼저 임시 파일에 쓰고 나서 Cv2.ImRead()을 호출합니다. 이러한 패턴은 Cv2.ImRead()가 파일 경로만 수용하기 때문에 존재합니다.
솔루션: IronOCR의 OcrInput는 스트림과 바이트 배열을 직접 수용합니다. 임시 파일 중간체를 삭제합니다.
// 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
스트림 입력 가이드는 HTTP 응답, 데이터베이스 블롭 및 메모리 스트림에서 스트림을 로드하는 방법을 다룹니다.
이슈 4: 비동기 초기화 패턴 제거
PaddleOCR: 모델 다운로드에 네트워크 I/O가 포함되므로 엔진 초기화는 비동기적으로 진행됩니다. 이로 인해 호출 체인 전체에서 비동기 처리가 강제되는데, 이는 생성자나 비동기가 아닌 이벤트 핸들러와 같은 동기 컨텍스트에서 문제가 될 수 있습니다.
해결책:IronOCR초기화는 동기식으로 이루어집니다. new IronTesseract()는 I/O를 수행하지 않습니다. 모델 다운로드가 유일한 비동기 작업인 메서드에서 await 및 async 수정자를 제거하십시오:
// 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
IronOCR는 또한 비블로킹 실행이 정말로 필요한 비동기 컨텍스트에서 ocr.ReadAsync(input)을 통해 네이티브 비동기 지원을 제공합니다.
문제 5: Docker 빌드 단계 정리
PaddleOCR: Dockerfile에는 apt-get install libopencv-dev, COPY models/ /app/models/ 명령어, 종종 모델 사전 다운로드 RUN 단계가 포함되어 있습니다. 기본 이미지는 GPU 배포를 위한 NVIDIA CUDA 이미지인 경우가 많습니다.
해결 방법: PaddleOCR 관련 Dockerfile 명령어를 모두 제거하십시오.IronOCR Docker 이미지는 특별한 기본 이미지나 모델 복사 단계가 필요하지 않습니다.
# 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"]
결과적으로 이미지 크기는 약 1.5GB에서 약 400MB로 줄어듭니다. Docker 배포 가이드는 Linux 라이브러리 요구 사항 및 다중 아키텍처 빌드에 대해 다룹니다.
이슈 6: CI/CD 모델 캐시 무효화
PaddleOCR: NuGet 복원 단계를 캐시하는 CI/CD 파이프라인은 모델 파일 캐싱을 별도로 관리해야 합니다. 일반적인 패턴은 실행 간에 models/ 폴더를 캐시하는 것입니다. 래퍼 버전이 업데이트되면 캐시 키가 변경되고 모델을 바이두 서버에서 다시 다운로드해야 하므로 파이프라인에 30~60초가 추가됩니다.
해결책:IronOCR에는 모델 캐시 디렉터리가 없습니다. 필요한 캐시는 표준 NuGet 패키지 캐시뿐입니다. 별도의 캐시 단계 없음, 래퍼 업데이트 시 캐시 무효화 없음, 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')}}
PaddleOCR(.NET) 마이그레이션 체크리스트
사전 마이그레이션
변경 작업을 하기 전에 코드베이스를 검토하여 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" .
모델 디렉토리를 인벤토리하고 총 크기를 기록하십시오. 사용 중인 언어 모델(중국어, 영어, 일본어 등)을 식별하여 추가할 IronOcr.Languages.* 패키지를 결정합니다. GPU 구성 정보가 있는지 확인하십시오. 해당 파일은 정리해야 할 부분이 가장 많습니다.
코드 마이그레이션
Sdcb.PaddleOCR,Sdcb.PaddleOCR.Models.Online,Sdcb.PaddleInference.runtime.*,OpenCvSharp4,OpenCvSharp4.runtime.*를.csproj파일에서 제거하십시오IronOcr를.csproj파일에 추가하십시오- 이전에 PaddleOCR 모델로 다운로드한 모든 비-영어 언어에 대한
IronOcr.Languages.*패키지를 추가하십시오 - 모든
using Sdcb.PaddleOCR*및using OpenCvSharp지시문을using IronOcr로 교체하십시오 - 애플리케이션 시작 시
IronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";를 추가하십시오 FullOcrModel models = await OnlineFullModels.*.DownloadAsync()를 아무것도 남기지 않게 교체 — 줄을 완전히 제거하십시오new PaddleOcrAll(models)를new IronTesseract()로 교체하십시오new PaddleOcrAll(models, PaddleDevice.Gpu(deviceId: 0))를new IronTesseract()로 교체하십시오Mat mat = Cv2.ImRead(path)를 바꾸세요. `var input = new OcrInput(); input.LoadImage(path);ocr.Run(mat)를ocr.Read(input)로 교체하십시오result.Regions접근을result.Pages[0].Lines또는result.Pages[0].Words으로 교체하세요region.Score >= threshold를word.Confidence >= threshold * 100로 교체하세요region.Rect.Center.X / .Center.Y를word.X / word.Y로 교체하세요- 수동 정렬 로직 제거 —IronOCR출력은 이미 읽기 순서대로 정렬되어 있습니다.
models/디렉토리와 모든 모델 파일을 리포지토리 및 배포 스크립트에서 제거하십시오
마이그레이션 이후
- 빌드 출력에
Sdcb.*,OpenCvSharp또는PaddleInference의 참고가 없는 상태로dotnet build이 성공하는지 확인하십시오 - PaddleOCR 출력 검증에 사용된 동일한 대표 문서 세트에 대해 OCR을 실행하고 텍스트 정확도를 비교합니다.
- 모든 필터 지점에서 신뢰도 값이 0~100 사이의 정수(0~1의 부동소수점이 아님)로 읽히는지 확인하십시오.
- 수동 정렬 없이 읽기 순서가 올바른지 확인하십시오. 특히 다단 형식 및 송장 레이아웃을 확인하십시오.
- CUDA 기본 이미지나
apt-get install libopencv-dev없이 Docker 이미지 빌드가 완료되는지 테스트하십시오 - Docker 이미지 크기가 500MB 미만인지 확인하십시오.
- CI/CD 파이프라인을 처음부터 끝까지 실행하고 빌드 중에 외부 다운로드가 발생하지 않는지 확인합니다.
- 에어갭 배포 테스트: 외부 네트워크 연결 없이 애플리케이션이 시작되고 문서를 처리하는지 확인합니다.
- 다중 프레임 TIFF 입력의 경우, 모든 프레임이 처리되었는지, 그리고 프레임 수가 원본 파일과 일치하는지 확인하십시오.
- PDF 입력의 경우,
input.LoadPdf()가 이전 PdfiumViewer 기반 변환과 동일한 페이지 수 및 텍스트 콘텐츠를 생성하는지 확인하십시오
IronOCR로 마이그레이션할 때의 주요 이점
배포 아티팩트가 80% 감소합니다. PaddleOCR 배포 점유 영역 — paddle_inference.dll, OpenCV DLL 및 세 개의 모델 디렉토리 — 모든 배포 대상에 300-500MB를 추가합니다. 마이그레이션 후IronOCR배포 용량은 약 80MB입니다. Docker 이미지 크기가 약 1.5GB에서 약 400MB로 줄었습니다. 컨테이너 시작 속도가 빨라지고 스토리지 비용이 절감되며, 이전에는 500MB의 아티팩트를 전송하던 배포 파이프라인이 이제 80MB만 전송합니다.
콜드 스타트 시간이 수 초에서 밀리초로 단축되었습니다. PaddleOCR은 첫 번째 추론 시 디스크에서 세 개의 신경망 모델 파일을 로드하며, 첫 번째 호출이 반환되기 전에 3~5초의 일시 중지 시간을 추가합니다. 서버리스 함수, 자동 확장 시나리오 또는 필요에 따라 새 인스턴스가 생성되는 모든 환경에서는 콜드 스타트 비용이 반복적으로 발생합니다. IronOCR의 엔진은 패키지에 포함되어 있으며 1초 이내에 초기화됩니다. 기본 OCR 예제는 초기화 패턴을 보여줍니다.
인프라 작업 없이 언어 지원 범위가 14개에서 125개로 확장되었습니다. PaddleOCR은 현재 14개 언어를 지원합니다. PaddleOCR에서 지원하는 111개 언어를 넘어IronOCR에서 지원하는 언어를 추가하는 것은 언어당 하나의 NuGet 패키지만 추가하면 됩니다. 모델 다운로드, 디렉터리 관리, 버전 동기화는 필요하지 않습니다. 문서량이 새로운 시장으로 확장되는 팀은 폴란드어, 베트남어, 그리스어 또는 히브리어 OCR 지원을 추가하기 위해 문서를 다시 작성하거나 새로운 인프라 구축 프로젝트를 진행할 필요가 없습니다. 전체 언어 카탈로그에는 사용 가능한 125개 이상의 팩이 모두 표시됩니다.
검색 가능한 PDF 출력을 위해서는 한 줄이 필요합니다. PaddleOCR은 텍스트 영역을 반환합니다. 해당 영역을 검색 가능한 PDF 레이어로 변환하려면 별도의 PDF 라이브러리, 픽셀-포인트 좌표 변환, 그리고 영구적인 유지 관리가 필요한 보이지 않는 텍스트 삽입 코드가 필요합니다. 마이그레이션 후, result.SaveAsSearchablePdf("output.pdf")이 전체 하위 시스템을 대체합니다. 스캔 문서 보관 워크플로, 팩스-PDF 변환 파이프라인, 문서 관리 통합 기능 모두 직접적인 이점을 얻습니다. 검색 가능한 PDF 생성 방법 및 PDF 데이터 추출 관련 블로그 게시물에서 모든 출력 옵션을 다룹니다.
어떤 단계에서도 외부 네트워크 연결이 없습니다. PaddleOCR는 모델 다운로드를 위해 Baidu의 bj.bcebos.com 스토리지에 연결됩니다. 정부 네트워크, 에어갭 시스템, 금융 서비스 인프라와 같이 외부 연결이 제한된 환경에서는 방화벽 예외를 설정하거나 CI/CD의 복잡성을 증가시키는 사전 다운로드 워크플로를 구축해야 합니다. IronOCR는 실행 중에 외부 연결을 하지 않습니다. 모델은 NuGet에서 dotnet restore의 일부로 복원되며, 배포 출력에 포함됩니다. AWS 배포 가이드 와 Azure 배포 가이드는 네트워크 제약이 있는 환경에 대한 클라우드별 구성을 다룹니다.
전체 OCR 스택에 대해 하나의 상업적 지원 연락처. PaddleOCR 문제는 Sdcb.PaddleOCR 래퍼(커뮤니티 GitHub), PaddlePaddle 프레임워크(Baidu), OpenCvSharp(커뮤니티) 및 CUDA/cuDNN(NVIDIA)까지 연결되며 포함됩니다. 각 계층마다 지원 채널이 다르며 응답 시간을 보장하지 않습니다.IronOCR은 Iron Software 의 단일 제품으로, 상용 이메일 지원 및 우선 응답 등급을 제공합니다. IronOCR 문서 허브는 모든 API 문서, 사용 방법 가이드 및 문제 해결 자료를 한 곳에 통합합니다.
자주 묻는 질문
PaddleOCR에서 IronOCR로 마이그레이션해야 하는 이유는 무엇인가요?
일반적인 동인으로는 COM 상호 운용의 복잡성 제거, 파일 기반 라이선스 관리 대체, 페이지당 과금 방지, Docker/컨테이너 배포 활성화, 표준 .NET 툴링과 통합되는 NuGet 네이티브 워크플로 채택 등이 있습니다.
PaddleOCR에서 IronOCR로 마이그레이션할 때 주요 코드 변경 사항은 무엇인가요?
PaddleOCR 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리(명시적 생성/로드/폐쇄 패턴)를 제거하고, 결과 속성 이름을 업데이트합니다. 그 결과 상용구 줄이 훨씬 줄어듭니다.
마이그레이션을 시작하려면 IronOCR을 어떻게 설치하나요?
패키지 관리자 콘솔에서 '설치-패키지 IronOcr'을 실행하거나 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행하세요. 언어 팩은 별도의 패키지입니다: 예를 들어 프랑스어의 경우 '닷넷 추가 패키지 IronOcr.Languages.French'를 실행합니다.
IronOCR은 표준 비즈니스 문서에 대해 PaddleOCR의 OCR 정확도와 일치하나요?
IronOCR은 송장, 계약서, 영수증, 타이핑된 양식 등 표준 비즈니스 콘텐츠에 대해 높은 정확도를 달성합니다. 이미지 전처리 필터(데스큐, 노이즈 제거, 대비 향상)는 품질이 저하된 입력에 대한 인식률을 더욱 향상시킵니다.
IronOCR은 별도로 설치하는 언어 데이터를 어떻게 처리하나요?
IronOCR의 언어 데이터는 NuGet 패키지로 배포됩니다. '닷넷 추가 패키지 IronOcr.Languages.German'은 독일어 지원을 설치합니다. 수동 파일 배치나 디렉터리 경로는 필요하지 않습니다.
PaddleOCR에서 IronOCR로 마이그레이션하려면 배포 인프라를 변경해야 하나요?
IronOCR은 PaddleOCR보다 인프라 변경이 덜 필요합니다. SDK 바이너리 경로, 라이선스 파일 배치 또는 라이선스 서버 구성이 필요하지 않습니다. NuGet 패키지에는 완전한 OCR 엔진이 포함되어 있으며 라이선스 키는 애플리케이션 코드에 설정된 문자열입니다.
마이그레이션 후 IronOCR 라이선싱은 어떻게 구성하나요?
애플리케이션 시작 코드에 IronOcr.License.LicenseKey = "YOUR-KEY"를 할당하세요. Docker 또는 Kubernetes에서 키를 환경 변수로 저장하고 시작 시 키를 읽습니다. 트래픽을 수락하기 전에 License.IsValidLicense를 사용하여 유효성을 검사하세요.
IronOCR은 PaddleOCR과 동일한 방식으로 PDF를 처리할 수 있나요?
예. IronOCR은 원본 및 스캔한 PDF를 모두 읽습니다. IronTesseract를 인스턴스화하고, 입력이 PDF 경로 또는 OcrPdfInput인 경우 ocr.Read(input)를 호출하고, OcrResult 페이지를 반복하면 됩니다. 별도의 PDF 렌더링 파이프라인이 필요하지 않습니다.
IronOCR은 대량 처리에서 스레딩을 어떻게 처리하나요?
IronTesseract는 스레드별로 인스턴스화해도 안전합니다. Parallel.ForEach 또는 Task 풀에서 스레드당 하나의 인스턴스를 스핀업하고, OCR을 동시에 실행하고, 완료되면 각 인스턴스를 폐기하면 됩니다. 전역 상태나 잠금이 필요하지 않습니다.
IronOCR은 텍스트 추출 후 어떤 출력 형식을 지원하나요?
IronOCR은 텍스트, 단어 좌표, 신뢰도 점수, 페이지 구조를 포함한 구조화된 결과를 반환합니다. 내보내기 옵션에는 일반 텍스트, 검색 가능한 PDF, 다운스트림 처리를 위한 구조화된 결과 개체가 포함됩니다.
워크로드 확장에 대해 IronOCR 가격이 PaddleOCR보다 더 예측 가능한가요?
IronOCR은 페이지당 또는 볼륨당 요금이 없는 정액제 영구 라이선스를 사용합니다. 10,000페이지를 처리하든 1,000만 페이지를 처리하든 라이선스 비용은 일정하게 유지됩니다. 볼륨 및 팀 라이선스 옵션은 IronOCR 가격 페이지에서 확인할 수 있습니다.
PaddleOCR에서 IronOCR로 마이그레이션한 후 기존 테스트는 어떻게 되나요?
추출된 텍스트 콘텐츠에 대해 어설트하는 테스트는 마이그레이션 후에도 계속 통과해야 합니다. API 호출 패턴 또는 COM 개체 수명 주기의 유효성을 검사하는 테스트는 IronOCR의 더 간단한 초기화 및 결과 모델을 반영하도록 업데이트해야 합니다.

