フッターコンテンツにスキップ
ビデオ

Migrating from GdPicture.NET to IronOCR

このガイドは、.NET開発者にSdcb.PaddleOCRパッケージファミリーからIronOCRへの完全な移行を案内します。 これは、完全な置き換えパスを網羅しています。つまり、複数のパッケージからなるPaddlePaddleスタックの削除、モデルファイル管理とGPU構成の排除、そしてOpenCVに依存する推論パイプラインを単一のNuGetインストールに置き換えることです。 各セクションは独立しており、比較記事を事前に読む必要はありません。

PaddleOCRから移行する理由

Sdcb.PaddleOCRラッパーは、PaddlePaddle for Pythonディープラーニングエコシステムと.NETの間のコミュニティによって維持される橋渡しです。 それは目的を果たすものの、モデルファイル、ネイティブ推論バイナリ、画像読み込み用のOpenCV、そしてオプションのCUDAインフラストラクチャなど、その橋梁全体の重量を背負うことになる。 ほとんど for .NET OCRワークロードにとって、それはプロジェクトでは決して必要とされなかったインフラストラクチャです。

1文字を読み取る前に3つのモデルディレクトリを経由します。PaddleOCRの推論パイプラインは、検出モデル、方向分類モデル、認識モデルという3つのニューラルネットワークを連結しています。 各ネットワークは、models/ディレクトリツリーを通じて提供されるかにかかわらず、開発者はモデルのバージョン管理を常に担います。 Sdcb.PaddleOCRが更新されると、以前のバージョンから先にダウンロードされたモデルを再ダウンロードする必要があるかもしれません。 IronOCRにはモデルファイルもモデルディレクトリもなく、バージョン同期の問題もありません。 エンジンはNuGetパッケージに同梱されています。

