# 要件定義書：Pure Rust OnnxOCR

作成者: Shion Watanabe  
日付: 2025-11-09  
リポジトリ: http://github.com/siska-tech/pure-onnx-ocr

## 🎯 目的

*   **プログラム開発の背景と目的 (Why)**
    `jingsongliujing/OnnxOCR` [1, 2] は、BaiduのPaddleOCRをベースにした高速なOCRソリューションですが、その実行はPythonとC++で記述されたONNX Runtimeライブラリ [3] に依存しています。本プロジェクトの目的は、このC/C++依存を完全に排除した「Pure Rust」環境 [3, 6, 33] でOCRパイプラインを再実装することです。これにより、Rustの持つメモリ安全性、容易なクロスコンパイル、高速な起動速度 [34] を備え、組み込みやWASMなどC/C++のFFI（Foreign Function Interface）が障壁となる環境 [5] へも展開可能な、移植性の高いOCRエンジンを構築します。

*   **プログラムが提供すべき機能 (What)**
    `jingsongliujing/OnnxOCR`が推奨する高性能モデルセット`PP-OCRv5_Server-ONNX` [1, 4] を対象とします。具体的には、テキスト検出（Detection）[35] とテキスト認識（Recognition）[36] の2段階のONNXモデル推論パイプライン（前処理 [37]、推論、後処理 [20]）全体を、Pure Rustで実装します。

*   **満たすべき品質、性能、制約（非機能要件）**
    最大の制約は「Pure Rust」であることです。これは、C/C++で記述された共有ライブラリへのFFIを**一切禁止**することを意味します [3]。この制約に基づき、推論エンジンには`onnxruntime-rs` [5] のようなC++ラッパーの使用を禁止し、`tract` [3, 6, 7] のようなRustのみで記述されたクレート [38] を使用します。

---

### 1. 開発背景と目的

*   **このプログラムが解決しようとしている課題**
    既存の`OnnxOCR` [1] は、MicrosoftのC++製ONNX Runtime [3] に依存しています。これにより、Rustアプリケーションに組み込む際にFFIの境界が発生し、ビルドの複雑化、クロスコンパイルの困難性、WASM対応の制約 [3]、およびCライブラリ固有の潜在的なセキュリティ問題（例：メモリ安全性）といった「C依存」の課題を抱えています [5]。
*   **想定される利用者（ターゲットユーザー）**
    *   Rustエコシステム内で完結したOCRソリューションを必要とする開発者。
    *   C/C++ライブラリの複雑な依存関係を避けたい、組み込みシステム、サーバーレス環境、またはWASM [3] アプリケーションの開発者。
*   **このプログラムが提供する中核的な価値**
    C++ランタイムへの依存を完全に排除し [3]、`cargo build`のみでビルド可能な、ポータブルでメモリ安全、かつ高速な起動 [34] が可能なPure RustのOCR推論ライブラリを提供すること。

### 2. 機能要件

*   **提供する機能の一覧**
    1.  **テキスト検出 (Detection):** 検出モデル（`det.onnx`: DBNet [8, 9]）を実行し、入力画像からテキスト領域のバウンディングボックス（多角形）を特定する機能。
    2.  **テキスト認識 (Recognition):** 検出された各テキスト領域の画像をクロップし、認識モデル（`rec.onnx`: SVTR_HGNet [10, 11]）を実行し、テキスト文字列を抽出する機能。
    3.  **統合パイプライン:** 上記の検出と認識を単一の関数（例: `OcrEngine::run()`）で実行し、画像パスまたは画像バッファから最終的なOCR結果（テキストと座標のリスト）[39] を返すAPI。

*   **各機能の入力と期待される出力の概要**
    *   **入力:** 画像ファイルパス（`&str`）、または `image::DynamicImage` 形式の画像バッファ。
    *   **出力:** 検出された各テキスト領域のOCR結果（`OcrResult`）のベクター（`Vec<OcrResult>`）。
        *   `OcrResult` 構造体 (例):
            *   `bounding_box`: `geo_types::Polygon` [12] 形式のテキスト領域座標 [40]。
            *   `text`: 認識された `String` 型のテキスト [39]。

