ocr

package module
v0.0.0-...-2fc3ca7 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 24, 2026 License: MIT Imports: 15 Imported by: 0

README

go-ocr

Pure-Go, zero-CGO OCR. Calls a real ONNX Runtime shared library via purego (no cgo, no C compiler at build time) to run PaddleOCR's PP-OCRv5 detection + recognition models.

Status

Under active development, not yet published as a tagged release.

Why not CGO

Binding to libtesseract/libonnxruntime via cgo requires a C cross-compiler for every target platform. This project's consumers cross-compile from a single Linux host to Windows/macOS/Linux with plain go build and no C toolchain - purego loads the shared library with dlopen/LoadLibrary and calls its C API through Go-level FFI trampolines instead, so the build stays pure Go.

Usage

import ocr "github.com/Allod-Solutions/go-ocr"

eng, err := ocr.New(ocr.Options{
    RuntimeLibPath: "/path/to/onnxruntime.so",
    DetModelPath:   "/path/to/ppocrv5-det-mobile.onnx",
    RecModelPath:   "/path/to/ppocrv5-rec-en-mobile.onnx",
})
if err != nil {
    // ...
}
defer eng.Close()

text, err := eng.RecognizeText(ctx, imageBytes)

go-ocr does not download or embed the ONNX Runtime library or model weights (tens of MB) - callers supply local file paths. See NOTICE for the license of the algorithm this project ports and the runtime it binds to.

License

MIT. See NOTICE for attribution of the ported detection-postprocessing algorithm (PaddleOCR, Apache-2.0) and the ONNX Runtime C API this project binds to (Microsoft, MIT).

Maintained by Allod Solutions.

Documentation

Overview

Package ocr provides cgo-free OCR by running PaddleOCR's PP-OCRv5 detection + recognition ONNX models through a real ONNX Runtime shared library, loaded via purego (no cgo, no C compiler). See the package README for usage and NOTICE for attribution of the ported detection- postprocessing algorithm and the ONNX Runtime API this binds to.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func CTCGreedyDecode

func CTCGreedyDecode(probs []float32, timesteps, numClasses int, charset []string, blankIndex int) (string, float32)

CTCGreedyDecode decodes a [timesteps, numClasses] row-major probability (or raw logit - only relative ordering matters for argmax) matrix into text via greedy CTC decoding: per-timestep argmax, collapse consecutive repeats of the same class, drop blankIndex. charset must have exactly numClasses entries; charset[c] is the text emitted for class c (charset[blankIndex] is never used and may be empty) - callers own whatever index convention their specific model's dictionary file uses (e.g. index 0 reserved for blank vs. appended at the end differs across PaddleOCR releases, so this function does not assume one).

Returns the decoded string and the mean of the per-kept-timestep max probability, as a rough per-line confidence signal.

func PreprocessDetection

func PreprocessDetection(img image.Image, opts DetPreprocessOptions) (data []float32, shape []int64, ratioH, ratioW float64, err error)

PreprocessDetection resizes img per PaddleOCR's DetResizeForTest (resize_image_type0): each side independently rounded to the nearest multiple of 32 (minimum 32), after first scaling down so the longer side does not exceed LimitSideLen. Returns NCHW float32 data (batch size 1, normalized per-channel) plus the height/width resize ratios needed to map detected boxes back to img's original pixel coordinates.

func PreprocessRecognition

func PreprocessRecognition(img image.Image, opts RecPreprocessOptions) (data []float32, shape []int64, err error)

PreprocessRecognition resizes a cropped text-line image to TargetHeight, preserving aspect ratio, capping the resized width at TargetWidth and right-zero-padding if narrower (matches PaddleOCR's resize_norm_img). Returns NCHW float32 data for batch size 1, channel order BGR (see DetPreprocessOptions.Mean's doc - the same PaddleOCR BGR-decode convention applies here even though the 0.5/0.5 normalization constant is identical across channels, since channel *order* still matters to the model).

Types

type Box

type Box struct {
	Corners [4]Point
}

Box is a detected text region, in original-image pixel coordinates, ordered [top-left, top-right, bottom-right, bottom-left] per PaddleOCR's convention (see orderMiniBoxCorners).

func DetectBoxes

func DetectBoxes(probMap []float32, mapH, mapW int, ratioH, ratioW float64, origW, origH int, opts DBOptions) []Box

DetectBoxes runs DB postprocessing on a detection model's raw output probability map (probMap, row-major, mapH x mapW - the resized/padded space the model actually ran on) and returns text-region boxes rescaled to the original image's pixel coordinates (origW x origH), sorted in reading order. ratioH/ratioW are (mapH/origH, mapW/origW), as returned by PreprocessDetection.

type DBOptions

type DBOptions struct {
	Thresh      float64 // binarization threshold on the raw probability map
	BoxThresh   float64 // minimum mean probability inside a candidate box to keep it
	UnclipRatio float64 // box expansion factor
	MinSize     float64 // minimum shorter-side length (in resized-image pixels) to keep a box
}

DBOptions configures the DB (Differentiable Binarization) detection postprocess. Defaults match PaddleOCR's documented DBPostProcess defaults; as with preprocessing options, these must still be verified against the actual pinned PP-OCRv5 export.

func DefaultDBOptions

func DefaultDBOptions() DBOptions

DefaultDBOptions returns PaddleOCR's documented DBPostProcess defaults.

type DetPreprocessOptions