OpenCVはオプションではありません。 OpenCvSharpを迂回してPaddleOCR推論へファイルパスから移行する経路はありません。すべての画像は形式にかかわらずocr.Run(mat)が受け入れることができます。 これは、2つの追加のNuGetパッケージ(System.Drawing.Bitmapを直接受け入れます。 Mat仲介は存在しません。

GPU構成は数日かかる作業です。PaddleOCRが宣伝しているGPUパフォーマンスの数値(画像1枚あたり50~100msに対し、CPUでは300~500ms)は本当です。 そこを実現するには、特定のバージョンのNVIDIAドライバー、CUDA Toolkit 11.8(12.xではない)、正しいPATHの場所に配置されたcuDNN 8.6以降、および別のGPUランタイムNuGetパッケージが必要です。 Dockerでは、ベースイメージはnvidia-container-toolkitがインストールされている必要があります。 既存のGPUインフラストラクチャを持たないチームは、環境ごとにCUDA構成に2~8時間を費やしている。 IronOCRはCPU推論向けに設計されており、標準的なハードウェアで画像1枚あたり150~300ミリ秒の処理速度を実現し、GPUの設定は一切不要です。

デプロイメントアーティファクトは4-6倍の大きさです。 PaddleOCRのデプロイメント出力にはopencv_world*.dllファイル(合計約50MB)、およびモデルディレクトリ(約21MB)が含まれます。 Dockerイメージのサイズは約1.5GBです。 IronOCRのデプロイメントに必要な総容量は約80MBです。 Dockerイメージのサイズは約400MBです。 CI/CDでは、その違いがNuGet顕著になります。NuGetパッケージを復元するパイプラインの実行ごとに、Baiduからモデルをダウンロードするか、別途管理されているキャッシュレイヤーからモデルを取得する必要があります。

検索可能なPDF出力はありません。PaddleOCRは画像からテキスト領域を返しますが、認識したテキストを検索可能なレイヤーとしてPDFに埋め込む機能はありません。 PaddleOCRの出力から検索可能なPDFを作成するには、サードパーティ製のPDFライブラリ、ページごとのテキストレイヤーの挿入、および座標の再マッピングが必要です。 IronOCRは1行のコードで完全に検索可能なPDFを生成します:result.SaveAsSearchablePdf("output.pdf")

基本的な問題

PaddleOCRでは、推論を開始する前に3つのモデルディレクトリを設定する必要があります。

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

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

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

IronOCRにはモデルファイルもモデルディレクトリもOpenCVへの依存関係もありません。

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

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

IronOCRとPaddleOCR(.NET)の機能比較

以下の表は、移行計画において最も重要な要素を網羅しています。

フィーチャー パドルOCR(Sdcb) IronOCR
必要なNuGetパッケージ 4-5 1
モデルファイルが必要です はい(3つのディレクトリ、約21MB) いいえ(パッケージに同梱されています)
モデルのダウンロード元 Baiduサーバー(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秒未満
クロスプラットフォーム Windows、Linux(一部対応) Windows、Linux、macOS、Docker、Azure、AWS
.NET互換性 .NET 6以降(コミュニティラッパー) .NET Framework 4.6.2以降、 .NET 5/6/7/8/9
商用サポート コミュニティ / GitHub の問題 はい(Iron Software、SLA付き)
ライセンス アパッチ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
SHELL

GPUランタイムがインストールされている場合は、それも削除してください。

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

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
$vbLabelText   $csharpLabel

ステップ 3: ライセンスの初期化

アプリケーションの起動時に一度、ライセンスの初期化を行ってください。IronTesseractインスタンスが作成される前に行う必要があります:

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

IronOCRのライセンスページから無料トライアルキーを入手できます。 試用版では透かし入りの出力が得られ、購入前に全機能を試すことができます。

コード移行の例

ローカルモデルパス構成の削除

実行時に Baidu サーバーへの接続を回避するために PaddleOCR モデルファイルを事前にダウンロードするプロジェクトでは、3 つの別々のディレクトリ パスを設定する必要があります。 この設定は、ラッパーのバージョンが変更されるたびに更新する必要があります。

PaddleOCRのアプローチ:

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

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

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

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

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

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

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

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

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

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

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

End Using
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

// なし 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);
// なし 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

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

Dim ocr As New IronTesseract()

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

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

FromDirectory()呼び出し、およびバージョン同期の問題はすべて消えます。 IronOCRエンジンは復元時にNuGetパッケージ内にバンドルされるため、実行時のパス解決は不要です。 ライセンスキーの場所をappsettings.jsonに含む初期化オプションについては、IronTesseractセットアップガイドを参照してください。

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
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

Dim ocr As New IronTesseract()

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

    Dim result = ocr.Read(input)

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

IronOCRの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
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

*IronOCRのアプローチは上記の例と同じです。IronTesseractは同じAPI呼び出しでこのシナリオを処理します。 GPUパッケージ、CUDAの前提条件、デバイスの選択は不要です。 new IronTesseract()に置き換え、すべてのGPU関連の構成を削除します。

IronOCRはCPU上で画像1枚あたり150~300msの処理速度を実現しており、CPU上のPaddleOCR(300~500ms)よりも高速で、GPUインフラストラクチャがなくても、ほとんどのWeb 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);

// なし 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);

// なし 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)

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

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

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

            lineGroups(lineKey).Add(region)
        Next

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

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

IronOCRのアプローチ:

using IronOcr;

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

Dim ocr As New IronTesseract()

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

    Dim result = ocr.Read(input)

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

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

手動で行をグループ化する近似処理(Y座標をピクセル単位のバケットサイズに丸める)は、Tesseractレイアウトエンジンに組み込まれている段落分割機能に置き換えられました。 定界ボックスの座標は、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);

// なし 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);

// なし 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)

        ' なし 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.")
    End Using
End Using
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

Dim ocr As New IronTesseract()

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

    Dim result = ocr.Read(input)

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

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

IronOCRには、座標マッピングの問題(OpenCVのピクセル座標を正しいDPIのPDFポイント空間に変換すること)は存在しません。 検索可能なPDFガイドでは、複数ページ出力、パスワード保護付きPDF、出力品質設定について解説しています。 スキャンされたアーカイブをデジタル化するチームや、ファックスを検索可能なPDFに変換するパイプラインを構築するチームにとって、この単一のメソッド呼び出しは、そうでなければ大規模な統合プロジェクトとなるであろう作業を不要にします。

複数フレームTIFFバッチ処理

