MODI OCR C# vs. IronOCR: C#에서 올바른 광학 문자 인식 라이브러리 선택하기
TesseractOCR(Sicos1977 포크)은 진정으로 활발하게 개발되고 있는 최신 .NET 래퍼입니다. 바로 이러한 점 때문에 TesseractOCR의 한계를 자세히 살펴볼 가치가 있습니다. 아카이브된 charlesw/tesseract 프로젝트와 달리, 이 포크는 .NET 6 이상을 대상으로 하며 Tesseract 5.4.1을 래핑합니다. 하지만 최신 래퍼라고 해서 Tesseract 엔진 자체의 문제가 해결되는 것은 아닙니다. charlesw에서 TesseractOCR로 프레임워크 호환성을 위해 업그레이드하는 팀들은 여전히 다음과 같은 어려운 문제들이 남아 있음을 발견합니다. tessdata 폴더 관리, 내장된 전처리 기능의 부재, 네이티브 PDF 지원 부족, 그리고 스레드 안전성이 확보되지 않아 동시 실행 시나리오에서 스레드당 하나의 인스턴스만 실행되도록 강제하는 엔진 문제 등입니다.
테서랙트OCR 이해하기
TesseractOCR은 Kees van Spelde(Sicos1977)가 유지 관리하는 Apache 2.0 라이선스의 .NET 래퍼로, 원래 charlesw/tesseract 프로젝트의 커뮤니티 포크입니다. 포크의 주된 동기는 실용적인 이유였습니다. charlesw의 활동이 2023년 이후 둔화되면서 .NET 6/7/8 개발자들은 최신 프레임워크에서 작동하는 Tesseract 바인딩을 사용할 수 없게 되었습니다. TesseractOCR은 .NET 6.0, 7.0 및 8.0을 대상으로 하고 Windows x64, Linux x64 및 macOS용 Tesseract 5.x 네이티브 라이브러리를 번들로 제공하여 이러한 격차를 해소합니다.
이 아키텍처는 P/Invoke 래퍼로, 관리되는 .NET 코드가 상호 운용성을 통해 네이티브 Tesseract C API를 호출합니다. NuGet 패키지에는 일반적인 플랫폼용 네이티브 바이너리가 포함되어 있어 기존 래퍼에서 발생했던 네이티브 라이브러리 배포 관련 어려움을 일부 해소합니다. 하지만 기본적인 설계는 여전히 테서랙트 엔진에 대한 단순한 바인딩에 그치고 있으며, 전처리 로직, PDF 파이프라인, 스레딩 추상화는 포함되어 있지 않습니다.
주요 건축적 특징:
- 단 한 명의 자원 봉사 개발자가 활발하게 유지 보수를 진행합니다 . 업데이트는 제공되지만, 서비스 수준 계약(SLA)이나 상업적 지원은 없으며, 버스 팩터는 1입니다.
- Wraps Tesseract 5.5.0 — 최신 LSTM 엔진 개선 사항을 이용할 수 있어 charlesw의 5.2.0 버전보다 유리합니다.
- .NET 6.0 이상을 대상으로 함 — 최신 프레임워크를 대상으로 하는 것이 이 포크가 존재하는 주요 이유입니다.
- 수동 tessdata 관리 필요 — 언어
.traineddata파일은 애플리케이션과 함께 별도로 다운로드 및 배포해야 합니다 - 내장 전처리 없음 — 래퍼가
engine.Process(image)를 직접 호출합니다; 이미지 품질 개선은 전적으로 개발자의 책임입니다. - 스레드 안전하지 않은 엔진 —
Engine인스턴스는 스레드 간에 공유될 수 없습니다; 각 병렬 작업자는 자체 인스턴스가 필요하므로 메모리 사용량이 증가합니다. - PDF를 기본적으로 지원하지 않습니다 . Tesseract에서 PDF를 처리하려면 별도의 라이브러리(Docnet.Core, PDFViewer)를 사용하여 페이지를 이미지로 변환해야 합니다.
- 약 20만 건의 NuGet 다운로드 와 charlesw의 약 800만 건의 다운로드를 비교해 보면, 커뮤니티 규모가 작다는 것은 Stack Overflow 답변과 튜토리얼이 적고, 기존 Tesseract 리소스를 활용하는 작업이 더 많다는 것을 의미합니다.
엔진 초기화 및 tessdata 종속성
모든 테서랙트OCR 작업은 Engine 초기화로 시작되며, 이는 외부 저장소에서 수동으로 다운로드한 언어 .traineddata 파일을 포함하는 tessdata 폴더가 필요합니다:
// tessdata/eng.traineddata must exist before this line runs
// Downloaded separately: curl -L -o tessdata/eng.traineddata
// https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile("document.png");
using var page = engine.Process(image);
string text = page.Text;
float confidence = page.MeanConfidence; // Returns 0.0-1.0 float
// tessdata/eng.traineddata must exist before this line runs
// Downloaded separately: curl -L -o tessdata/eng.traineddata
// https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile("document.png");
using var page = engine.Process(image);
string text = page.Text;
float confidence = page.MeanConfidence; // Returns 0.0-1.0 float
Imports TesseractOCR
' tessdata/eng.traineddata must exist before this line runs
' Downloaded separately: curl -L -o tessdata/eng.traineddata
' https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata
Using engine As New Engine("./tessdata", Language.English, EngineMode.Default)
Using image As Pix.Image = TesseractOCR.Pix.Image.LoadFromFile("document.png")
Using page As Page = engine.Process(image)
Dim text As String = page.Text
Dim confidence As Single = page.MeanConfidence ' Returns 0.0-1.0 float
End Using
End Using
End Using
Engine 생성자는 tessdata 디렉터리 경로와 Language 열거형 값을 받습니다. 디렉터리가 존재하지 않거나, .traineddata 파일이 없거나, 파일 버전이 Tesseract 엔진 버전과 일치하지 않으면 초기화가 예외를 발생시킵니다. 다음은 모든 Tesseract 래퍼에서 가장 흔하게 발생하는 세 가지 제작 오류이며, TesseractOCR은 이 모든 오류를 그대로 물려받았습니다. 프로젝트의 README 파일에는 엔진을 구성하기 전에 tessdata 폴더와 개별 언어 파일을 확인하는 방어적 유효성 검사 코드가 포함되어 있는데, 이는 개발자들이 이 문제를 얼마나 자주 접하는지 알려줍니다.
IronOCR 이해하기
IronOCR 최적화된 Tesseract 5 엔진과 자동 전처리, 네이티브 PDF 입출력, 스레드 안전 아키텍처를 갖춘 상 for .NET OCR 라이브러리입니다. 이 라이브러리 전체는 외부 종속성, tessdata 폴더 관리, 네이티브 라이브러리 구성 없이 단일 NuGet 패키지로 제공됩니다.
주요 특징:
- 하나의 NuGet 설치 —
dotnet add package IronOcr는 작동하는 OCR 파이프라인을 생성합니다; tessdata, 네이티브 바이너리 설정, 추가 패키지가 핵심 워크플로에 필요하지 않습니다 - 자동 전처리 — 엔진이 자동으로 기울기 보정, 노이즈 제거, 대비 향상, 이진화 및 해상도 확대/축소를 적용합니다. explicit filter methods are available when fine-grained control is needed
- 네이티브 PDF 입력 및 출력 — PDF는
OcrInput.LoadPdf()를 통해 직접 로드됩니다; 스캔된 PDF는result.SaveAsSearchablePdf()를 통해 검색 가능한 PDF 출력을 생성합니다 - 스레드 안전한
IronTesseract— 단일 인스턴스가 스레드 중복 없이 동시 요청을 처리합니다 - 125개 이상의 언어를 NuGet 패키지로 제공 - 외부 파일 다운로드 필요 없음; 언어 팩은
dotnet add package IronOcr.Languages.French를 통해 설치되고 경로 설정 없이 참조됩니다 - 영구 라이선스 — $999 Lite / $1,499 Plus / $2,999 Professional; 문서당 비용 없음, 구독료 없음
- 일관된 동작을 제공하는 크로스 플랫폼 지원 — Windows, Linux, macOS, Docker, Azure 및 AWS 모두 플랫폼별 구성 없이 동일한 패키지로 작동합니다.
기능 비교
| 기능 | 테서랙트OCR | IronOCR |
|---|---|---|
| .NET 타겟팅 | .net 6.0, 7.0, 8.0 | .NET 6.0, 7.0, 8.0, .NET Framework 4.6.2 이상 |
| 라이선스 | Apache 2.0 (무료) | 상업용 ($999+ 영구) |
| tessdata management | 필수 (수동 다운로드) | 필수 아님 (묶음 상품) |
| 내장 전처리 기능 | None | 자동 필터 + 명시적 필터 |
| 네이티브 PDF 입력 | 아니요 | 예 |
| 검색 가능한 PDF 출력 | 아니요 | 예 |
| 나사 안전 | 아니요 (스레드별 엔진) | 예 (단일 공유 인스턴스) |
상세 기능 비교
| 기능 | 테서랙트OCR | IronOCR | |
|---|---|---|---|
| 설정 및 배포 | |||
| NuGet 설치 | TesseractOCR |
IronOcr |
|
| 테스데이터 폴더 필요 | 예 | 아니요 | |
| 언어 파일 다운로드 | 매뉴얼 (GitHub) | NuGet 패키지 | |
| 네이티브 바이너리 번들링 | 부분적 (공통 플랫폼) | 전체 | |
| 단일 패키지 배포 | 아니요 (tessdata 별도) | 예 | |
| 공기 간극 환경 | 사전 준비된 tessdata가 필요합니다. | NuGet 패키지는 오프라인에서도 작동합니다. | |
| OCR 기능 | |||
| 테서랙트 엔진 버전 | 5.5.0 | 5.x (최적화됨) | |
| 자동 기울기 보정 | 아니요 | 예 | |
| 자동 소음 제거 | 아니요 | 예 | |
| 자동 대비 | 아니요 | 예 | |
| 해상도 향상 | 아니요 | 예 (EnhanceResolution(300)) |
|
| 이진화 | 아니요 | 예 | |
| PDF 지원 | |||
| PDF 입력 | 아니요 (외부 라이브러리 필요) | 예 (원어민) | |
| 비밀번호로 보호된 PDF | 아니요 (복호화 및 재처리 필요) | 예 (단일 매개변수) | |
| 검색 가능한 PDF 출력 | 아니요 | 예 | |
| 특정 페이지 범위 | 수동(페이지별 렌더링 루프) | 예 (LoadPdfPages) |
|
| 언어 지원 | |||
| 지원되는 언어 | 모든 tessdata 파일 | NuGet 통해 125개 이상 | |
| 다국어 구문 | 언어.영어\ |
언어.프랑스어 | OcrLanguage.English + OcrLanguage.French |
| 사용자 지정 언어 데이터 | 예 (파일을 tessdata에 복사하세요) | 예 (사용자 지정 언어 팩) | |
| 나사산 및 배치 | |||
| 스레드 안전 엔진 | 아니요 | 예 | |
| 병렬 처리 패턴 | 스레드별 엔진(메모리 집약적) | 단일 인스턴스, 병렬 입력 | |
| 스레드당 메모리 | 엔진 인스턴스당 약 40~100MB | 공유 인스턴스 | |
| 출력 및 결과 | |||
| 신뢰도 점수 | page.MeanConfidence (0.0-1.0) |
result.Confidence (0-100%) |
|
| 단어 수준 위치 지정 | 제한적 | 예 (단어당 X, Y, 너비, 높이) | |
| 구조화된 결과 계층 구조 | 아니요 | 페이지, 단락, 줄, 단어 | |
| OCR 중 바코드 판독 | 아니요 | 예 | |
| hOCR 내보내기 | 아니요 | 예 | |
| 지원 및 유지 관리 | |||
| 유지보수 모델 | 개인 자원봉사 개발자 | 영업팀 | |
| 상업적 지원 | 아니요 | 예 (이메일, SLA 옵션) | |
| GitHub 문제 해결 | 자원봉사 일정 | 상업 광고 일정 |
Tessdata 관리: 사라지지 않는 배포 문제
Sicos1977 포크는 Tesseract 엔진을 업데이트하고 대상 프레임워크를 현대화했습니다. 이는 언어 데이터의 작동 방식을 바꾸지는 않았습니다. TesseractOCR를 실행하는 모든 환경은 첫 번째 Engine 생성자 호출 전에 .traineddata 파일로 채워진 tessdata 폴더가 필요합니다.
테서랙트OCR 접근법
이 저장소의 basic-ocr.cs 파일에는 프로젝트가 OCR 작업 전에 실행할 것을 권장하는 ValidateTessData() 메서드가 포함되어 있습니다. 그 방어적 패턴은 실패 모드 — 파이프라인 중간에 발생하는 TesseractException —가 라이브러리 자체의 예제에서도 이를 대비하고 있을 정도로 흔하기 때문에 존재합니다:
// From BasicOcrService in tesseractocr-basic-ocr.cs
private void ValidateTessData()
{
if (!Directory.Exists(_tessDataPath))
{
throw new DirectoryNotFoundException(
$"tessdata folder not found at: {_tessDataPath}\n" +
"Download traineddata files from: https://github.com/tesseract-ocr/tessdata_best");
}
string engTrainedData = Path.Combine(_tessDataPath, "eng.traineddata");
if (!File.Exists(engTrainedData))
{
throw new FileNotFoundException(
$"eng.traineddata not found in {_tessDataPath}\n" +
"Download from: https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata");
}
}
// From BasicOcrService in tesseractocr-basic-ocr.cs
private void ValidateTessData()
{
if (!Directory.Exists(_tessDataPath))
{
throw new DirectoryNotFoundException(
$"tessdata folder not found at: {_tessDataPath}\n" +
"Download traineddata files from: https://github.com/tesseract-ocr/tessdata_best");
}
string engTrainedData = Path.Combine(_tessDataPath, "eng.traineddata");
if (!File.Exists(engTrainedData))
{
throw new FileNotFoundException(
$"eng.traineddata not found in {_tessDataPath}\n" +
"Download from: https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata");
}
}
Private Sub ValidateTessData()
If Not Directory.Exists(_tessDataPath) Then
Throw New DirectoryNotFoundException(
$"tessdata folder not found at: {_tessDataPath}" & vbCrLf &
"Download traineddata files from: https://github.com/tesseract-ocr/tessdata_best")
End If
Dim engTrainedData As String = Path.Combine(_tessDataPath, "eng.traineddata")
If Not File.Exists(engTrainedData) Then
Throw New FileNotFoundException(
$"eng.traineddata not found in {_tessDataPath}" & vbCrLf &
"Download from: https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata")
End If
End Sub
다국어 OCR은 문제를 더욱 악화시킨다. 각 언어는 고유한 .traineddata 파일이 필요하며 — 언어당 15 ~ 50MB — 파일은 올바른 저장소 버전에서 가져와야 합니다. tessdata_best 저장소는 더 높은 정확도를 제공하지만 처리 속도는 더 느립니다. tessdata_fast는 정확도를 희생하고 속도를 높입니다. 서로 다른 버전을 혼합하여 사용하거나, Tesseract 4.x용으로 빌드된 tessdata 파일을 Tesseract 5.x 엔진과 함께 사용하면 오류 신호 없이 정확도가 저하됩니다.
Docker 배포의 경우, tessdata 파일은 이미지에 포함되거나 알려진 경로에 마운트되어야 합니다. CI/CD 파이프라인의 경우, 다운로드 단계는 스크립트로 작성하고 캐시해야 합니다. 외부와 완전히 분리된 환경의 경우, 파일은 사전에 준비되어 있어야 합니다. 각 배포 구성은 오류가 발생할 수 있는 또 다른 지점입니다.
// Multi-language requires each .traineddata file pre-downloaded
// eng.traineddata + fra.traineddata + deu.traineddata all required
using var engine = new Engine(@"./tessdata",
Language.English | Language.French | Language.German,
EngineMode.Default);
// If any traineddata file is missing, this throws at construction time
using var image = TesseractOCR.Pix.Image.LoadFromFile(imagePath);
using var page = engine.Process(image);
return page.Text;
// Multi-language requires each .traineddata file pre-downloaded
// eng.traineddata + fra.traineddata + deu.traineddata all required
using var engine = new Engine(@"./tessdata",
Language.English | Language.French | Language.German,
EngineMode.Default);
// If any traineddata file is missing, this throws at construction time
using var image = TesseractOCR.Pix.Image.LoadFromFile(imagePath);
using var page = engine.Process(image);
return page.Text;
Imports TesseractOCR
' Multi-language requires each .traineddata file pre-downloaded
' eng.traineddata + fra.traineddata + deu.traineddata all required
Using engine As New Engine("./tessdata", Language.English Or Language.French Or Language.German, EngineMode.Default)
' If any traineddata file is missing, this throws at construction time
Using image As TesseractOCR.Pix.Image = TesseractOCR.Pix.Image.LoadFromFile(imagePath)
Using page As Page = engine.Process(image)
Return page.Text
End Using
End Using
End Using
IronOCR 접근법
IronOCR 언어 지원 기능을 NuGet 패키지로 제공합니다. 영어는 핵심 패키지에 포함되어 있습니다. 추가 언어는 단 하나의 명령으로 설치할 수 있으며 경로 설정이 필요하지 않습니다.
// dotnet add package IronOcr.Languages.French
// dotnet add package IronOcr.Languages.German
// 아니요 tessdata folder, no download scripts, no path validation
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
ocr.AddSecondaryLanguage(OcrLanguage.German);
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = ocr.Read(input);
return result.Text;
// dotnet add package IronOcr.Languages.French
// dotnet add package IronOcr.Languages.German
// 아니요 tessdata folder, no download scripts, no path validation
var ocr = new IronTesseract();
ocr.Language = OcrLanguage.French;
ocr.AddSecondaryLanguage(OcrLanguage.German);
using var input = new OcrInput();
input.LoadImage(imagePath);
var result = ocr.Read(input);
return result.Text;
Imports IronOcr
Dim ocr As New IronTesseract()
ocr.Language = OcrLanguage.French
ocr.AddSecondaryLanguage(OcrLanguage.German)
Using input As New OcrInput()
input.LoadImage(imagePath)
Dim result = ocr.Read(input)
Return result.Text
End Using
언어 팩은 NuGet 종속성으로, 버전이 지정되고 자동으로 복원되며 애플리케이션 바이너리와 함께 배포됩니다. 외부 GitHub 저장소도, curl 스크립트도, 출력 디렉터리로 파일을 복사하기 위한 빌드 시스템 구성도 필요 없습니다. 에어갭 배포의 경우, NuGet 패키지는 다른 패키지와 마찬가지로 비공개 피드에서 오프라인으로 복원할 수 있습니다. 다국어 가이드는 지원되는 125개 이상의 모든 언어에 대한 설정 방법을 다룹니다.
전처리: 최신 포크가 여전히 할 수 없는 것들
TesseractOCR의 Sicos1977 포크는 charlesw의 포크보다 최신 버전이며, 최신 .NET 대상으로 하고, 업데이트된 Tesseract 바이너리를 포함합니다. 개발자가 기울어지거나, 대비가 낮거나, 전화카메라 품질의 이미지를 engine.Process(image)에 전달할 때 발생하는 결과는 변화하지 않습니다. 엔진은 원시 픽셀을 가져옵니다. 테서랙트는 품질이 저하된 출력을 생성합니다. 그런 다음 개발자는 종속성 그래프에 외부 이미지 처리 라이브러리를 추가하고 전처리 코드를 작성합니다.
테서랙트OCR 접근법
이 저장소의 migration-comparison.cs 파일은 TesseractOCR에 필요한 전처리 패턴을 보여줍니다. 외부 이미지 라이브러리(이 경우 SixLabors.ImageSharp)가 추가되어야 하며, 수동 필터 매개변수가 조정되어야 하며, 전처리 된 이미지는 TesseractOCR이 읽기 전에 임시 파일에 작성되어야 합니다 - 왜냐하면 TesseractOCR.Pix.Image API는 파일 경로를 예상하기 때문입니다:
// Requires: dotnet add package SixLabors.ImageSharp
// Manual preprocessing — each parameter requires tuning per document type
using var image = Image.Load(imagePath);
image.Mutate(x => x.Grayscale());
image.Mutate(x => x.Contrast(1.5f)); // 1.5 is a guess; tune per use case
image.Mutate(x => x.GaussianBlur(0.5f)); // Denoise with blur
image.Mutate(x => x.BinaryThreshold(0.5f)); // Threshold requires manual tuning
// Deskew is NOT in ImageSharp — requires separate Hough transform implementation
// (~50-100 additional lines)
string tempPath = Path.GetTempFileName() + ".png";
try
{
image.Save(tempPath);
using var engine = new Engine(@"./tessdata", Language.English);
using var pixImage = TesseractOCR.Pix.Image.LoadFromFile(tempPath);
using var page = engine.Process(pixImage);
return page.Text;
}
finally
{
File.Delete(tempPath); // Clean up temp file
}
// Requires: dotnet add package SixLabors.ImageSharp
// Manual preprocessing — each parameter requires tuning per document type
using var image = Image.Load(imagePath);
image.Mutate(x => x.Grayscale());
image.Mutate(x => x.Contrast(1.5f)); // 1.5 is a guess; tune per use case
image.Mutate(x => x.GaussianBlur(0.5f)); // Denoise with blur
image.Mutate(x => x.BinaryThreshold(0.5f)); // Threshold requires manual tuning
// Deskew is NOT in ImageSharp — requires separate Hough transform implementation
// (~50-100 additional lines)
string tempPath = Path.GetTempFileName() + ".png";
try
{
image.Save(tempPath);
using var engine = new Engine(@"./tessdata", Language.English);
using var pixImage = TesseractOCR.Pix.Image.LoadFromFile(tempPath);
using var page = engine.Process(pixImage);
return page.Text;
}
finally
{
File.Delete(tempPath); // Clean up temp file
}
Imports SixLabors.ImageSharp
Imports SixLabors.ImageSharp.Processing
Imports TesseractOCR
Imports System.IO
' Requires: dotnet add package SixLabors.ImageSharp
' Manual preprocessing — each parameter requires tuning per document type
Dim image As Image = Image.Load(imagePath)
image.Mutate(Sub(x) x.Grayscale())
image.Mutate(Sub(x) x.Contrast(1.5F)) ' 1.5 is a guess; tune per use case
image.Mutate(Sub(x) x.GaussianBlur(0.5F)) ' Denoise with blur
image.Mutate(Sub(x) x.BinaryThreshold(0.5F)) ' Threshold requires manual tuning
' Deskew is NOT in ImageSharp — requires separate Hough transform implementation
' (~50-100 additional lines)
Dim tempPath As String = Path.GetTempFileName() & ".png"
Try
image.Save(tempPath)
Using engine As New Engine("./tessdata", Language.English)
Using pixImage As TesseractOCR.Pix.Image = TesseractOCR.Pix.Image.LoadFromFile(tempPath)
Using page As Page = engine.Process(pixImage)
Return page.Text
End Using
End Using
End Using
Finally
File.Delete(tempPath) ' Clean up temp file
End Try
TesseractOCR의 README 파일에는 불완전한 입력에 따른 정확도 저하가 명시되어 있습니다. 예를 들어 5도 기울어지면 정확도가 97%에서 65~75%로 떨어집니다. 스마트폰 카메라의 촬영 효율은 30~50%로 떨어집니다. 이는 실제 운영 환경에서 발생하는 예외적인 경우가 아니라, 스캔한 문서, 화이트보드 사진, 팩스 등의 기본 상태입니다. 정확도를 회복하려면 기울기 보정, 노이즈 감소 및 대비 정규화가 필요합니다. 기울기 보정 기능은 일반적인 .NET 이미지 라이브러리에서 제공되지 않으므로, 허프 변환을 이용한 각도 감지 알고리즘을 직접 구현해야 합니다.
IronOCR 접근법
IronOCR의 전처리 파이프라인은 OcrInput에 내장되어 있습니다. Deskew(), DeNoise(), Contrast(), 그리고 EnhanceResolution()을 호출하면 외부 라이브러리, 임시 파일, 일반 문서 유형에 대한 매개변수 조정 없이 해당 알고리즘을 적용합니다:
// 아니요 external imaging library needed
// 아니요 temp files, no manual parameter tuning
using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew(); // Automatic angle detection and correction
input.DeNoise(); // Intelligent noise removal
input.Contrast(); // 자동 대비 enhancement
input.EnhanceResolution(300); // Upscale if below 300 DPI
var result = new IronTesseract().Read(input);
return result.Text;
// 아니요 external imaging library needed
// 아니요 temp files, no manual parameter tuning
using var input = new OcrInput();
input.LoadImage(imagePath);
input.Deskew(); // Automatic angle detection and correction
input.DeNoise(); // Intelligent noise removal
input.Contrast(); // 자동 대비 enhancement
input.EnhanceResolution(300); // Upscale if below 300 DPI
var result = new IronTesseract().Read(input);
return result.Text;
Imports IronOcr
Using input As New OcrInput()
input.LoadImage(imagePath)
input.Deskew() ' Automatic angle detection and correction
input.DeNoise() ' Intelligent noise removal
input.Contrast() ' 자동 대비 enhancement
input.EnhanceResolution(300) ' Upscale if below 300 DPI
Dim result = New IronTesseract().Read(input)
Return result.Text
End Using
문서 품질 문제가 사전에 알려지지 않은 경우, 엔진은 명시적인 필터 호출 없이 자동으로 기준선 수정을 적용합니다. 이미지 품질 보정 가이드는 자동 동작 조정이 필요한 경우에 대한 매개변수 옵션과 함께 각 필터에 대해 설명합니다. 이미지 방향 보정 가이드는 특히 기울기 보정 및 회전 감지에 대해 다룹니다. 이러한 작업은 TesseractOCR을 사용한 사용자 지정 구현이 필요합니다. 저품질 스캔 예시는 까다로운 문서에서 정확도 차이가 확연히 드러납니다.
PDF 처리: 외부 라이브러리 세금
TesseractOCR은 이미지를 처리합니다. PDF 파일을 처리하지 못합니다. TesseractOCR을 사용하는 모든 PDF 워크플로는 PDF 페이지를 이미지 파일로 렌더링하기 위한 두 번째 라이브러리가 필요하며, PDF 렌더링 이미지 워크플로는 임시 파일 관리, 바이트 형식 변환 및 정리 로직이 필요합니다.
테서랙트OCR 접근법
이 저장소의 tesseractocr-pdf-processing.cs 파일은 완전한 PDF OCR 서비스를 구현합니다. 추가적인 종속성으로 Docnet.Core가 필요하며,IronOCR단 세 줄로 수행하는 작업을 약 100줄의 코드로 처리합니다. 핵심 추출 루프는 Docnet으로 PDF를 로드하고, 각 페이지를 BGRA 바이트 배열로 렌더링하며, 각 페이지를 임시 파일로 작성하고 (왜냐하면 TesseractOCR.Pix.Image.LoadFromFile는 바이트 배열이 아닌 파일 경로를 필요로하기 때문입니다), 임시 파일을 OCR 처리하여 StringBuilder에 추가하고 임시 파일을 finally block에서 삭제하는 과정을 포함합니다:
// Requires: dotnet add package TesseractOCR
// dotnet add package Docnet.Core
// Note: Docnet is MIT-licensed; iTextSharp would be AGPL
using var library = DocLib.Instance;
using var docReader = library.GetDocReader(pdfPath, new PageDimensions(dpi, dpi));
int pageCount = docReader.GetPageCount();
var allText = new StringBuilder();
var tempFiles = new List<string>();
try
{
using var engine = new Engine(_tessDataPath, Language.English, EngineMode.Default);
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++)
{
using var pageReader = docReader.GetPageReader(pageIndex);
var width = pageReader.GetPageWidth();
var height = pageReader.GetPageHeight();
var imageBytes = pageReader.GetImage(); // BGRA bytes
// TesseractOCR.Pix.Image requires a file path — write to temp
string tempPath = Path.Combine(_tempDirectory, $"page_{pageIndex}_{Guid.NewGuid()}.png");
tempFiles.Add(tempPath);
SaveBgraAsPng(imageBytes, width, height, tempPath); // ~30 lines
using var image = TesseractOCR.Pix.Image.LoadFromFile(tempPath);
using var page = engine.Process(image);
allText.AppendLine($"--- Page {pageIndex + 1} ---");
allText.AppendLine(page.Text);
}
}
finally
{
foreach (var tempFile in tempFiles)
{
try { File.Delete(tempFile); } catch { }
}
}
// Requires: dotnet add package TesseractOCR
// dotnet add package Docnet.Core
// Note: Docnet is MIT-licensed; iTextSharp would be AGPL
using var library = DocLib.Instance;
using var docReader = library.GetDocReader(pdfPath, new PageDimensions(dpi, dpi));
int pageCount = docReader.GetPageCount();
var allText = new StringBuilder();
var tempFiles = new List<string>();
try
{
using var engine = new Engine(_tessDataPath, Language.English, EngineMode.Default);
for (int pageIndex = 0; pageIndex < pageCount; pageIndex++)
{
using var pageReader = docReader.GetPageReader(pageIndex);
var width = pageReader.GetPageWidth();
var height = pageReader.GetPageHeight();
var imageBytes = pageReader.GetImage(); // BGRA bytes
// TesseractOCR.Pix.Image requires a file path — write to temp
string tempPath = Path.Combine(_tempDirectory, $"page_{pageIndex}_{Guid.NewGuid()}.png");
tempFiles.Add(tempPath);
SaveBgraAsPng(imageBytes, width, height, tempPath); // ~30 lines
using var image = TesseractOCR.Pix.Image.LoadFromFile(tempPath);
using var page = engine.Process(image);
allText.AppendLine($"--- Page {pageIndex + 1} ---");
allText.AppendLine(page.Text);
}
}
finally
{
foreach (var tempFile in tempFiles)
{
try { File.Delete(tempFile); } catch { }
}
}
Imports Docnet.Core
Imports TesseractOCR
Imports System.IO
Imports System.Text
' Requires: dotnet add package TesseractOCR
' dotnet add package Docnet.Core
' Note: Docnet is MIT-licensed; iTextSharp would be AGPL
Dim library = DocLib.Instance
Dim docReader = library.GetDocReader(pdfPath, New PageDimensions(dpi, dpi))
Dim pageCount As Integer = docReader.GetPageCount()
Dim allText As New StringBuilder()
Dim tempFiles As New List(Of String)()
Try
Using engine As New Engine(_tessDataPath, Language.English, EngineMode.Default)
For pageIndex As Integer = 0 To pageCount - 1
Using pageReader = docReader.GetPageReader(pageIndex)
Dim width = pageReader.GetPageWidth()
Dim height = pageReader.GetPageHeight()
Dim imageBytes = pageReader.GetImage() ' BGRA bytes
' TesseractOCR.Pix.Image requires a file path — write to temp
Dim tempPath As String = Path.Combine(_tempDirectory, $"page_{pageIndex}_{Guid.NewGuid()}.png")
tempFiles.Add(tempPath)
SaveBgraAsPng(imageBytes, width, height, tempPath) ' ~30 lines
Using image = TesseractOCR.Pix.Image.LoadFromFile(tempPath)
Using page = engine.Process(image)
allText.AppendLine($"--- Page {pageIndex + 1} ---")
allText.AppendLine(page.Text)
End Using
End Using
End Using
Next
End Using
Finally
For Each tempFile In tempFiles
Try
File.Delete(tempFile)
Catch
End Try
Next
End Try
암호로 보호된 PDF는 문서를 비밀번호 보호하기 위해 iText와 AGPL 라이센스, 또는 PDFSharp과 같은 제3의 라이브러리가 필요하여 추가 종속성과 추가 라이센스 평가를 추가합니다. tesseractocr-pdf-processing.cs 파일의 주석은 이와 관련하여 다음과 같이 명확하게 언급하고 있습니다. "TesseractOCR + Docnet은 암호로 보호된 PDF를 직접 처리할 수 없습니다." 다음 사항을 준수해야 합니다. 1. 암호 해독을 지원하는 PDF 라이브러리를 사용하십시오... 2. 먼저 암호를 해독하거나 제거하세요... 3. 암호 해독된 PDF를 저장합니다... 4. 그런 다음 위의 코드를 사용하여 처리하십시오.
IronOCR 접근법
IronOCR은 PDF를 기본적으로 지원합니다. 외부 라이브러리, 임시 파일, 바이트 형식 변환이 필요하지 않습니다. PDF 입력 가이드는 전체 문서, 페이지 범위, 암호로 보호된 파일 등 모든 PDF 시나리오를 다룹니다.
// 전체 PDF — native, no external library
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
string text = result.Text;
// 비밀번호로 보호된 PDF — built-in, one parameter
using var encryptedInput = new OcrInput();
encryptedInput.LoadPdf("encrypted.pdf", Password: "secret");
var encryptedResult = ocr.Read(encryptedInput);
// Specific page range — no manual loop required
using var pageInput = new OcrInput();
pageInput.LoadPdfPages(pdfPath, startPage: 1, endPage: 5);
var pageResult = ocr.Read(pageInput);
// 전체 PDF — native, no external library
var ocr = new IronTesseract();
using var input = new OcrInput();
input.LoadPdf(pdfPath);
var result = ocr.Read(input);
string text = result.Text;
// 비밀번호로 보호된 PDF — built-in, one parameter
using var encryptedInput = new OcrInput();
encryptedInput.LoadPdf("encrypted.pdf", Password: "secret");
var encryptedResult = ocr.Read(encryptedInput);
// Specific page range — no manual loop required
using var pageInput = new OcrInput();
pageInput.LoadPdfPages(pdfPath, startPage: 1, endPage: 5);
var pageResult = ocr.Read(pageInput);
Imports IronTesseract
' 전체 PDF — native, no external library
Dim ocr As New IronTesseract()
Using input As New OcrInput()
input.LoadPdf(pdfPath)
Dim result = ocr.Read(input)
Dim text As String = result.Text
End Using
' 비밀번호로 보호된 PDF — built-in, one parameter
Using encryptedInput As New OcrInput()
encryptedInput.LoadPdf("encrypted.pdf", Password:="secret")
Dim encryptedResult = ocr.Read(encryptedInput)
End Using
' Specific page range — no manual loop required
Using pageInput As New OcrInput()
pageInput.LoadPdfPages(pdfPath, startPage:=1, endPage:=5)
Dim pageResult = ocr.Read(pageInput)
End Using
스캔된 PDF — Docnet + 전처리 + OCR의 조합이 가장 힘든 테서랙트OCR 시나리오 —는 IronOCR의 전처리 파이프라인이 가장 유용한 시나리오이기도 합니다. 스캔된 PDF는 LoadPdf(), 자동 전처리, OCR, 선택적인 검색 가능한 PDF 출력을 temp 파일 관리 없이 직선형 체인으로 거칩니다. PDF OCR 예제와 검색 가능한 PDF 가이드는 TesseractOCR에는 동등한 것이 없는 result.SaveAsSearchablePdf()를 포함한 전체 워크플로를 다룹니다.
스레딩: 스레드 안전하지 않은 엔진의 메모리 비용
TesseractOCR의 Engine 는 스레드 안전하지 않습니다. basic-ocr.cs 파일에는 명시적인 경고가 있는 ThreadSafeOcrService 클래스가 포함되어 있습니다: "메모리 오버헤드: 4개의 스레드 x 50MB = 엔진에만 200MB+". 동시 TesseractOCR의 비용은 스레드당 하나의 엔진 인스턴스로, 각각 약 40-100MB의 네이티브 Tesseract 메모리를 보유하고 있으며, 각각 약 500ms의 초기화 시간이 필요합니다.
테서랙트OCR 접근법
TesseractOCR와 병렬 처리를 하려면 각 작업자 람다 내에 새로운 Engine를 생성해야 합니다.
// WARNING: Engine is NOT thread-safe — must create per thread
// Memory: _maxDegreeOfParallelism * engine footprint (~40-100MB each)
var results = new ConcurrentDictionary<string, string>();
Parallel.ForEach(
imagePaths,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
imagePath =>
{
// Per-thread engine — required, expensive (~500ms init, ~50MB memory)
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile(imagePath);
using var page = engine.Process(image);
results[imagePath] = page.Text;
});
// WARNING: Engine is NOT thread-safe — must create per thread
// Memory: _maxDegreeOfParallelism * engine footprint (~40-100MB each)
var results = new ConcurrentDictionary<string, string>();
Parallel.ForEach(
imagePaths,
new ParallelOptions { MaxDegreeOfParallelism = 4 },
imagePath =>
{
// Per-thread engine — required, expensive (~500ms init, ~50MB memory)
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile(imagePath);
using var page = engine.Process(image);
results[imagePath] = page.Text;
});
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
' WARNING: Engine is NOT thread-safe — must create per thread
' Memory: _maxDegreeOfParallelism * engine footprint (~40-100MB each)
Dim results As New ConcurrentDictionary(Of String, String)()
Parallel.ForEach(
imagePaths,
New ParallelOptions With {.MaxDegreeOfParallelism = 4},
Sub(imagePath)
' Per-thread engine — required, expensive (~500ms init, ~50MB memory)
Using engine As New Engine("./tessdata", Language.English, EngineMode.Default)
Using image As TesseractOCR.Pix.Image = TesseractOCR.Pix.Image.LoadFromFile(imagePath)
Using page As Page = engine.Process(image)
results(imagePath) = page.Text
End Using
End Using
End Using
End Sub)
단일 엔진 재사용 패턴(루프 외부에서 하나의 엔진을 생성하고 순차적으로 재사용하는 방식)은 직렬 처리에는 효과적이지만, 다른 스레드가 해당 인스턴스에 접근하면 오류가 발생합니다. 따라서 부하가 걸린 상태에서 배치 처리를 하려면 스레드별 엔진의 메모리 비용을 감수하거나, 수명 주기 관리를 철저히 하는 스레드 로컬 엔진 풀을 구현해야 합니다.
IronOCR 접근법
IronTesseract는 스레드 안전합니다. 하나의 인스턴스가 여러 개의 동시 스레드에서 오는 요청을 처리합니다.
// Single instance — thread-safe, no per-thread duplication
var ocr = new IronTesseract();
var results = new ConcurrentDictionary<string, string>();
Parallel.ForEach(imagePaths, imagePath =>
{
using var input = new OcrInput(imagePath);
results[imagePath] = ocr.Read(input).Text;
});
// Single instance — thread-safe, no per-thread duplication
var ocr = new IronTesseract();
var results = new ConcurrentDictionary<string, string>();
Parallel.ForEach(imagePaths, imagePath =>
{
using var input = new OcrInput(imagePath);
results[imagePath] = ocr.Read(input).Text;
});
Imports System.Collections.Concurrent
Imports System.Threading.Tasks
' Single instance — thread-safe, no per-thread duplication
Dim ocr As New IronTesseract()
Dim results As New ConcurrentDictionary(Of String, String)()
Parallel.ForEach(imagePaths, Sub(imagePath)
Using input As New OcrInput(imagePath)
results(imagePath) = ocr.Read(input).Text
End Using
End Sub)
멀티스레딩 예제는 해당 패턴을 보여줍니다. 4개의 병렬 워커에 필요한 메모리 용량은 엔진 인스턴스 4개가 아닌 1개입니다. 처리량이 중요한 일괄 문서 처리 파이프라인의 경우, 이는 상당한 차이입니다.
API 매핑 참조
| 테서랙트OCR | IronOCR에 상응하는 | 노트 | |
|---|---|---|---|
Engine(tessDataPath, Language.English, EngineMode.Default) |
new IronTesseract() |
tessdata 경로가 필요하지 않습니다. | |
TesseractOCR.Pix.Image.LoadFromFile(path) |
new OcrInput(path) |
더 많은 형식을 지원합니다 | |
engine.Process(image) |
ocr.Read(input) |
핵심 OCR 호출 | |
page.Text |
result.Text |
추출된 전체 텍스트 | |
page.MeanConfidence (0.0-1.0) |
result.Confidence (0-100) |
규모가 다릅니다 | |
언어.영어\ |
언어.프랑스어 | OcrLanguage.English + OcrLanguage.French |
운영자가 다릅니다 |
EngineMode.Default |
해당 없음 | 자동 선택 | |
TesseractOCR.Exceptions.TesseractException |
IronOcr.Exceptions.OcrException |
처리해야 할 예외 유형 수가 줄어듭니다. | |
| 수동 전처리(ImageSharp) | input.Deskew(), input.DeNoise(), input.Contrast() |
내장 기능, 외부 라이브러리 필요 없음 | |
Docnet GetPageReader().GetImage() + 임시 파일 |
input.LoadPdf(path) |
임시 파일 없이 네이티브 PDF로 제공됩니다. | |
| 해당 없음 | input.LoadPdf(path, Password: "secret") |
추가 라이브러리 없이는 동등한 기능을 제공하지 않습니다. | |
| 해당 없음 | result.SaveAsSearchablePdf(path) |
TesseractOCR에는 상응하는 기능이 없습니다. | |
| 해당 없음 | result.Pages, result.Lines, result.Words |
구조화된 출력 | |
| 해당 없음 | ocr.Configuration.ReadBarCodes = true |
바코드 동시 판독 | |
스레드당 Engine 인스턴스 |
단일 IronTesseract 인스턴스 |
나사산 안전장치 내장 |
팀이 TesseractOCR에서IronOCR로 전환을 고려할 때
문서 품질은 다양합니다.
TesseractOCR 통합은 고품질 300 DPI 스캔에서 원활하게 작동합니다. 문서 품질이 떨어지는 순간, 즉 평판 스캐너로 출력한 페이지가 비뚤어지거나, 명암 대비가 낮은 팩스, 휴대폰으로 찍은 영수증 사진 등이 문제가 되면 정확도 격차가 발생합니다. README 파일에 포함된 자체 벤치마크 결과에 따르면, 전처리 없이 스마트폰 카메라로 촬영한 이미지의 정확도는 30~50%까지 떨어집니다. ImageSharp 또는 SkiaSharp에서 해당 정확도를 복구하기 위해 전처리 파이프라인을 구축하고 조정하는 데에는 8~20시간의 개발 시간이 소요되며 추가적인 종속성이 발생합니다. 초기 통합 후 6개월이 지나서야 "고품질 스캔"이라는 가정이 틀렸음을 깨닫는 팀이 전형적인 테서랙트OCR 마이그레이션 사례입니다. 전처리 격차는 한 번 설정하면 해결되는 문제가 아니라, 새로운 문서 유형이나 캡처 방식이 파이프라인에 추가될 때마다 발생하는 문제입니다.
PDF 문서는 입력 워크플로의 일부입니다.
PDF OCR을 위한 Docnet.Core와 테서랙트OCR 조합은 작동하지만, 기존 코드 3줄을 대체하는 데 약 100줄의 코드가 필요합니다. 더욱 현실적인 문제는 Docnet의 라이선스(MIT), 크로스 플랫폼 호환성, 잘못된 형식의 PDF 처리 방식, 그리고 기존 tessdata 및 전처리 코드와의 상호 작용 등을 평가해야 한다는 점입니다. 문서 관리 시스템, 송장 처리 시스템 또는 PDF가 주요 입력으로 사용되는 모든 워크플로를 구축하는 팀은 외부 라이브러리 PDF 방식이 시간이 지남에 따라 페이지 크기 처리, 렌더링을 위한 DPI 선택, 임시 파일 정리 로직, 그리고 검색 가능한 PDF 출력의 부재와 같은 문제점들로 인해 어려움을 겪는다는 것을 알게 됩니다. 스캔한 파일에서 검색 가능한 PDF를 생성해야 하는 팀은 TesseractOCR만으로는 해결할 수 없습니다.
스레딩 아키텍처가 메모리 한계에 도달했습니다.
TesseractOCR에서 네 개의 동시 OCR 작업자가 하나의 이미지를 처리하기 전에 엔진 메모리에서 200~400MB를 소비합니다. 이는 처리량이 낮은 백그라운드 작업에는 문제가 되지 않습니다. 이는 여러 문서를 동시에 업로드하는 ASP.NET Core 엔드포인트나 처리량을 높이는 배치 프로세서에서 발생하는 문제입니다. 스레드별 엔진 패턴은 또한 각 새 스레드가 첫 번째 문서를 처리하기 전에 약 500ms의 초기화 비용을 지불해야 함을 의미합니다. 백그라운드 서비스로 TesseractOCR을 선택한 후 처리량을 확장해야 하는 팀은 이러한 한계에 직면하게 됩니다. 스레드 안전 엔진으로 전환하면 스레드별 오버헤드가 완전히 제거됩니다.
초기 개발 이후 배포 환경 변경 사항
TesseractOCR을 사용하려면 애플리케이션과 함께 tessdata 파일이 배포되어야 합니다. 개발자의 로컬 환경에서는 이 정도 문제는 해결 가능합니다. Docker 컨테이너에서 이는 tessdata 파일을 이미지에 포함시키거나(언어당 이미지 크기에 15~50MB 추가) 알려진 경로에 볼륨을 마운트하는 것을 의미합니다(운영 복잡성 증가). CI/CD 파이프라인에서 이는 다운로드를 스크립팅하고 캐싱하는 것을 의미합니다. Azure App Service 또는 AWS Lambda에서 tessdata 경로 구성은 개발 환경과 다를 수 있는 환경별 설정 중 하나입니다. 로컬 환경에서만 개념 증명을 진행한 후 컨테이너 또는 클라우드 배포로 전환하는 팀은 각 환경에서 tessdata 요구 사항이 다르게 작동한다는 사실을 발견합니다. IronOCR의 NuGet 기반 언어 팩은 패키지가 복원되는 모든 곳에 동일하게 배포됩니다.
지역사회 지원이 중대한 기로에 서다
TesseractOCR은 NuGet 약 20만 건의 다운로드를 기록했습니다. charlesw/tesseract에는 약 800만 개의 콘텐츠가 있습니다. Tesseract .NET 래퍼에 대한 Stack Overflow 질문, 블로그 게시물 및 GitHub 문제는 압도적으로 charlesw의 API — TesseractEngine, 아닌 Engine을 언급합니다; Pix.LoadFromFile, 아닌 TesseractOCR.Pix.Image.LoadFromFile. charlesw에게 효과적인 해결책은 TesseractOCR의 API 차이점을 고려하여 조정해야 합니다. 커뮤니티 리소스를 주요 지원 모델로 삼는 팀에게 있어 이는 상당한 마찰 요인이 됩니다.
일반적인 마이그레이션 고려사항
네임스페이스 및 클래스 대체
핵심 대체는 Engine에서 IronTesseract로, 그리고 TesseractOCR.Pix.Image.LoadFromFile()에서 OcrInput로 변경입니다. 네임스페이스 스왑 (using TesseractOCR에서 using IronOcr으로) 대부분의 참조를 찾을 수 있습니다. TesseractOCR에서 Language.English를 사용하는 경우 |Language.French(bitwise OR on a flags enum),IronOCR usesOcrLanguage.English + OcrLanguage.French(덧셈 연산자). 신뢰도 척도도 다릅니다: TesseractOCR는page.MeanConfidence을 0.0-1.0 부동 소수점으로 반환합니다; IronOCR는result.Confidence`을 0-100의 더블로 반환합니다. 신뢰도 값을 비교하는 모든 임계값 논리는 업데이트가 필요합니다.
// Before (TesseractOCR)
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile("document.png");
using var page = engine.Process(image);
float confidence = page.MeanConfidence; // 0.0 to 1.0
// After (IronOCR)
var ocr = new IronTesseract();
using var input = new OcrInput("document.png");
var result = ocr.Read(input);
double confidence = result.Confidence; // 0 to 100
// Before (TesseractOCR)
using var engine = new Engine(@"./tessdata", Language.English, EngineMode.Default);
using var image = TesseractOCR.Pix.Image.LoadFromFile("document.png");
using var page = engine.Process(image);
float confidence = page.MeanConfidence; // 0.0 to 1.0
// After (IronOCR)
var ocr = new IronTesseract();
using var input = new OcrInput("document.png");
var result = ocr.Read(input);
double confidence = result.Confidence; // 0 to 100
Imports TesseractOCR
Imports IronOcr
' Before (TesseractOCR)
Using engine As New Engine("./tessdata", Language.English, EngineMode.Default)
Using image As TesseractOCR.Pix.Image = TesseractOCR.Pix.Image.LoadFromFile("document.png")
Using page As Page = engine.Process(image)
Dim confidence As Single = page.MeanConfidence ' 0.0 to 1.0
End Using
End Using
End Using
' After (IronOCR)
Dim ocr As New IronTesseract()
Using input As New OcrInput("document.png")
Dim result As OcrResult = ocr.Read(input)
Dim confidence As Double = result.Confidence ' 0 to 100
End Using
전처리 종속성을 제거합니다.
기존 테서랙트OCR 통합에 ImageSharp 또는 SkiaSharp 전처리 파이프라인이 이미 포함되어 있는 경우, 마이그레이션 후 해당 코드를 삭제할 수 있습니다. IronOCR의 내장 Deskew(), DeNoise(), Contrast(), 그리고 EnhanceResolution() 메서드는 외부 필터 체인을 대체합니다. 전처리 된 이미지 주변의 임시 파일 생성 및 정리 코드도 제거되며 — OcrInput은 중간 파일 작성 없이 파일 경로, 바이트 배열, 스트림 또는 Bitmap를 직접 허용합니다. 이미지 필터 예제는 사용 가능한 필터와 그들 간의 등가성을 설명합니다.
PDF 외부 라이브러리를 제거하세요
PDF 렌더링을 위해 Docnet.Core 또는 PdfiumViewer를 사용하는 팀은 해당 패키지를 완전히 제거할 수 있습니다. 전체 PDF 렌더링 루프를 — DocLib.Instance, GetDocReader, GetPageReader, GetImage, SaveBgraAsPng, 임시 파일 생성, Pix.Image.LoadFromFile, engine.Process — input.LoadPdf(pdfPath)로 교체합니다. PDF 입력 가이드 와 PDF OCR 사용 사례 페이지에서는IronOCR PDF API의 모든 기능을 다룹니다. 프로젝트에서 tessdata 폴더를 삭제하고 tessdata 파일에 대한 <CopyToOutputDirectory> 빌드 구성을 제거하고 Docker 이미지에서 모든 apt-get install tesseract-ocr 단계를 제거하도록 업데이트합니다.
오류 처리 표면이 축소됩니다
TesseractOCR는 엔진 초기화 실패에 대한 TesseractOCR.Exceptions.TesseractException, 누락된 네이티브 라이브러리에 대한 DllNotFoundException, 아키텍처 불일치에 대한 BadImageFormatException를 잡아야 합니다.IronOCR자체 종속성을 번들링하고 초기화를 내부적으로 관리하므로 이러한 예외 유형은 적용되지 않습니다. 남아 있는 오류 표면은 파일 액세스 문제에 대한 표준 IOException와 OCR 특정 실패에 대한 IronOcr.Exceptions.OcrException입니다.
IronOCR의 추가 기능
이 비교에서 다룬 영역 외에도IronOCR TesseractOCR에는 없는 기능들이 포함되어 있습니다.
- 검색 가능한 PDF 출력 —
result.SaveAsSearchablePdf()은 스캔된 문서를 내장된, 선택 가능한 텍스트로 PDF로 변환합니다; TesseractOCR은 어떠한 형태의 PDF 출력도 생성하지 않습니다. - 영역 기반 OCR —
input.LoadImage("invoice.jpg", new CropRectangle(0, 0, 600, 100))은 처리를 특정 영역으로 제한합니다; 양식 필드 추출 및 구조화된 문서 구문 분석에 유용함 - OCR 중 바코드 읽기 —
ocr.Configuration.ReadBarCodes = true는 텍스트 추출과 같은 패스에서 문서에 내장된 바코드와 QR 코드를 읽습니다 - 구조화된 결과 데이터 —
result.Pages,result.Paragraphs,result.Lines, 그리고result.Words는 문서 구조를 단어별 좌표 데이터로 노출합니다; TesseractOCR은 단일 신뢰도 값을 가진 평면 텍스트 문자열을 반환합니다. - hOCR 내보내기 —
result.SaveAsHocrFile()는 하류 문서 처리 파이프라인을 위한 hOCR 형식 출력을 생성합니다 - 비동기 OCR — ASP.NET Core 통합을 위한 네이티브 async/await 지원으로 수동
Task.Run래퍼가 필요하지 않습니다 - 단어별 신뢰도 점수 — 단어 수준의 신뢰도를 통해 불확실한 추출 결과를 걸러낼 수 있습니다. TesseractOCR은 문서 수준의 평균 신뢰도만 제공합니다.
- 특수 문서 판독 — 여권, MICR 수표, 차량 번호판 판독 등 일반 OCR을 뛰어넘는 분야별 최적화 기능을 제공합니다.
.NET 호환성 및 미래 준비
TesseractOCR은 .NET 6.0, 7.0 및 8.0을 대상으로 하며, 이는 현재 활성화된 LTS 및 STS 릴리스를 모두 포함합니다.IronOCR최신 .NET 버전을 지원하며, 프레임워크 마이그레이션을 완료하지 않은 팀을 위해 .NET Framework 4.6.2 이상 버전과의 하위 호환성을 제공합니다. 두 라이브러리 모두 Windows, Linux 및 macOS에서 작동합니다.IronOCR플랫폼별 구성 없이 지원되는 모든 플랫폼에 대해 플랫폼별 최적화 기능을 NuGet 패키지에 포함하여 제공합니다. TesseractOCR은 일반적인 플랫폼용 네이티브 바이너리를 제공하지만, 흔하지 않은 Linux 배포판이나 사용자 지정 Docker 기본 이미지의 경우 추가적인 네이티브 라이브러리 구성이 필요합니다.IronOCR프로덕션 환경에 적합한 검증된 구성을 포함하는 Docker , Linux , Azure 및 AWS 배포 가이드를 게시합니다.
결론
TesseractOCR은 진정한 틈새시장을 공략합니다. Apache 2.0 라이선스가 필요하고, 깨끗하고 고품질의 이미지를 처리해야 하며, 파이프라인에 필요한 모든 전처리 작업을 구축할 수 있는 사내 이미지 처리 전문가를 보유한 프로젝트에 활발하게 유지 관리되는 최신 프레임워크 기반의 Tesseract 바인딩이 필요할 때, TesseractOCR은 올바른 선택입니다. Sicos1977 포크는 새로운 .NET 6+ 작업에 아카이브된 charlesw 프로젝트를 사용하는 것보다 훨씬 더 나은 성능을 제공합니다. 최신 엔진, 활발한 버그 수정, 진정한 크로스 플랫폼 네이티브 번들링을 지원합니다. 입력값이 깨끗하고 오픈소스만 사용하는 프로젝트의 경우, 그것으로 충분합니다.
이 비교의 논점은 더 구체적입니다. 래퍼를 업데이트해도 Tesseract 자체에서 제공하지 않는 기능은 해결되지 않습니다. tessdata 요구 사항은 변경되지 않았습니다. 스레드 안전 기능을 지원하지 않는 엔진은 변경되지 않았습니다. 전처리 과정이 없다는 점은 변함이 없습니다. PDF를 기본적으로 지원하지 않는다는 점은 변함이 없습니다. 최신 .NET 환경을 대상으로 TesseractOCR을 선택하는 팀이라도 초기 설정, 전처리 구현 및 PDF 통합에 26~56시간을 예산에 포함시켜야 합니다. 이는 charlesw를 사용할 때와 동일한 예산입니다. 최신 포크는 버전 마찰을 줄여줍니다. 이는 통합 작업을 줄여주지 않습니다.
IronOCR는 네 가지 간극을 직접 해결합니다: 언어는 NuGet 패키지로 설치되고, IronTesseract는 스레드 안전하며, 전처리는 자동으로 진행되며, PDF는 네이티브입니다. 대가는 Lite 라이선스의 $999입니다. 대부분의 실제 애플리케이션의 경우, 이러한 상충 관계는 빠르게 해소됩니다. 경쟁력 있는 가격으로 개발자가 투입하는 시간은 지속적인 유지 보수 비용을 고려하기 전에도 설정 작업만으로도 첫 주 만에 라이선스 비용을 초과하기 때문입니다.
TesseractOCR을 평가하는 모든 팀에게 중요한 질문은 해당 포크가 활발하게 운영되고 잘 관리되고 있는지 여부가 아닙니다. 실제로 그렇습니다. 핵심은 테서랙트의 기본 아키텍처가 생산 요구 사항에 부합하는지 여부입니다. 만약 답변에 품질이 다양한 문서, PDF 입력, 확장 가능한 처리량 또는 테스데이터 관리가 번거로운 배포 모델이 포함된다면, IronOCR의 접근 방식은 일회성 라이선스 비용으로 이러한 문제들을 해결해 줍니다.
자주 묻는 질문
TesseractOCR.Net이란 무엇인가요?
TesseractOCR.Net은 개발자와 기업이 이미지와 문서에서 텍스트를 추출하는 데 사용하는 OCR 솔루션입니다. 이 솔루션은 .NET 애플리케이션 개발용 IronOCR과 함께 평가된 여러 OCR 옵션 중 하나입니다.
IronOCR은 .NET 개발자를 위한 TesseractOCR.Net과 어떻게 다른가요?
IronOCR은 IronTesseract를 핵심 엔진으로 사용하는 NuGet 네이티브 .NET OCR 라이브러리입니다. TesseractOCR.Net에 비해 배포가 간편하고(SDK 설치 프로그램 없음), 정액제 요금이 적용되며, COM 상호 운용이나 클라우드 종속성이 없는 깔끔한 C# API를 제공합니다.
IronOCR이 TesseractOCR.Net보다 설정이 더 쉬운가요?
IronOCR은 단일 NuGet 패키지를 통해 설치됩니다. SDK 설치 프로그램, 복사할 라이선스 파일, 등록할 COM 구성 요소 또는 관리해야 할 별도의 런타임 바이너리가 없습니다. 전체 OCR 엔진이 패키지에 번들로 제공됩니다.
TesseractOCR.Net과 IronOCR 사이에는 어떤 정확도 차이가 있나요?
IronOCR은 표준 비즈니스 문서, 송장, 영수증, 스캔 양식에 대해 높은 인식 정확도를 달성합니다. 품질이 많이 저하된 문서나 일반적이지 않은 스크립트의 경우 정확도는 소스 품질에 따라 달라집니다. IronOCR에는 이미지 전처리 필터가 포함되어 있어 저품질 입력에 대한 인식률을 향상시킵니다.
IronOCR은 PDF 텍스트 추출을 지원하나요?
예. IronOCR은 한 번의 호출로 원본 PDF와 스캔한 PDF 이미지 모두에서 텍스트를 추출합니다. 또한 여러 페이지의 TIFF 파일, 이미지, 스트림도 지원합니다. 스캔한 PDF의 경우 OCR은 페이지별 결과 개체를 사용하여 페이지별로 적용됩니다.
TesseractOCR.Net 라이선싱은 IronOCR과 어떻게 비교되나요?
IronOCR은 페이지당 또는 스캔당 요금이 없는 정액제 영구 라이선스를 사용합니다. 대량의 문서를 처리하는 조직은 문서 양에 관계없이 동일한 라이선스 비용을 지불합니다. 자세한 내용과 볼륨 가격은 IronOCR 라이선스 페이지에서 확인할 수 있습니다.
IronOCR 어떤 언어를 지원하나요?
IronOCR은 별도의 NuGet 언어 팩을 통해 127개 언어를 지원합니다. 언어를 추가하려면 '닷넷 추가 패키지 IronOcr.Languages.{Language}' 명령 하나만 있으면 됩니다. 수동으로 파일을 배치하거나 경로를 구성할 필요가 없습니다.
.NET 프로젝트에 IronOCR 설치하는 방법은 무엇인가요?
NuGet을 통해 설치합니다: 패키지 관리자 콘솔에서 '설치-패키지 IronOcr' 또는 CLI에서 '닷넷 추가 패키지 IronOcr'을 실행합니다. 추가 언어 팩도 같은 방법으로 설치됩니다. 기본 SDK 인스톨러가 필요하지 않습니다.
IronOCR은 TesseractOCR.Net과 달리 Docker 및 컨테이너화된 배포에 적합하나요?
예. IronOCR은 NuGet 패키지를 통해 Docker 컨테이너에서 작동합니다. 라이선스 키는 환경 변수를 통해 설정됩니다. OCR 엔진 자체에는 라이선스 파일, SDK 경로 또는 볼륨 마운트가 필요하지 않습니다.
구매하기 전에 TesseractOCR.Net과 비교하여 IronOCR을 사용해 볼 수 있나요?
예. IronOCR 평가판 모드는 문서를 처리하고 출력물에 워터마크 오버레이가 포함된 OCR 결과를 반환합니다. 라이선스를 구매하기 전에 자신의 문서에서 정확성을 확인할 수 있습니다.
IronOCR은 텍스트 추출과 함께 바코드 판독을 지원하나요?
IronOCR은 텍스트 추출과 OCR에 중점을 둡니다. 바코드 판독을 위해 Iron Software는 동반 라이브러리로 IronBarcode를 제공합니다. 두 가지 모두 개별적으로 또는 Iron Suite 번들의 일부로 사용할 수 있습니다.
TesseractOCR.Net에서 IronOCR로 쉽게 마이그레이션할 수 있나요?
TesseractOCR.Net에서 IronOCR로 마이그레이션하려면 일반적으로 초기화 시퀀스를 IronTesseract 인스턴스화로 대체하고, COM 수명 주기 관리를 제거하며, API 호출을 업데이트해야 합니다. 대부분의 마이그레이션은 코드 복잡성을 크게 줄여줍니다.