*   **機能詳細**
    *   **検出前処理 (4.1節):**
        *   入力画像を`limit_side_len`（例: 960px）[41, 42] に基づき、アスペクト比を維持したままリサイズ [43] する（`image::resize` [13]）。
        *   ピクセル値を正規化 [37] し、HWC (Height, Width, Channel) 形式から NCHW (Batch, Channel, Height, Width) 形式に軸を転置 [23, 44] する（`ndarray::permuted_axes` [14]）。
    *   **検出後処理 (4.2節):**
        *   `tract`から出力された確率マップ（`ndarray::Array`）に対し、`imageproc::contours::find_contours` [15, 16] を用いて輪郭を抽出する（`cv2.findContours` [17] の代替）。
        *   `i_overlay::buffering` [18, 19] を用い、抽出されたポリゴンを拡大（オフセット）する（`pyclipper` [20, 21] の代替）。
        *   結果を`geo_types::Polygon` [12, 22] として整形する（`shapely` [21] の代替）。
    *   **認識前処理 (5.1節):**
        *   検出されたポリゴンに基づき、元画像から画像領域をクロップする。
        *   各クロップ画像を、モデルの要求する固定サイズ（例: `` [10, 11, 23]）へ、アスペクト比を**無視**してリサイズ [1] する（`image::resize_exact` [24]）。
        *   正規化し、`ndarray::stack` [25] を用いてバッチ化する。
    *   **認識後処理 (5.2節):**
        *   `ppocrv5_dict.txt` [10, 26] を`HashMap<usize, char>`または`Vec<String>`にロードする。
        *   `tract`から出力されたロジット（`ndarray::Array`）に対し、`ndarray::argmax_axis` [27] を適用する。
        *   Pure RustでCTC Greedyデコード [28, 29] のロジック（連続する重複インデックス [45] とブランクID [46] の削除）を実装する。
        *   デコードされたインデックスのシーケンスを辞書でマッピングし、最終的な `String` を生成する。

### 3. 非機能要件

*   **性能**
    *   リファレンス実装の`PP-OCRv5_Server-ONNX` [1, 4] モデルセット（DBNet [8] + SVTR_HGNet [10]）を、Pure Rustの推論エンジン`tract` [3, 6, 7] を使用してCPU [26] で実行可能であること。
*   **互換性 (依存ライブラリの制約)**
    *   **最重要:** C/C++ライブラリへのFFI [33] を**厳密に禁止**する。
    *   **推論:** `onnxruntime-rs` [5] および `ort` [5, 47]（C++ラッパー）の使用を**禁止**し、`tract-onnx` [3, 6, 7] に限定する。
    *   **配列操作:** `numpy` [27] 依存を排除し、`ndarray` [25, 48, 49, 50, 51] クレートを使用する。
    *   **画像I/O・処理:** `opencv-python` [52] 依存を排除し、`image` [53] および `imageproc` [54, 55] クレートを使用する。
    *   **ジオメトリ処理:** `pyclipper` [56, 57] (C++ラッパー [35]) および `shapely` [58, 59] (GEOS C API依存 [59]) の使用を**禁止**し、Pure Rust実装 [19, 60] の `i_overlay` [1, 56, 18] および `geo-types` [22, 61] (Pure Rust [62, 63]) を使用する。
*   **信頼性 (技術的リスク)**
    *   **致命的リスク:** 認識モデル`SVTR_HGNet` [10]（Transformerベース [64]）は、`LayerNormalization` [30, 31] や `Scan` [32] といった複雑なONNXオペレータを要求する可能性が高い。
    *   `tract`のドキュメント [32] では、`LayerNormalization`のサポートが明記されておらず、`Scan`を含むシーケンス処理オペレータを「注目すべき欠落部分」と明記している。
    *   **必須アクション (PoC):** 本格的な開発着手前に、`rec.onnx`モデルが`tract_onnx::onnx().model_for_path()` [65] でロード・実行できるかを検証する最小限の技術検証（PoC）を**最優先**で実施する必要がある（3.3節参照）。

### 4. 制約条件

*   **使用するプログラミング言語:** Rust (Pure Rust [3, 6, 33]、C/C++コードのFFI呼び出しなし)
*   **使用する主要フレームワーク（クレート）:**
    *   **推論:** `tract-onnx` [3, 6, 7]
    *   **N次元配列:** `ndarray` [25, 48, 49]
    *   **画像I/O・リサイズ:** `image` [53]
    *   **輪郭抽出:** `imageproc` [54, 55]
    *   **ポリゴン処理:** `i_overlay` [1, 18], `geo-types` [22, 61]
    *   **(オプション) 並列処理:** `rayon` [54, 48]
*   **ライセンス**
    *   リファレンスプロジェクト `jingsongliujing/OnnxOCR` [1] および `PaddleOCR` [20] は `Apache-2.0` ライセンスである。
    *   主要依存クレート `tract` [66] は `MIT OR Apache-2.0` である。
    *   本プロジェクトの成果物も、上記に準拠する `Apache-2.0` または `MIT` ライセンスとすることを推奨する。