複数ページのTIFFファイルは、文書スキャンワークフローで頻繁に登場します。 PaddleOCRにはTIFFのマルチフレームの直接サポートがありません。各フレームは外部のイメージライブラリを使用して個別に抽出し、別個の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
$vbLabelText   $csharpLabel

IronOCRのアプローチ:

using IronOcr;

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

var ocr = new IronTesseract();

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

var result = ocr.Read(input);

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

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

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

Dim ocr As New IronTesseract()

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

    Dim result = ocr.Read(input)

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

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

フレーム抽出ループ、System.Drawing依存性、一時ファイル作成、およびクリーンアップロジックはすべて削除されます。 IronOCRは、単一の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 .Words 構造化されたテキスト領域
region.Text word.Text / line.Text 地域のテキストコンテンツ
region.Score(浮動小数点0-1) word.Confidence(整数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の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)
$vbLabelText   $csharpLabel

ドキュメントレベルの自信度は、迅速な品質ゲーティングのためにresult.Confidenceとして利用可能です。 信頼度スコアガイドでは、単語単位および文書単位の閾値について説明しています。

問題2:読書順序に関する前提

PaddleOCR: result.Regionsは検出順に並べられており、読み取り順ではありません。 読み取り順のトップからボトム、左から右出力を期待するresult.Textを消費するコードは、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)
$vbLabelText   $csharpLabel

問題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
$vbLabelText   $csharpLabel

ストリーム入力ガイドでは、HTTPレスポンス、データベースBLOB、およびメモリストリームからのストリーム読み込みについて説明します。

問題4:非同期初期化パターンの削除

PaddleOCR:モデルのダウンロードにはネットワークI/Oが伴うため、エンジンの初期化は非同期で行われます。 これにより、呼び出しチェーン全体で非同期処理が強制されるため、コンストラクタや非同期ではないイベントハンドラなどの同期的なコンテキストでは問題が発生する可能性があります。

解決策: IronOCRの初期化は同期的に行われます。 new IronTesseract()はI/Oを実行しません。 モデルのダウンロードが唯一の非同期操作だったメソッドから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
$vbLabelText   $csharpLabel

IronOCRはまた、非同期コンテキストで真に必要なときには非ブロック実行を通してocr.ReadAsync(input)によるネイティブ非同期サポートを提供します。

問題5:Dockerビルドステップのクリーンアップ

PaddleOCR: Dockerfileには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/フォルダをキャッシュすることです。 ラッパーのバージョンが更新されると、キャッシュキーが変更され、モデルをBaiduサーバーから再ダウンロードする必要があるため、処理に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')}}
YAML

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" .
SHELL

モデルのディレクトリを確保し、合計サイズを確認してください。どの言語モデルが使用中か(中国語、英語、日本語など)を特定して、追加するIronOcr.Languages.*パッケージを決定します。 GPU構成ファイルが存在するかどうかを確認してください。これらのファイルは、クリーンアップが必要な領域が最も大きいためです。