type DetPreprocessOptions struct {
	LimitSideLen int
	// Mean/Std are per-channel in BGR order (index 0=B, 1=G, 2=R) - PaddleOCR
	// decodes images via OpenCV (cv2.imread, BGR by default) and normalizes
	// in that same channel order without ever converting to RGB, so the
	// model's input tensor channel 0 is normalized Blue, not Red. Confirmed
	// against the official PP-OCRv5_mobile_det inference.yml
	// (DecodeImage.img_mode: BGR). Getting this backwards silently swaps R
	// and B for every pixel - not a shape/crash bug, so nothing catches it
	// except comparing against a real model's actual behavior.
	Mean [3]float32
	Std  [3]float32
}

DetPreprocessOptions configures detection-model preprocessing. Defaults match PaddleOCR's DetResizeForTest + NormalizeImage operators; the exact values must still be verified against whichever PP-OCRv5 ONNX export is pinned (see go-ocr's open follow-ups) before shipping - these are the well-documented PaddleOCR defaults, not yet confirmed against that specific artifact's own config.

func DefaultDetPreprocessOptions

func DefaultDetPreprocessOptions() DetPreprocessOptions

DefaultDetPreprocessOptions returns PaddleOCR's documented defaults (ImageNet mean/std, 960px side limit).

type Engine

type Engine struct {
	// contains filtered or unexported fields
}

Engine is a loaded detection+recognition pipeline. Safe for concurrent use by multiple goroutines - the allodswg print-DLP path runs one goroutine per print job and needs this guarantee.

func New

func New(opts Options) (*Engine, error)

New loads the ONNX Runtime library and both models, and reads the recognition charset. Returns an error - not a nil-and-swallowed failure - on any problem; "best-effort, silent on failure" is a policy decision for callers to make at their own call site (see allodswg's screenshot.go wiring), not something this reusable library bakes in.

func (*Engine) Close

func (e *Engine) Close() error

Close releases both sessions and the runtime. Safe to call once; the allodswg wiring is responsible for not calling into a closed Engine concurrently with Close (see its idle-timeout lifecycle).

func (*Engine) RecognizeLines

func (e *Engine) RecognizeLines(ctx context.Context, imageBytes []byte) ([]Line, error)

RecognizeLines runs detection then recognition on imageBytes (PNG/JPEG), returning one Line per detected text region that decoded to non-empty text, in reading order.

NOTE: the assumed output tensor layouts below (detection: last two dims are [H, W]; recognition: [1, T, C]) match PaddleOCR's documented PP-OCRv5 export shapes but are NOT YET VERIFIED against a real pinned model file - no ONNX artifact was available in this environment. Confirm via Session.OutputNames()/actual Run() output shapes against the real files before relying on this in production; this is the concrete task Milestone 6's golden test (blocked on sourcing that file) exists to catch.

func (*Engine) RecognizeText

func (e *Engine) RecognizeText(ctx context.Context, imageBytes []byte) (string, error)

RecognizeText runs the full pipeline and returns extracted text, lines joined by "\n" in reading order (see sortBoxesReadingOrder).

type Line

type Line struct {
	Text       string
	Confidence float32
	Box        Box
}

Line is one detected, recognized text line, in original-image pixel coordinates.

type Options

type Options struct {
	RuntimeLibPath string // onnxruntime.{dll,so,dylib}
	DetModelPath   string // PP-OCRv5 detection .onnx
	RecModelPath   string // PP-OCRv5 recognition .onnx

	// RecCharsetPath is the recognition model's dictionary file, one
	// character/token per line, in class-index order. Required - there is
	// no embedded default, because a wrong or mismatched charset produces
	// silently-wrong decoded text (plausible-looking output, no error),
	// which is worse than requiring the caller to supply the file that
	// actually matches their pinned model export.
	RecCharsetPath string

	// BlankIndex is the CTC blank class index in the recognition model's
	// output, and its position within RecCharsetPath's line order. Verify
	// against the actual pinned model/dictionary; PaddleOCR has used both
	// index-0 and last-index conventions across versions. Defaults to 0.
	BlankIndex int

	IntraOpNumThreads int

	// Zero-value Det/Rec/DB options fall back to their package defaults
	// (DefaultDetPreprocessOptions / DefaultRecPreprocessOptions /
	// DefaultDBOptions) - see those functions' docs for the caveat that
	// the defaults are PaddleOCR's documented values, not yet confirmed
	// against a specific pinned model export.
	DetOptions DetPreprocessOptions
	RecOptions RecPreprocessOptions
	DBOptions  DBOptions
}

Options configures a new Engine. All model/library paths are plain filesystem paths - this package does not download or embed the ONNX Runtime shared library or model weights; callers own fetching those (see README).

type Point

type Point struct{ X, Y float32 }

Point is a 2D coordinate in original-image pixel space.

type RecPreprocessOptions

type RecPreprocessOptions struct {
	TargetHeight int
	TargetWidth  int // max width; narrower resized images are right-zero-padded
}

RecPreprocessOptions configures recognition-model preprocessing. Defaults match PP-OCRv4/v5's documented rec image shape (3, 48, 320) and (px/255 - 0.5)/0.5 normalization - a single mean/std applied uniformly across channels, distinct from detection's per-channel ImageNet stats. Must be verified against the actual pinned model, same caveat as det options.

func DefaultRecPreprocessOptions

func DefaultRecPreprocessOptions() RecPreprocessOptions

DefaultRecPreprocessOptions returns PP-OCRv4/v5's documented defaults.

Directories

Path Synopsis
internal
ortapi
Package ortapi is a minimal, purego-based (no cgo) binding to the subset of the ONNX Runtime C API needed to load a model and run inference.
Package ortapi is a minimal, purego-based (no cgo) binding to the subset of the ONNX Runtime C API needed to load a model and run inference.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL