Skip to main content

Video-first Rust OCR pipeline — SSIM frame sampling + temporal dedup, emitting timestamped text/SRT for RAG ingestion.

Project description

rust_ocr_transformer

Rust 기반 통합 비전 추론·처리 프레임워크

이미지·영상을 디코드 → 전처리 → 신경망 모델 추론 → 후처리 → 구조화 출력으로 흘려보낸다. 작업별 모델(텍스트 검출·인식, 분류, 객체 검출, 레이아웃, 세그멘테이션)을 trait 뒤에 꽂아 교체하는 오케스트레이션 틀이며, 기본 추론은 순수 Rust(tract) / zero FFI / CPU 로 동작한다.

이 문서는 라이브러리의 개발자 매뉴얼이다. 설계 원칙, 공개 API, 작업별 동작과 성숙도, CLI/Python 사용법, 모델 준비, 서비스 통합, 새 작업/백엔드 추가법, 빌드·테스트 절차를 담는다.

[주요 참고 논문]

  1. DBNet: Real-time Scene Text Detection with Differentiable Binarization (텍스트 검출 + DB 후처리) - https://arxiv.org/abs/1911.08947
  2. CRNN: An End-to-End Trainable Neural Network for Image-based Sequence Recognition (CNN+RNN+CTC 시퀀스 인식) - https://arxiv.org/abs/1507.05717
  3. SVTR: Scene Text Recognition with a Single Visual Model (PP-OCRv5 인식 백본) - https://arxiv.org/abs/2205.00159
  4. PP-OCR: A Practical Ultra Lightweight OCR System (임베드하는 경량 OCR 모델군) - https://arxiv.org/abs/2009.09941
  5. Image Quality Assessment: From Error Visibility to Structural Similarity (SSIM — 영상 프레임 샘플링 게이트) - https://ece.uwaterloo.ca/~z70wang/research/ssim/

목차

  1. 핵심 특징
  2. 빠른 시작
  3. 설치와 Cargo Feature
  4. 아키텍처
  5. 공통 타입 레퍼런스
  6. 공개 API 레퍼런스
  7. 작업별 동작과 성숙도
  8. 영상 시간축 처리
  9. CLI 도구 (roct)
  10. Python 바인딩 (PyO3)
  11. 모델 준비 (ONNX 모델·사전)
  12. 서비스 파이프라인에 붙이기
  13. 새 작업·백엔드 추가하기
  14. 빌드 · Feature 조합 · 테스트
  15. 디렉토리 구조
  16. 라이선스

1. 핵심 특징

비전 파이프라인에서 과소평가되는 영역이 전·후처리와 오케스트레이션이다. 모델이 아무리 좋아도 입력 정규화·검출 후처리·디코딩 규약이 어긋나면 결과가 무너진다. 이 라이브러리는 단일 만능 모델이 아니라, 그 위아래의 시스템 엔지니어링을 책임지는 을 지향한다.

원칙 의미
모델은 담지 않고 꽂는다 "지능"은 trait 뒤의 모델 몫이다. 프레임워크는 디코드·전처리·후처리·조립을 맡는다. 같은 입력이면 같은 모델로 같은 결과(결정적).
작업 단위 추상화 텍스트 검출/인식, 분류, 객체 검출, 레이아웃, 세그멘테이션을 각각의 trait 으로 분리. 새 모델은 trait 하나만 구현하면 끼워진다.
순수 Rust 기본 / zero FFI 기본 추론 엔진은 tract(순수 Rust ONNX 런타임). C++ ONNX Runtime·CUDA·subprocess 불필요. CPU 단일 바이너리·클린 abi3 휠. 속도/GPU 가 필요하면 ort 를 opt-in 으로 더한다.
영상 1급 시민 정지 이미지는 프레임 1개인 영상의 퇴화 사례. 같은 파이프라인이 둘 다 받고, 영상에는 SSIM 샘플링·시간축 병합이 더해진다.

"이해"는 코어 밖이다

이 프레임워크가 만드는 것은 "무엇이 어디에 있다"(텍스트·박스·클래스·좌표)까지의 구조화된 비전 결과다. "이 영수증을 JSON 으로 해석", "사고 사진의 손상 부위 판독" 같은 이해·추론은 대형 VLM/LLM 의 몫이며, 그건 코어 밖(서버 등)에 위임하고 이 프레임워크는 그 입력을 만든다. 순수 문자 인식은 소형 특화 모델이 프론티어 LLM 보다 정확하고 결정적·저비용이므로, 코어는 LLM-free 로 둔다.


2. 빠른 시작

Rust 라이브러리 (OCR)

use rust_ocr_transformer::{Frame, OcrEngine, TractTextDetector, TractTextRecognizer};

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 이미지 1장 로드 (영상은 프레임 스트림으로 같은 엔진에 흘린다)
    let frame = Frame::from_path("page.png")?;

    // 검출 모델(입력 736x1280) + 인식 모델(입력 48x320) + 문자 사전
    let detector = TractTextDetector::new("models/det.onnx", (736, 1280))?;
    let recognizer = TractTextRecognizer::new("models/rec.onnx", "models/dict.txt", (48, 320))?;
    let engine = OcrEngine::new(detector, recognizer);

    // 검출 → 크롭 → 인식
    for r in engine.read(&frame)? {
        println!("[{:.2}] ({},{}) {}", r.confidence, r.bbox.x, r.bbox.y, r.text);
    }
    Ok(())
}

모델·사전 파일을 받는 방법은 11장에 있다.

CLI

cargo build --release --features cli
./target/release/roct image page.png \
  --det-model models/det.onnx --rec-model models/rec.onnx --dict models/dict.txt

Python

import json
import rust_ocr_transformer as roct

# 이미지 OCR — 모델·사전 경로를 주면 인식 결과 JSON 반환
out = roct.recognize_image("page.png", "models/det.onnx", "models/rec.onnx", "models/dict.txt")
for r in json.loads(out):
    print(r["confidence"], r["text"])

3. 설치와 Cargo Feature

Cargo.toml:

[dependencies]
rust_ocr_transformer = { git = "https://github.com/arabangoo/rust_ocr_transformer", tag = "v0.1.0" }

Feature 목록

Feature 활성화 대상 비고
tract 순수 Rust ONNX 추론 백엔드 기본 활성. C++ FFI 없음. tract-onnx
video 영상 디코드(Phase 2) ffmpeg-next — 현재 자리만 잡힘, 미구현
cli roct 실행 바이너리 clap — 라이브러리 소비자에겐 새지 않는 opt-in
python PyO3 cdylib 바인딩 pyo3(abi3)
# default = ["tract"]   ← 순수 Rust 인식 백엔드 포함, zero FFI

# 코어 IP(타입·trait·샘플링·병합·전후처리)만, 백엔드는 직접 주입하고 싶을 때
rust_ocr_transformer = { version = "0.1", default-features = false }

기본(tract) 빌드는 외부 .so/.dll 이나 subprocess 를 요구하지 않는다. 속도·GPU 가 병목이면 같은 trait 뒤에 들어오는 ort(ONNX Runtime, C++ FFI) 백엔드를 opt-in feature 로 추가할 계획이다 (현재 미구현 — 데드 feature 를 미리 만들지 않는다).


4. 아키텍처

디코드 → 전처리 → 작업 모델(trait) → 후처리 → 구조화 출력
 Frame   preprocess   tasks::*        postprocess   FrameAnalysis
                       (모델 plug point)              + SRT/JSON/평문

핵심은 작업 trait 레이어다. 각 작업(검출·인식·분류·객체검출·레이아웃·세그멘테이션)은 입력으로 공통 Frame 을 받고 작업별 결과 타입을 낸다. 모델은 그 trait 의 구현체로 들어오므로, 코어 파이프라인은 어떤 모델을 쓰는지 모른 채 작업 단위로만 조립된다.

  • 디코드 — 이미지/영상을 Frame 으로. 이미지 = 프레임 1개 영상.
  • 전처리preprocess: letterbox 리사이즈·정규화·NCHW 텐서화. 작업 무관 재사용.
  • 추론tasks trait 뒤의 모델(backends::tract).
  • 후처리postprocess: 비최대 억제(NMS)·softmax·연결성 시계열 분류(CTC) 디코딩·DB 박스.
  • 출력FrameAnalysis 로 여러 작업 결과를 모으고, 영상은 SRT/JSON 으로.

5. 공통 타입 레퍼런스

types 모듈. 결과 타입은 serde::{Serialize, Deserialize} 를 구현해 그대로 JSON 으로 떨어뜨릴 수 있다.

/// 파이프라인 1단위. 이미지는 프레임이 1개인 영상의 퇴화 사례다.
pub struct Frame {
    pub image:     image::DynamicImage,
    pub index:     u64,        // 영상 내 프레임 순번 (이미지면 0)
    pub timestamp: Timestamp,  // 표시 시각(ms) (이미지면 0)
}
// Frame::from_path(p) / Frame::from_image(img) / Frame::new(img, index, ts)

/// 픽셀 좌표계 사각 영역(좌상단 원점).
pub struct BBox { pub x: u32, pub y: u32, pub width: u32, pub height: u32 }

작업별 결과 타입

pub struct TextBox     { pub bbox: BBox, pub confidence: f32 }                  // 검출
pub struct Crop        { pub image: image::DynamicImage, pub bbox: BBox }       // 검출→인식 사이
pub struct Recognized  { pub text: String, pub confidence: f32, pub bbox: BBox }// 인식
pub struct Detection   { pub bbox: BBox, pub label: String, pub score: f32 }    // 객체 검출
pub struct Classification { pub label: String, pub score: f32 }                 // 분류
pub struct LayoutRegion { pub bbox: BBox, pub kind: String, pub score: f32 }    // 레이아웃
pub struct Mask        { pub width: u32, pub height: u32, pub classes: Vec<u8> }// 세그멘테이션

/// 한 프레임의 종합 분석 결과 — 여러 작업 출력을 모으는 구조화 출력 컨테이너.
pub struct FrameAnalysis {
    pub recognized:      Vec<Recognized>,
    pub detections:      Vec<Detection>,
    pub classifications: Vec<Classification>,
    pub layout:          Vec<LayoutRegion>,
}

영상 시간축 타입

pub struct Timestamp(pub u64);   // 밀리초. to_srt() → "HH:MM:SS,mmm"
pub struct Segment { pub start: Timestamp, pub end: Timestamp, pub text: String }

6. 공개 API 레퍼런스

6.1 작업 trait

tasks 모듈. 모델을 꽂는 자리다. 모두 Send + Sync(멀티스레드 공유 가능).

pub trait TextDetector:   Send + Sync { fn detect(&self, frame: &Frame) -> Result<Vec<TextBox>>; }
pub trait TextRecognizer: Send + Sync { fn recognize(&self, crops: &[Crop]) -> Result<Vec<Recognized>>; }
pub trait ObjectDetector: Send + Sync { fn detect_objects(&self, frame: &Frame) -> Result<Vec<Detection>>; }
pub trait Classifier:     Send + Sync { fn classify(&self, frame: &Frame) -> Result<Vec<Classification>>; }
pub trait LayoutAnalyzer: Send + Sync { fn analyze_layout(&self, frame: &Frame) -> Result<Vec<LayoutRegion>>; }
pub trait Segmenter:      Send + Sync { fn segment(&self, frame: &Frame) -> Result<Mask>; }

6.2 OcrEngine — OCR 작업 합성

검출기 + 인식기를 합성한 OCR 파이프라인. 다른 작업은 각자의 trait 으로 직접 조립한다.

OcrEngine::new(detector: D, recognizer: R) -> OcrEngine<D, R>   // D: TextDetector, R: TextRecognizer
fn read(&self, frame: &Frame) -> Result<Vec<Recognized>>        // 검출 → 크롭 → 인식
fn detector(&self) -> &D
fn recognizer(&self) -> &R

// 헬퍼: 검출 박스대로 프레임을 잘라 Crop 목록 생성
crop_regions(frame: &Frame, boxes: &[TextBox]) -> Vec<Crop>

6.3 전처리 (preprocess)

작업 무관 재사용 함수. 이미지를 모델 입력 텐서(NCHW f32)로.

pub const IMAGENET_MEAN: [f32; 3];  // [0.485, 0.456, 0.406]
pub const IMAGENET_STD:  [f32; 3];  // [0.229, 0.224, 0.225]

// letterbox(비율 유지+패딩) + 채널별 정규화 → (data[3*h*w], scale). scale 은 박스 역매핑용.
fn letterbox_chw(img: &DynamicImage, in_h: usize, in_w: usize, mean: [f32;3], std: [f32;3]) -> (Vec<f32>, f32)