コードの移行

  1. .csprojファイルから削除します。
  2. .csprojファイルに追加します。
  3. これまでにPaddleOCRモデルとしてダウンロードされた英語以外の言語ごとにIronOcr.Languages.*パッケージを追加します。
  4. すべてのusing IronOcrで置き換えます。
  5. アプリケーション起動時にIronOcr.License.LicenseKey = "YOUR-LICENSE-KEY";を追加します。
  6. FullOcrModel models = await OnlineFullModels.*.DownloadAsync()を何もないものに置き換えます—行を完全に削除します。
  7. new IronTesseract()で置き換えます。
  8. new IronTesseract()で置き換えます。
  9. Mat mat = Cv2.ImRead(path)var input = new OcrInput();で置き換えます。 input.LoadImage(path);`.
  10. ocr.Read(input)で置き換えます。
  11. result.Pages[0].Wordsで置き換えます。
  12. word.Confidence >= threshold * 100で置き換えます。
  13. word.X / word.Yで置き換えます。
  14. 手動ソートロジックを削除する — IronOCRの出力は既に読み上げ順になっている
  15. models/ディレクトリおよびすべてのモデルファイルをリポジトリおよびデプロイメントスクリプトから削除します。

移行後

  • ビルド出力に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、および3つのモデルディレクトリ—は、すべてのデプロイメントターゲットに300-500MBを追加します。 移行後、 IronOCRのデプロイメントは約80MBになります。 Dockerイメージのサイズが約1.5GBから約400MBに縮小します。 コンテナの起動が高速化され、ストレージコストが削減されました。また、以前は500MBのアーティファクトを転送していたデプロイパイプラインが、現在は80MBの転送で済むようになりました。

コールドスタート時間が数秒から数ミリ秒に短縮。PaddleOCRは、最初の推論時にディスクから3つのニューラルネットワークモデルファイルを読み込むため、最初の呼び出しが返るまでに3~5秒の遅延が生じます。 サーバーレス関数、自動スケーリングのシナリオ、あるいはオンデマンドで新しいインスタンスが起動されるあらゆる状況において、そのコールドスタートのコストは繰り返し発生します。 IronOCRのエンジンはバンドルされており、1秒未満で初期化されます。 基本的なOCRの例では、初期化のパターンを示しています。

インフラストラクチャの構築作業なしに、対応言語が14言語から125言語に拡大。PaddleOCRは14言語に対応しています。 PaddleOCRの上限を超えてIronOCRがサポートする111言語のいずれかを追加する場合、言語ごとにNuGetパッケージを1つ追加するだけで済みます。モデルのダウンロード、ディレクトリ管理、バージョンの同期は一切不要です。 ドキュメントのボリュームが拡大し、新たな市場に進出するチームであっても、ポーランド語、ベトナム語、ギリシャ語、またはヘブライ語のOCRサポートを追加するために、ドキュメントの書き直しや新たなインフラストラクチャプロジェクトに取り組む必要はありません。 言語カタログの完全版には、利用可能な125以上のパックがすべて掲載されています。

検索可能なPDF出力には1行が必要です。PaddleOCRはテキスト領域を返します。 これらの領域を検索可能なPDFレイヤーに変換するには、別のPDFライブラリ、ピクセルからポイントへの座標変換、および恒久的なメンテナンスとなる不可視テキストの挿入コードが必要となります。 移行後、result.SaveAsSearchablePdf("output.pdf")がその全サブシステムを置き換えます。 スキャンされた文書のアーカイブワークフロー、FAXからPDFへの変換パイプライン、および文書管理システムとの連携など、これらすべてが直接的な恩恵を受けます。 検索可能なPDF操作ガイドおよびPDFデータ抽出に関するブログ記事では、出力オプションの全容を網羅しています。

どの段階でも外部ネットワーク接続はありません。 PaddleOCRはモデルのダウンロードのためにBaiduのbj.bcebos.comストレージに接続します。 政府ネットワーク、エアギャップシステム、金融サービスインフラなど、外部への接続が制限されている環境では、その接続にはファイアウォールの例外設定、あるいはCI/CDの複雑さを増す事前ダウンロードワークフローのいずれかが必要となります。 IronOCRはランタイムで外部接続を行いません。モデルはNuGetからdotnet restoreの一部として復元され、デプロイメント出力に存在します。 AWS 導入ガイドおよび Azure 導入ガイドでは、ネットワーク制限のある環境におけるクラウド固有の設定について解説しています。

OCRスタック全体に対する1つの商業サポート連絡先。 PaddleOCRの問題はSdcb.PaddleOCRラッパー(コミュニティGitHub)、PaddlePaddleフレームワーク(Baidu)、OpenCvSharp(コミュニティ)、およびCUDA/cuDNN(NVIDIA)にわたります。 各レイヤーには異なるサポートチャネルが用意されていますが、応答時間は保証されません。IronOCRはIron Softwareの単一製品であり、商用メールサポートおよび優先対応レベルが提供されています。 IronOCRドキュメントハブでは、すべてのAPIドキュメント、ハウツーガイド、トラブルシューティングリソースを一か所にまとめています。

ご注意PDFium、PaddleOCR、PDFSharp、Tesseract、およびiTextは、それぞれの所有者の登録商標です。 このサイトは、Baidu、Chromium Project、Google、PaddlePaddle、empira Software GmbH、またはiText Groupと提携しておらず、承認または支援を受けていません。すべての製品名、ロゴ、ブランドはそれぞれの所有者の所有物です。 比較は情報提供のみを目的としており、執筆時点で公開されている情報を反映しています。

よくある質問

なぜPaddleOCRからIronOCRに移行する必要があるのですか?

一般的な推進要因には、COM相互接続の複雑さの解消、ファイルベースのライセンス管理の置き換え、ページ単位の課金の回避、Docker/コンテナデプロイの有効化、標準的な.NETツールと統合するNuGetネイティブワークフローの採用などがあります。

PaddleOCRからIronOCRに移行する際の主なコード変更は何ですか?

PaddleOCRの初期化シーケンスをIronTesseractのインスタンス化に置き換え、COMのライフサイクル管理(明示的なCreate/Load/Closeパターン)を削除し、結果のプロパティ名を更新します。その結果、定型的な行が大幅に減りました。

IronOCRをインストールして移行を開始するにはどうすればいいですか?

パッケージマネージャーコンソールで'Install-Package IronOcr'を実行するか、CLIで'dotnet add package IronOcr'を実行してください。言語パックは別のパッケージです:例えばフランス語の場合は'dotnet add package IronOcr.Languages.French'となります。

IronOCRは標準的なビジネス文書のPaddleOCRのOCR精度に匹敵しますか?

IronOCRは、請求書、契約書、領収書、入力フォームなどの標準的なビジネスコンテンツで高い精度を達成しています。画像前処理フィルター(傾き補正、ノイズ除去、コントラスト強調)により、劣化した入力の認識をさらに向上させます。

IronOCRはPaddleOCRが別途インストールする言語データをどのように扱うのですか?

IronOCRの言語データはNuGetパッケージとして配布されます。'dotnet add package 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もスキャンしたPDFも読み取ります。IronTesseractをインスタンス化し、ocr.Read(input)を呼び出し、入力はPDFパスまたはOcrPdfInputであり、OcrResultページを反復します。別のPDFレンダリングパイプラインは必要ありません。

IronOCRはどのように大量処理のスレッディングを処理するのですか?

IronTesseractはスレッド毎にインスタンス化しても安全です。Parallel.ForEachまたはタスクプールでスレッドごとにインスタンスを1つスピンアップし、OCRを同時に実行し、完了したら各インスタンスを破棄します。グローバルステートやロックは必要ありません。

IronOCRはテキスト抽出後、どのような出力形式をサポートしていますか?

IronOCRはテキスト、単語座標、信頼度スコア、ページ構造を含む構造化された結果を返します。エクスポートオプションには、プレーンテキスト、検索可能なPDF、下流処理用の構造化結果オブジェクトが含まれます。

IronOCRの価格はPaddleOCRよりもワークロードのスケーリングを予測しやすいですか?

IronOCRは、定額制の永久ライセンスを採用しており、ページ単位やボリューム単位の料金はかかりません。10,000ページでも1,000万ページでも、ライセンスコストは一定です。ボリュームライセンスとチームライセンスのオプションはIronOCRの価格ページをご覧ください。

PaddleOCRからIronOCRに移行した後、既存のテストはどうなりますか?

抽出されたテキストコンテンツをアサートするテストは、移行後もパスし続ける必要があります。APIコールパターンやCOMオブジェクトのライフサイクルを検証するテストは、IronOCRのシンプルな初期化と結果モデルを反映するように更新する必要があります。

Kannaopat Udonpant
ソフトウェアエンジニア
ソフトウェアエンジニアになる前に、Kannapatは北海道大学で環境資源の博士号を修了しました。博士号を追求する間に、彼はバイオプロダクションエンジニアリング学科の一部である車両ロボティクスラボラトリーのメンバーになりました。2022年には、C#のスキルを活用してIron Softwareのエンジニアリングチームに参加し、IronPDFに注力しています。Kannapatは、IronPDFの多くのコードを執筆している開発者から直接学んでいるため、この仕事を大切にしています。同僚から学びながら、Iron Softwareでの働く社会的側面も楽しんでいます。コードやドキュメントを書いていない時は、KannapatはPS5でゲームをしたり、『The Last of Us』を再視聴したりしていることが多いです。

アイアンサポートチーム

私たちは週5日、24時間オンラインで対応しています。
チャット
メール
電話してね