// 높이 고정·비율 유지, 폭 우측 0-pad, [-1,1] 정규화 → NCHW (텍스트 인식용)
fn fixed_height_chw(img: &DynamicImage, in_h: usize, in_w: usize) -> Vec<f32>

6.4 후처리 (postprocess)

모델 무관 순수 로직은 단위 테스트로 검증돼 있다.

fn softmax(logits: &[f32]) -> Vec<f32>            // 수치 안정 softmax
fn argmax(v: &[f32]) -> (usize, f32)              // top-1 (인덱스, 값)
fn iou(a: &BBox, b: &BBox) -> f32                 // 교집합/합집합
fn nms(boxes: &[(BBox, f32)], iou_threshold: f32) -> Vec<usize>   // 비최대 억제 → 유지 인덱스
fn ctc_greedy_decode(logits: &[f32], t: usize, c: usize, dict: &[String]) -> (String, f32)  // CTC
fn connected_boxes(prob: &[f32], w: usize, h: usize, threshold: f32, min_area: usize)
    -> Vec<(usize, usize, usize, usize, f32)>     // DB 검출 후처리(연결요소 박스)

6.5 에러 타입

pub enum VisionError {
    Io(std::io::Error),
    Decode(String),       // 이미지/영상 디코드 실패
    Backend(String),      // 모델 로드/추론 에러 (구체 백엔드 에러를 문자열로 흡수)
    NotWired(&'static str),// 아직 연결 안 된 기능 호출
    Unsupported(String),
}
pub type OcrError = VisionError;          // 구 명칭 호환 별칭
pub type Result<T> = std::result::Result<T, VisionError>;

에러 타입은 optional 의존성(tract 등)에 의존하지 않는다. 백엔드 구체 에러는 문자열로 흡수하므로 어떤 feature 조합에서도 항상 컴파일된다.


7. 작업별 동작과 성숙도

작업 trait / 백엔드 상태
텍스트 검출 + 인식(OCR) TextDetector/TextRecognizer, TractTextDetector/TractTextRecognizer, OcrEngine 동작 검증됨 — PP-OCRv5 한국어 모델로 CPU end-to-end 실행 확인
이미지 분류 Classifier, TractClassifier 컴파일·구조 완성, 실모델 정확도 미검증
객체 검출 ObjectDetector, TractObjectDetector 컴파일됨. 출력 레이아웃을 [N,6]=(x1,y1,x2,y2,score,cls)로 가정 — 모델마다 다르니 검증·교체 필요
레이아웃 분석 LayoutAnalyzer trait 정의만(레이아웃 라벨을 가진 객체 검출의 특수형)
세그멘테이션 Segmenter, Mask trait 정의만(구체 백엔드 미구현)
영상 시간축 SamplingGate, TemporalMerger 동작·테스트 완료 (8장). 단 영상 디코드는 미구현(Phase 2)

검증·한계 메모:

  • OCR 정확도는 사전(dict) 정합에 민감하다. 인식 모델의 클래스 인덱스와 문자 사전이 1:1로 맞아야 한다. 모델에 딸린 전용 사전을 써야 하며, 다른 사전을 물리면 글자가 통째로 어긋난다(중국어 사전을 한국어 모델에 물리면 한글이 한자로 나오는 식). 11장 참고.
  • 검출 박스는 축 정렬이다(회전·unclip 미적용). 수평 자막·화면텍스트엔 충분하나 기울어진 텍스트는 후속 고도화 대상이다.
  • 고정 입력 형상. 검출/인식 입력을 빌드 시 고정(예: 검출 736x1280, 인식 48x320)해 가변 형상 재최적화를 피한다. 매우 넓은 줄은 인식 폭(예: 320px)으로 잘릴 수 있다.
  • 동적 입력 ONNX 처리. PaddleOCR ONNX 는 입력이 동적 차원이라, 백엔드가 로드 시 원시 proto 의 입력 차원을 정적으로 고정한 뒤 파싱한다. tract 는 검출(DB)·인식(CRNN/SVTR) 모두 실행 가능함을 확인했다.

8. 영상 시간축 처리

영상에서 텍스트를 뽑을 때의 차별점 — 모든 프레임을 인식하지 않고, 변화가 있는 프레임만 인식한 뒤 인접 프레임의 중복을 시간 구간으로 병합한다.

8.1 SSIM 샘플링 게이트

직전 키프레임과 구조적 유사도(SSIM)가 충분히 높으면 프레임을 버린다. 30fps 영상에서 자막은 초당 수 프레임만 바뀌므로, 통과율을 한 자릿수 %까지 낮춰 인식 호출 자체를 줄인다.

let mut gate = SamplingGate::new(0.98);        // 임계값(높을수록 덜 버림). with_scale 로 비교 크기 조정
if gate.admit(&frame) {                        // true=통과(새 프레임), false=스킵(직전과 동일)
    // 이 프레임만 OCR
}
ssim(&gray_a, &gray_b) -> f64                  // 두 그레이스케일 이미지의 전역 SSIM

8.2 temporal 병합

게이트를 통과한 인접 프레임의 인식 결과는 거의 같은 텍스트일 수 있다. 정규화 Levenshtein 유사도로 "같은 자막의 연속"을 하나의 (start, end, text) 구간으로 합친다.

let mut merger = TemporalMerger::new(0.8);     // 유사도 임계값
if let Some(seg) = merger.push(timestamp, text) { /* 자막이 바뀜 → 직전 구간 확정 */ }
let last = merger.finish();                     // 스트림 끝 → 마지막 구간 회수

8.3 출력 직렬화 (emit)

emit::to_srt(&segments)  -> String          // SRT 자막
emit::to_json(&segments) -> Result<String>  // JSON 배열(타임스탬프 ms)
emit::to_plain(&segments)-> String          // 텍스트만 줄바꿈 연결

9. CLI 도구 (roct)

--features cli 로 빌드된다.

cargo build --release --features cli
서브커맨드 인자 동작
image <path> --det-model --rec-model --dict 이미지 OCR(검출+인식). 결과를 [score] (x,y,w,h) text 로 출력
classify <path> --model --labels 이미지 분류(top-k)
ssim <a> <b> 두 이미지의 구조적 유사도 출력(샘플링 게이트 지표)
srt <segments.json> 시간 구간 JSON → SRT 자막(stdout)
video <path> 영상 OCR — Phase 2, 현재 NotWired 에러 반환
# 이미지 OCR
roct image page.png --det-model models/det.onnx --rec-model models/rec.onnx --dict models/dict.txt

# 이미지 분류 (모델 + 라벨 목록)
roct classify cat.jpg --model models/cls.onnx --labels models/imagenet.txt

# 구간 JSON → SRT
roct srt segments.json > out.srt

10. Python 바인딩 (PyO3)

abi3(stable ABI) 로 빌드되어 Python 3.9+ 단일 휠로 호환된다(C++ 런타임 의존 없는 순수 Rust 휠).

Python 에서 이미지 OCR(recognize_image)과 코어 유틸리티를 호출한다. 모델·사전 파일은 호출자가 제공한다(11장). 영상 처리(read_video)는 영상 디코드(Phase 2)와 함께 추가된다.

설치

# PyPI 게시 후 — Rust 툴체인 불필요
pip install rust_ocr_transformer

# 소스에서(최신 main / 게시 전) — 설치 머신에 Rust 툴체인 필요
pip install "git+https://github.com/arabangoo/rust_ocr_transformer"

API

import json
import rust_ocr_transformer as roct

roct.__version__                              # "0.1.0"

# 이미지 OCR — 검출+인식 결과를 JSON 문자열로
out = roct.recognize_image("page.png", "models/det.onnx", "models/rec.onnx", "models/dict.txt")
for r in json.loads(out):
    print(r["confidence"], r["text"], r["bbox"])   # {"x":..,"y":..,"width":..,"height":..}

# 코어 유틸리티
roct.image_ssim("a.png", "b.png")             # 두 이미지의 구조적 유사도(0.0-1.0)
roct.segments_to_srt(segments_json)           # 시간 구간 JSON 문자열 → SRT 자막 문자열

recognize_image 는 입력 형상 인자(det_height/det_width/rec_height/rec_width)를 선택적으로 받는다(기본 PP-OCRv5 권장값).

빌드 (개발자 · 게시자)

루트 pyproject.toml(maturin 백엔드)이 빌드 메타데이터를 제공한다. [tool.maturin] features = ["python"] 덕분에 --features python 을 생략해도 된다.

pip install maturin
maturin develop --release          # 현재 venv 에 설치
maturin build --release            # target/wheels/ 에 휠 빌드

11. 모델 준비 (ONNX 모델·사전)

이 프레임워크는 모델을 담지 않는다 — 추론에는 ONNX 모델 파일과(인식의 경우) 문자 사전이 필요하다. 모델 가중치는 레포에 커밋하지 않는다(.gitignore*.onnxmodels/ 를 제외).

PaddleOCR ONNX 모델 (검증에 사용한 출처)

사전 변환된 PP-OCR ONNX 모델과 사전을 직접 받을 수 있다(PaddlePaddle, Apache-2.0).

mkdir -p models
base="https://github.com/GreatV/oar-ocr/releases/download/v0.3.0"
# 검출(언어 무관)
curl -sL -o models/det.onnx       "$base/pp-ocrv5_mobile_det.onnx"
# 인식(언어별) — 예: 한국어 PP-OCRv5
curl -sL -o models/rec.onnx       "$base/korean_pp-ocrv5_mobile_rec.onnx"
# 문자 사전 — 반드시 인식 모델과 짝이 맞는 것
curl -sL -o models/dict.txt       "$base/ppocrv5_korean_dict.txt"

영어·라틴·일본어 등 다른 언어 인식 모델과 그에 맞는 사전도 같은 릴리스에 있다.

사전은 모델과 정확히 짝이 맞아야 한다. 인식 모델의 출력 클래스 수와 사전 길이·문자 순서가 1:1로 대응해야 정상 인식된다. 같은 언어라도 모델 버전(v3/v4/v5)에 따라 사전이 다르므로, 모델과 함께 배포된 전용 사전을 쓴다. 사전이 어긋나면 글자가 통째로 잘못 매핑된다.

입력 형상

백엔드 생성 시 입력 형상을 지정한다(PP-OCRv5 권장값): 검출 (736, 1280), 인식 (48, 320), 분류 (224, 224). 모델은 동적 입력이어도 백엔드가 이 형상으로 고정해 적재한다.


12. 서비스 파이프라인에 붙이기

이 라이브러리는 단독 앱이 아니라 비전 입력 단에 박아 넣는 코어 의존성이다. 추출된 구조화 결과(텍스트· 박스·구간)는 그 자체로 쓰거나, 검색 증강 생성(RAG) 인제스트의 비전 입구로 흘려보낸다.

12.1 Rust 서비스에 임베드

추론은 CPU 바운드이므로 async 서버(axum/actix)에서는 spawn_blocking 으로 감싼다. 모델은 한 번 로드해 재사용한다(엔진을 Arc 로 공유 — trait 이 Send + Sync).

use std::sync::Arc;
use rust_ocr_transformer::{Frame, OcrEngine, TractTextDetector, TractTextRecognizer};

// 기동 시 1회 로드 후 공유
let engine = Arc::new(OcrEngine::new(
    TractTextDetector::new("models/det.onnx", (736, 1280))?,
    TractTextRecognizer::new("models/rec.onnx", "models/dict.txt", (48, 320))?,
));

// 핸들러
let eng = engine.clone();
let results = tokio::task::spawn_blocking(move || {
    let frame = Frame::from_path("upload.png")?;
    eng.read(&frame)
}).await??;

12.2 영상 → 자막(SRT) 파이프라인

SSIM 게이트로 프레임을 솎고, 통과 프레임만 OCR 한 뒤 temporal 병합으로 자막 구간을 만든다.

use rust_ocr_transformer::{SamplingGate, TemporalMerger, emit};

let mut gate = SamplingGate::new(0.98);
let mut merger = TemporalMerger::new(0.85);
let mut segments = Vec::new();

for frame in frames {                       // 영상 디코드는 호출자 측(Phase 2 전까지)
    if !gate.admit(&frame) { continue; }    // 변화 없는 프레임 스킵
    let text = engine.read(&frame)?
        .iter().map(|r| r.text.as_str()).collect::<Vec<_>>().join(" ");
    if let Some(seg) = merger.push(frame.timestamp, &text) { segments.push(seg); }
}
if let Some(seg) = merger.finish() { segments.push(seg); }
std::fs::write("out.srt", emit::to_srt(&segments))?;

12.3 타 언어 / 배치 — CLI 래핑

Python·Rust 가 아닌 스택이나 배치 잡에서는 roct 바이너리를 subprocess 로 호출한다. 단일 정적 바이너리라 컨테이너에 roct 하나만 넣으면 된다(런타임 의존 없음).

roct image /data/page.png --det-model det.onnx --rec-model rec.onnx --dict dict.txt

13. 새 작업·백엔드 추가하기

코어를 건드리지 않고 새 모델·새 작업을 끼울 수 있다.

13.1 새 백엔드 — 기존 작업 trait 구현

예: 자체 분류 모델을 Classifier 로. 공용 TractModel 러너 + 재사용 전·후처리를 쓰면 짧다.

use rust_ocr_transformer::{Classifier, Classification, Frame, Result, TractModel};
use rust_ocr_transformer::{preprocess, postprocess};

struct MyClassifier { model: TractModel, labels: Vec<String> }

impl Classifier for MyClassifier {
    fn classify(&self, frame: &Frame) -> Result<Vec<Classification>> {
        let (h, w) = self.model.dims();
        let (data, _) = preprocess::letterbox_chw(&frame.image, h, w,
            preprocess::IMAGENET_MEAN, preprocess::IMAGENET_STD);
        let (logits, _) = self.model.run(data)?;
        let probs = postprocess::softmax(&logits);
        let (i, score) = postprocess::argmax(&probs);
        Ok(vec![Classification { label: self.labels[i].clone(), score }])
    }
}

13.2 새 작업 — 새 trait

기존 6개로 표현 안 되는 작업(예: 키포인트·깊이 추정)은 tasks 패턴대로 Send + Sync trait 을 새로 정의하고 Frame 을 입력으로 받게 만든다. 전·후처리는 preprocess/postprocess 의 재사용 함수를 쓴다.

13.3 tract 백엔드 (참고)

backends::tract 가 제공하는 것:

TractModel::load(path, in_h, in_w) -> Result<TractModel>   // 동적 입력도 정적 고정 후 적재
fn dims(&self) -> (usize, usize)
fn run(&self, data: Vec<f32>) -> Result<(Vec<f32>, Vec<usize>)>  // (출력 슬라이스, 형상)

TractTextDetector::new(model, (h, w))            // .with_threshold(f32)
TractTextRecognizer::new(model, dict, (h, w))
TractClassifier::new(model, labels, (h, w))      // .with_top_k(usize)
TractObjectDetector::new(model, labels, (h, w))  // .with_thresholds(score, iou)

14. 빌드 · Feature 조합 · 테스트

이 저장소를 clone 한 경우, 쓰려면 Rust 툴체인(stable, 1.74 이상 권장) 으로 한 번 빌드해야 한다.

쓰는 방식 빌드 명령 결과물
CLI 도구 cargo build --release --features cli target/release/roct 단일 바이너리
Python 모듈 pip install maturin && maturin develop --release 현재 venv 에 import rust_ocr_transformer
Rust 라이브러리 Cargo.tomlpath/git 의존성 다른 Rust 프로젝트에 링크
# 기본: 순수 Rust(tract) 백엔드 포함, zero FFI
cargo build --release

# 코어 IP 만 (백엔드 직접 주입)
cargo build --release --no-default-features

# CLI / Python
cargo build --release --features cli
maturin develop --release

# 테스트 / 린트
cargo test                  # 후처리 순수 로직(softmax·argmax·IoU·NMS·CTC) + 파이프라인 통합
cargo clippy --all-targets

테스트는 외부 모델 없이 동작하는 범위를 검증한다 — 합성 이미지로 SSIM 게이트·temporal 병합·SRT 출력·trait 합성 엔진 결선을, 합성 텐서로 NMS·softmax·CTC·IoU 후처리를 결정적으로 확인한다 (tests/pipeline.rs, src/postprocess.rs 단위 테스트).


15. 디렉토리 구조

rust_ocr_transformer/
  Cargo.toml
  README.md              # 이 문서
  LICENSE                # Apache-2.0
  src/
    lib.rs               # 크레이트 루트 · re-export
    types.rs             # 공통 타입(Frame/BBox/결과 타입/FrameAnalysis/Segment)
    tasks.rs             # 작업 trait(TextDetector/Recognizer/ObjectDetector/Classifier/...)
    engine.rs            # OcrEngine(검출+인식 합성) · crop_regions
    preprocess.rs        # letterbox · 정규화 · CHW 텐서화
    postprocess.rs       # NMS · softmax · argmax · IoU · CTC · DB 연결요소 박스 (+ 단위 테스트)
    sampler.rs           # SSIM 샘플링 게이트(영상)
    temporal.rs          # temporal 병합(영상)
    emit.rs              # SRT / JSON / 평문 직렬화
    error.rs             # VisionError / Result
    python.rs            # PyO3 바인딩 (feature = "python")
    bin/
      roct.rs            # CLI 바이너리 (feature = "cli")
    backends/
      mod.rs             # feature 게이트
      tract.rs           # 순수 Rust 추론 백엔드 (feature = "tract")
  tests/
    pipeline.rs          # 합성 픽스처 기반 통합 테스트

16. 라이선스

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rust_ocr_transformer-0.1.1.tar.gz (66.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

rust_ocr_transformer-0.1.1-cp39-abi3-win_amd64.whl (6.2 MB view details)

Uploaded CPython 3.9+Windows x86-64

rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.1 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ x86-64

rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (6.4 MB view details)

Uploaded CPython 3.9+manylinux: glibc 2.17+ ARM64

rust_ocr_transformer-0.1.1-cp39-abi3-macosx_11_0_arm64.whl (5.9 MB view details)

Uploaded CPython 3.9+macOS 11.0+ ARM64

rust_ocr_transformer-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl (6.6 MB view details)

Uploaded CPython 3.9+macOS 10.12+ x86-64

File details

Details for the file rust_ocr_transformer-0.1.1.tar.gz.

File metadata

  • Download URL: rust_ocr_transformer-0.1.1.tar.gz
  • Upload date:
  • Size: 66.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for rust_ocr_transformer-0.1.1.tar.gz
Algorithm Hash digest
SHA256 ccff865a2602d373eda4e11084a8059ceab0efab0d6904e03b45ff989fa4a748
MD5 c0829fa808e6936ac4ccaa343f098431
BLAKE2b-256 1eb5ce52d92507eb5a50d66d96eace84e77cb71d3c8deac4e27a313986c80a06

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1.tar.gz:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rust_ocr_transformer-0.1.1-cp39-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for rust_ocr_transformer-0.1.1-cp39-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 2ecb68587df01c04a84228a13318fc2f5e0c7736b3984e313640a69114772979
MD5 e397ac34c22cf3ffd418d1cf51278c3e
BLAKE2b-256 00f5992e955f13f01355165a26348c3fa519671b405311a62c94745a2eb59e1d

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1-cp39-abi3-win_amd64.whl:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a6726fcc1eb5fa9190ddde8995ca705a01e4e7c2d2030204d9dd617057c72f27
MD5 dff1451ca1a17d39b00aa95f8d25375b
BLAKE2b-256 9690c6fd1da4aa3dc6bdf118a9a21d10dca3c452fed11ccba84d0320e78725a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 51ae6a6ec9844e5ef0c73cedc5d52a199d6ac4317e21c9d0e659389dab77ee3c
MD5 455a2ba58c712e2728ff3eb225361a47
BLAKE2b-256 94f577587ea10b9dba2f4303983206ab002e1deb54c408459ad6e3b8777a730f

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rust_ocr_transformer-0.1.1-cp39-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for rust_ocr_transformer-0.1.1-cp39-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 bd4b52c1a3ba2f46f2b92ad94f2614ed71efd2b48079663eef763d5bc84bca25
MD5 ac06f1b0f4f83164548c99219aa37e88
BLAKE2b-256 314c78680a198f02c01a2ce4a062abca791e6c64fdec2e4fbbc4048244ed1928

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1-cp39-abi3-macosx_11_0_arm64.whl:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file rust_ocr_transformer-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for rust_ocr_transformer-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 1c20463eadc4f5da28a1e9158a825e9d022ed9484e05960d3ca60222746fd433
MD5 3f23a82159b339d5ddb15fe13473e9b6
BLAKE2b-256 5377b232d18c74199280d3313fc30e1b62cf69467db87b13f1a4a92a8298a758

See more details on using hashes here.

Provenance

The following attestation bundles were made for rust_ocr_transformer-0.1.1-cp39-abi3-macosx_10_12_x86_64.whl:

Publisher: release.yml on arabangoo/rust_ocr_transformer

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page