### Run OCR Example Source: https://github.com/robertknight/ocrs/blob/main/ocrs/README.md This example demonstrates how to download models and run OCR on an image using the OCRS library. Ensure you build in release mode for optimal performance. ```sh cd examples/ # Download models in .rten format. ./download-models.sh # Run OCR on an image and print the extracted text. cargo run --release --example hello_ocr rust-book.jpg ``` -------------------------------- ### CLI Usage Examples Source: https://context7.com/robertknight/ocrs/llms.txt Examples demonstrating various command-line options for OCRS, such as using custom models, restricting characters, and enabling debug logging. ```APIDOC ## Use a custom recognition model with a custom alphabet. ocrs image.png --rec-model ./my-rec.rten --alphabet "0123456789ABCDEFabcdef" ## Restrict output to digits only. ocrs image.png --allowed-chars "0123456789" ## Use beam search decoding (more accurate, slower). ocrs image.png --beam ## Generate a text probability heatmap image. ocrs image.png --text-map ## Generate a binary text mask image. ocrs image.png --text-mask ## Export preprocessed images of each detected text line (for debugging). ocrs image.png --text-line-images ## Enable debug logging (word/line counts, timing). ocrs image.png --debug ``` -------------------------------- ### Full OCR Pipeline Example in Rust Source: https://context7.com/robertknight/ocrs/llms.txt A complete example demonstrating the OcrEngine's capabilities, including text detection, line grouping, and recognition with word-level bounding boxes. This example processes an image file and prints recognized lines and words with their coordinates. ```rust use std::error::Error; use ocrs::{ImageSource, OcrEngine, OcrEngineParams, TextItem}; use rten::Model; fn main() -> Result<(), Box> { let detection_model = Model::load_file("examples/text-detection.rten")?; let recognition_model = Model::load_file("examples/text-recognition.rten")?; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(detection_model), recognition_model: Some(recognition_model), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; // Step 1: detect word bounding boxes. let word_rects = engine.detect_words(&ocr_input)?; // Step 2: group and sort into reading-order lines. let line_rects = engine.find_text_lines(&ocr_input, &word_rects); // Step 3: recognize characters in each line. let line_texts = engine.recognize_text(&ocr_input, &line_rects)?; for line in line_texts.iter().flatten().filter(|l| l.to_string().len() > 1) { println!("Line: {}", line); for word in line.words() { let r = word.bounding_rect(); println!(" [{},{}] '{}'", r.left(), r.top(), word); } } // Example output: // Line: Hello World // [10,5] 'Hello' // [85,5] 'World' Ok(()) } ``` -------------------------------- ### Install ocrs-cli with Cargo Source: https://github.com/robertknight/ocrs/blob/main/README.md Install the ocrs CLI tool using Cargo. Ensure Rust and Cargo are installed first. ```sh cargo install ocrs-cli --locked ``` -------------------------------- ### Install ocrs-cli with Clipboard Support Source: https://github.com/robertknight/ocrs/blob/main/README.md Install the ocrs CLI tool with the 'clipboard' feature enabled to support reading images from the system clipboard. ```sh cargo install ocrs-cli --locked --features clipboard ``` -------------------------------- ### Build Browser Extension Source: https://github.com/robertknight/ocrs/blob/main/ocrs-extension/README.md Install dependencies and build the browser extension. Navigate to the `ocrs-extension` directory before running these commands. ```sh cd ocrs-extension npm install make build ``` -------------------------------- ### CLI: Install and Basic Text Extraction Source: https://context7.com/robertknight/ocrs/llms.txt Instructions for installing the `ocrs-cli` tool using Cargo, including an optional feature for clipboard support. Demonstrates basic text extraction from an image file and piping input from stdin. ```sh # Install (requires Rust/Cargo). cargo install ocrs-cli --locked # Install with clipboard support. cargo install ocrs-cli --locked --features clipboard # Extract text from an image (models downloaded automatically on first run). ocrs image.png # Write output to a file. ocrs image.png -o content.txt # Extract from stdin (pipe-friendly). cat image.png | ocrs # Extract from system clipboard. ocrs --clipboard ocrs -c # short form ``` -------------------------------- ### Extract Text from Clipboard using CLI Source: https://github.com/robertknight/ocrs/blob/main/README.md Extract text from an image currently on the system clipboard using the ocrs CLI. Requires installation with the 'clipboard' feature. ```sh ocrs --clipboard ``` ```sh ocrs -c ``` -------------------------------- ### JSON Output Structure for OCR Results Source: https://context7.com/robertknight/ocrs/llms.txt Example of the JSON structure produced by the `ocrs --json` command, detailing image dimensions and hierarchical text layout including paragraphs, lines, and words with their vertices. ```json { "url": "image.png", "image_width": 1200, "image_height": 800, "paragraphs": [ { "lines": [ { "text": "Hello World", "vertices": [[10, 5], [120, 5], [120, 25], [10, 25]], "words": [ { "text": "Hello", "vertices": [[10, 5], [55, 5], [55, 25], [10, 25]] }, { "text": "World", "vertices": [[65, 5], [120, 5], [120, 25], [65, 25]] } ] } ] } ] } ``` -------------------------------- ### Recognize Text from Image Lines with OcrEngine Source: https://context7.com/robertknight/ocrs/llms.txt Use `recognize_text` after detecting text lines to get the recognized text. It returns a vector of optional `TextLine` objects, one for each input line. Filter for lines with recognized text and iterate through words for detailed information. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("receipt.jpg")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); let line_texts = engine.recognize_text(&ocr_input, &line_rects)?; for line in line_texts.iter().flatten().filter(|l| l.to_string().len() > 1) { println!("{}", line); // Iterate individual words with their bounding boxes: for word in line.words() { let br = word.bounding_rect(); println!(" '{}' at ({}, {})", word, br.left(), br.top()); } } ``` -------------------------------- ### Detect Text Positions Without Recognition Source: https://context7.com/robertknight/ocrs/llms.txt Use `detectText` to get word bounding boxes without running the recognition model. This is faster when only positional information is needed. ```javascript // Detect text positions without running the recognition model. const detectedLines = ocrEngine.detectText(ocrInput); const result = detectedLines.map((line) => ({ lineRect: Array.from(line.rotatedRect().boundingRect()), words: line.words().map((word) => ({ rect: Array.from(word.boundingRect()), })), })); console.log(JSON.stringify(result, null, 2)); // Output: // [ // { // "lineRect": [10, 5, 200, 30], // "words": [ // { "rect": [10, 5, 80, 30] }, // { "rect": [90, 5, 200, 30] } // ] // } // ] ``` -------------------------------- ### Detect Text Pixels with OcrEngine Source: https://context7.com/robertknight/ocrs/llms.txt Use `detect_text_pixels` to get a probability map indicating text pixels. This is useful for debugging detection quality or creating visual masks. The output is a 2D tensor where each value represents the probability of a pixel belonging to a text word. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("page.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let text_map = engine.detect_text_pixels(&ocr_input)?; let threshold = engine.detection_threshold(); // default ~0.2 // Binarize into a text mask. let text_mask = text_map.map(|&p| if p > threshold { 1.0f32 } else { 0.0 }); let [height, width] = text_map.shape(); println!("Text probability map: {}×{}, threshold={:.2}", width, height, threshold); ``` -------------------------------- ### OcrEngine Initialization and Usage (JavaScript) Source: https://context7.com/robertknight/ocrs/llms.txt Demonstrates how to initialize the OcrEngine using WebAssembly and process an image to extract text, both as a single string and structured lines with word bounding boxes. ```APIDOC ## OcrEngineInit and OcrEngine (Node.js / Browser) ### Description Initializes the OcrEngine with detection and recognition models and processes an image to extract text. ### Method ```javascript import { readFile } from "fs/promises"; import { OcrEngine, OcrEngineInit, default as initOcrLib } from "ocrs"; import sharp from "sharp"; // Load the Wasm module, models, and image concurrently. const wasmBinary = await readFile("ocrs_bg.wasm"); const [_, detectionModel, recognitionModel] = await Promise.all([ initOcrLib(wasmBinary), readFile("text-detection.rten").then((d) => new Uint8Array(d)), readFile("text-recognition.rten").then((d) => new Uint8Array(d)), ]); // Initialize engine. const ocrInit = new OcrEngineInit(); ocrInit.setDetectionModel(detectionModel); ocrInit.setRecognitionModel(recognitionModel); const ocrEngine = new OcrEngine(ocrInit); // Load image as raw RGB bytes. const image = sharp("document.png"); const { width, height } = await image.metadata(); const data = new Uint8Array(await image.raw().toBuffer()); const ocrInput = ocrEngine.loadImage(width, height, data); // Simple: get all text as a string. const text = ocrEngine.getText(ocrInput); console.log(text); // Structured: get lines with word bounding boxes. const textLines = ocrEngine.getTextLines(ocrInput); for (const line of textLines) { console.log("Line:", line.text()); for (const word of line.words()) { const [left, top, right, bottom] = word.rotatedRect().boundingRect(); console.log(` '${word.text()}' at [${left},${top},${right},${bottom}]`); } } ``` ``` -------------------------------- ### Initialize OcrEngine with Models (Node.js/Browser) Source: https://context7.com/robertknight/ocrs/llms.txt Loads Wasm module and models, then initializes the OcrEngine. Requires models to be loaded as Uint8Array. ```javascript import { readFile } from "fs/promises"; import { OcrEngine, OcrEngineInit, default as initOcrLib } from "ocrs"; import sharp from "sharp"; // Load the Wasm module, models, and image concurrently. const wasmBinary = await readFile("ocrs_bg.wasm"); const [_, detectionModel, recognitionModel] = await Promise.all([ initOcrLib(wasmBinary), readFile("text-detection.rten").then((d) => new Uint8Array(d)), readFile("text-recognition.rten").then((d) => new Uint8Array(d)), ]); // Initialize engine. const ocrInit = new OcrEngineInit(); ocrInit.setDetectionModel(detectionModel); ocrInit.setRecognitionModel(recognitionModel); const ocrEngine = new OcrEngine(ocrInit); // Load image as raw RGB bytes. const image = sharp("document.png"); const { width, height } = await image.metadata(); const data = new Uint8Array(await image.raw().toBuffer()); const ocrInput = ocrEngine.loadImage(width, height, data); // Simple: get all text as a string. const text = ocrEngine.getText(ocrInput); console.log(text); // Structured: get lines with word bounding boxes. const textLines = ocrEngine.getTextLines(ocrInput); for (const line of textLines) { console.log("Line:", line.text()); for (const word of line.words()) { const [left, top, right, bottom] = word.rotatedRect().boundingRect(); console.log(` '${word.text()}' at [${left},${top},${right},${bottom}]`); } } ``` -------------------------------- ### Build WebAssembly OCR Library Source: https://github.com/robertknight/ocrs/blob/main/ocrs-extension/README.md Build the WebAssembly OCR library. This command should be run in the root directory of the repository. ```sh make wasm ``` -------------------------------- ### Build and Run ocrs Locally Source: https://github.com/robertknight/ocrs/blob/main/README.md Build and run the ocrs CLI tool locally after cloning the repository. Requires a recent stable Rust version. ```sh git clone https://github.com/robertknight/ocrs.git cd ocrs cargo run -p ocrs-cli -r -- image.png ``` -------------------------------- ### Configure OcrEngine with Custom Parameters Source: https://context7.com/robertknight/ocrs/llms.txt Load detection and recognition models from .rten files. Configure engine parameters like debug logging, beam-search decoding width, and allowed characters. ```rust use ocrs::{OcrEngine, OcrEngineParams}; use ocrs::DecodeMethod; use rten::Model; // Load models from .rten files (use download-models.sh to fetch them). let detection_model = Model::load_file("text-detection.rten")?; let recognition_model = Model::load_file("text-recognition.rten")?; // Minimal engine with both models. let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(detection_model), recognition_model: Some(recognition_model), ..Default::default() })?; // Engine with beam-search decoding, debug logging, and digit-only output. let engine_custom = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), debug: true, decode_method: DecodeMethod::BeamSearch { width: 100 }, allowed_chars: Some("0123456789".to_string()), alphabet: None, // use default alphabet ..Default::default() })?; ``` -------------------------------- ### OcrEngine::new — Construct the engine Source: https://context7.com/robertknight/ocrs/llms.txt Creates an `OcrEngine` from `OcrEngineParams`. Returns `anyhow::Result`. At least one of `detection_model` or `recognition_model` must be provided for the corresponding step to work. ```APIDOC ## OcrEngine::new — Construct the engine Creates an `OcrEngine` from `OcrEngineParams`. Returns `anyhow::Result`. At least one of `detection_model` or `recognition_model` must be provided for the corresponding step to work. ```rust use ocrs::{OcrEngine, OcrEngineParams}; use rten::Model; fn build_engine() -> anyhow::Result { let detection_model = Model::load_file("text-detection.rten")?; let recognition_model = Model::load_file("text-recognition.rten")?; OcrEngine::new(OcrEngineParams { detection_model: Some(detection_model), recognition_model: Some(recognition_model), ..Default::default() }) } ``` ``` -------------------------------- ### Download and Copy OCR Models Source: https://github.com/robertknight/ocrs/blob/main/ocrs-extension/README.md Download pre-trained OCR models using the ocrs CLI tool and copy them to the models directory. Replace `test-image.jpeg` with any image file you have. ```sh cargo run -r -p ocrs-cli test-image.jpeg mkdir -p models/ocr cp ~/.cache/ocrs/text-detection.rten ~/.cache/ocrs/text-recognition.rten models/ocr ``` -------------------------------- ### Dry Run Release with Cargo-Release (Workspace) Source: https://github.com/robertknight/ocrs/blob/main/docs/release.md Perform a dry run of the release for the entire workspace using `cargo release --workspace `. This allows you to preview the release without making any actual changes. ```bash cargo release --workspace ``` -------------------------------- ### Build OcrEngine Instance Source: https://context7.com/robertknight/ocrs/llms.txt Construct an OcrEngine using OcrEngineParams. Ensure at least one model (detection or recognition) is provided for the respective step to function. ```rust use ocrs::{OcrEngine, OcrEngineParams}; use rten::Model; fn build_engine() -> anyhow::Result { let detection_model = Model::load_file("text-detection.rten")?; let recognition_model = Model::load_file("text-recognition.rten")?; OcrEngine::new(OcrEngineParams { detection_model: Some(detection_model), recognition_model: Some(recognition_model), ..Default::default() }) } ``` -------------------------------- ### CTC Decoding Strategies: Greedy vs. Beam Search Source: https://context7.com/robertknight/ocrs/llms.txt Configure the OcrEngine with different decoding methods. Greedy is faster, while BeamSearch with a specified width can improve accuracy on ambiguous text. ```rust use ocrs::{OcrEngine, OcrEngineParams, DecodeMethod}; use rten::Model; // Greedy decoding (default, fastest). let engine_greedy = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), decode_method: DecodeMethod::Greedy, ..Default::default() })?; ``` ```rust // Beam search decoding (slower, potentially more accurate). let engine_beam = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), decode_method: DecodeMethod::BeamSearch { width: 100 }, ..Default::default() })?; ``` -------------------------------- ### Run Lint and Unit Tests Source: https://github.com/robertknight/ocrs/blob/main/README.md Execute lint checks and unit tests for the ocrs project using the provided Makefile. ```sh make check ``` -------------------------------- ### Generate Text Probability Heatmap Source: https://context7.com/robertknight/ocrs/llms.txt Create a heatmap image visualizing text probability. ```bash ocrs image.png --text-map ``` -------------------------------- ### Prepare Image Input for OcrEngine Source: https://context7.com/robertknight/ocrs/llms.txt Converts an ImageSource to OcrInput by performing greyscale conversion and pixel normalization. This OcrInput is then passed to all subsequent engine methods. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; // ocr_input can now be reused across detect_words, recognize_text, etc. ``` -------------------------------- ### Use Custom Recognition Model and Alphabet Source: https://context7.com/robertknight/ocrs/llms.txt Specify a custom recognition model and define a custom alphabet for recognition. ```bash ocrs image.png --rec-model ./my-rec.rten --alphabet "0123456789ABCDEFabcdef" ``` -------------------------------- ### Enable Debug Logging Source: https://context7.com/robertknight/ocrs/llms.txt Activate debug logging to view word/line counts and timing information. ```bash ocrs image.png --debug ``` -------------------------------- ### Extract Text and Layout in JSON using CLI Source: https://github.com/robertknight/ocrs/blob/main/README.md Extract text and layout information from an image and output it in JSON format to a specified file. ```sh ocrs image.png --json -o content.json ``` -------------------------------- ### Create ImageSource from Raw Bytes Source: https://context7.com/robertknight/ocrs/llms.txt Wrap raw pixel bytes (HWC format, 1, 3, or 4 channels) into an ImageSource. Compatible with the `image` crate's raw buffer output. ```rust use ocrs::ImageSource; // Load an image with the `image` crate and wrap it for ocrs. let img = image::open("photo.jpg")?.into_rgb8(); let (width, height) = img.dimensions(); let img_source = ImageSource::from_bytes(img.as_raw(), (width, height))?; // img_source is ready to pass to engine.prepare_input(...) ``` -------------------------------- ### OcrEngine::prepare_input Source: https://context7.com/robertknight/ocrs/llms.txt Converts an ImageSource into an OcrInput by performing greyscale conversion and pixel normalization. This OcrInput is then passed to all subsequent engine methods. ```APIDOC ## `OcrEngine::prepare_input` — Preprocess an image for OCR ### Description Converts an `ImageSource` into an `OcrInput` by performing greyscale conversion and pixel normalization (values mapped to `[-0.5, 0.5]`). This `OcrInput` is then passed to all subsequent engine methods. ### Usage ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; // ocr_input can now be reused across detect_words, recognize_text, etc. ``` ``` -------------------------------- ### ImageSource::from_bytes — Create image input from raw pixel bytes Source: https://context7.com/robertknight/ocrs/llms.txt Constructs an `ImageSource` from a byte slice in HWC (height × width × channels) row-major order. Supports 1 (greyscale), 3 (RGB), or 4 (RGBA) channels. Compatible with the `image` crate's raw buffer output. ```APIDOC ## ImageSource::from_bytes — Create image input from raw pixel bytes Constructs an `ImageSource` from a byte slice in HWC (height × width × channels) row-major order. Supports 1 (greyscale), 3 (RGB), or 4 (RGBA) channels. Compatible with the `image` crate's raw buffer output. ```rust use ocrs::ImageSource; // Load an image with the `image` crate and wrap it for ocrs. let img = image::open("photo.jpg")?.into_rgb8(); let (width, height) = img.dimensions(); let img_source = ImageSource::from_bytes(img.as_raw(), (width, height))?; // img_source is ready to pass to engine.prepare_input(...) ``` ``` -------------------------------- ### Use Beam Search Decoding Source: https://context7.com/robertknight/ocrs/llms.txt Enable beam search decoding for potentially more accurate but slower OCR results. ```bash ocrs image.png --beam ``` -------------------------------- ### CLI: Annotated PNG Output Source: https://context7.com/robertknight/ocrs/llms.txt Generate an annotated PNG image that visually displays the detected word bounding boxes on top of the original image. This command is useful for debugging and visualizing detection results. ```sh # Produce annotated copy of the input image showing detected word boxes. ocrs image.png --png -o annotated.png # Use a custom text detection model. ocrs image.png --detect-model ./my-detection.rten ``` -------------------------------- ### Debug Recognition Input with OcrEngine Source: https://context7.com/robertknight/ocrs/llms.txt Use `prepare_recognition_input` to extract the preprocessed image of a text line before it's fed to the recognition model. This returns a greyscale tensor useful for debugging recognition accuracy. Remember to shift values back to [0, 1] if saving as an image. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); // Inspect the preprocessed image for the first line. if let Some(first_line) = line_rects.first() { let mut line_img = engine.prepare_recognition_input(&ocr_input, first_line)?; // Shift from [-0.5, 0.5] back to [0, 1] for saving as PNG. line_img.apply(|x| x + 0.5); println!("Line image shape: {:?}", line_img.shape()); } ``` -------------------------------- ### Dry Run Release with Cargo-Release (Specific Crates) Source: https://github.com/robertknight/ocrs/blob/main/docs/release.md Execute a dry run for specific crates by listing them with `-p crate1 -p crate2 `. This is useful when only a subset of crates needs to be released. The `--exclude` flag can also be used to omit packages. ```bash cargo release -p crate1 -p crate2 ``` -------------------------------- ### Generate Binary Text Mask Source: https://context7.com/robertknight/ocrs/llms.txt Create a binary mask image highlighting detected text areas. ```bash ocrs image.png --text-mask ``` -------------------------------- ### OcrEngineParams — Engine configuration struct Source: https://context7.com/robertknight/ocrs/llms.txt Configuration passed to `OcrEngine::new`. Holds optional detection and recognition models, decode method, debug flag, custom alphabet, and character allow-list. ```APIDOC ## OcrEngineParams — Engine configuration struct Configuration passed to `OcrEngine::new`. Holds optional detection and recognition models, decode method, debug flag, custom alphabet, and character allow-list. ```rust use ocrs::{OcrEngine, OcrEngineParams}; use ocrs::DecodeMethod; use rten::Model; // Load models from .rten files (use download-models.sh to fetch them). let detection_model = Model::load_file("text-detection.rten")?; let recognition_model = Model::load_file("text-recognition.rten")?; // Minimal engine with both models. let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(detection_model), recognition_model: Some(recognition_model), ..Default::default() })?; // Engine with beam-search decoding, debug logging, and digit-only output. let engine_custom = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), debug: true, decode_method: DecodeMethod::BeamSearch { width: 100 }, allowed_chars: Some("0123456789".to_string()), alphabet: None, // use default alphabet ..Default::default() })?; ``` ``` -------------------------------- ### Extract Text to File using CLI Source: https://github.com/robertknight/ocrs/blob/main/README.md Extract text from an image and save the output to a specified text file. ```sh ocrs image.png -o content.txt ``` -------------------------------- ### Extract All Text as a Single String with OcrEngine::get_text Source: https://context7.com/robertknight/ocrs/llms.txt Runs the full pipeline (detect → layout → recognize) and returns all text joined by newlines. This is the simplest API when layout information is not needed. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; fn ocr_file(path: &str) -> anyhow::Result { let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open(path)?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let text = engine.get_text(&ocr_input)?; // Returns all lines joined with '\n', e.g.: // "Hello World\nSecond line of text\nThird line" Ok(text) } ``` -------------------------------- ### Annotate Image with Detected Text using CLI Source: https://github.com/robertknight/ocrs/blob/main/README.md Extract text from an image and generate an annotated PNG image highlighting detected words and lines. ```sh ocrs image.png --png -o annotated.png ``` -------------------------------- ### Export Preprocessed Text Line Images Source: https://context7.com/robertknight/ocrs/llms.txt Export images of each detected text line for debugging purposes. ```bash ocrs image.png --text-line-images ``` -------------------------------- ### Execute Release with Cargo-Release Source: https://github.com/robertknight/ocrs/blob/main/docs/release.md After a successful dry run, execute the release process by running `cargo release changes` again, this time with the `--execute` flag. This flag confirms the release and applies the changes. ```bash cargo release --execute ``` -------------------------------- ### OcrEngine::prepare_recognition_input Source: https://context7.com/robertknight/ocrs/llms.txt Debug utility to extract the preprocessed image of a text line before it's fed into the recognition model. Returns a greyscale tensor. ```APIDOC ## `OcrEngine::prepare_recognition_input` — Debug: extract preprocessed line image Exposes the preprocessing step that `recognize_text` applies before feeding a text line into the recognition model. Returns a greyscale `(H, W)` tensor with values in `[-0.5, 0.5]`. Useful for debugging recognition accuracy. ### Usage Example ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); // Inspect the preprocessed image for the first line. if let Some(first_line) = line_rects.first() { let mut line_img = engine.prepare_recognition_input(&ocr_input, first_line)?; // Shift from [-0.5, 0.5] back to [0, 1] for saving as PNG. line_img.apply(|x| x + 0.5); println!("Line image shape: {:?}", line_img.shape()); } ``` ``` -------------------------------- ### Run End-to-End Tests Source: https://github.com/robertknight/ocrs/blob/main/README.md Execute the end-to-end tests for the ocrs project, which cover the entire OCR pipeline including ML models. ```sh make test-e2e ``` -------------------------------- ### CLI: JSON Output with Layout Information Source: https://context7.com/robertknight/ocrs/llms.txt Command to output OCR results, including word and line bounding boxes, in JSON format. This is useful for programmatic processing of recognition data. ```sh # Output text with word/line bounding boxes in JSON format. ocrs image.png --json -o content.json ``` -------------------------------- ### Detect Text Word Bounding Boxes with OcrEngine::detect_words Source: https://context7.com/robertknight/ocrs/llms.txt Runs the text detection model and returns an unordered Vec of oriented bounding rectangles, one per detected word. Use this when you need raw word positions before layout grouping. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("screenshot.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; println!("Detected {} words", word_rects.len()); for rect in &word_rects { let br = rect.bounding_rect(); println!(" word at ({}, {}) size {}×{}", br.left(), br.top(), br.width(), br.height()); } ``` -------------------------------- ### Group Words into Reading-Order Lines with OcrEngine::find_text_lines Source: https://context7.com/robertknight/ocrs/llms.txt Takes the unordered word rectangles from detect_words and returns them grouped and sorted into reading order. Each element in the returned Vec> is one line, containing the word bounding boxes for that line in left-to-right order. ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); println!("Found {} lines", line_rects.len()); for (i, line) in line_rects.iter().enumerate() { println!(" Line {}: {} words", i, line.len()); } ``` -------------------------------- ### Create ImageSource from Tensor Source: https://context7.com/robertknight/ocrs/llms.txt Construct an ImageSource from an NdTensorView (u8 or f32) in CHW or HWC layout. Useful for integrating with existing tensor pipelines. ```rust use ocrs::{DimOrder, ImageSource}; use rten_tensor::NdTensor; // CHW float tensor (e.g. from a machine learning pipeline). let tensor: NdTensor = NdTensor::zeros([3, 480, 640]); // 3×H×W let img_source = ImageSource::from_tensor(tensor.view(), DimOrder::Chw)?; // HWC u8 tensor (e.g. from a video frame). let hwc: NdTensor = NdTensor::zeros([480, 640, 3]); // H×W×3 let img_source_hwc = ImageSource::from_tensor(hwc.view(), DimOrder::Hwc)?; ``` -------------------------------- ### Extract Text from Image using CLI Source: https://github.com/robertknight/ocrs/blob/main/README.md Extract text from an image file using the ocrs CLI. The tool automatically downloads necessary models on the first run. ```sh ocrs image.png ``` -------------------------------- ### OcrEngine::recognize_text Source: https://context7.com/robertknight/ocrs/llms.txt Recognizes characters in detected line regions. It takes preprocessed input and line regions, returning recognized text lines. ```APIDOC ## `OcrEngine::recognize_text` — Recognize characters in detected lines Runs the text recognition model on the line regions produced by `find_text_lines`. Returns `Vec>` where each entry corresponds to an input line; entries are `None` when no text was recognized for that line region. ### Usage Example ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), recognition_model: Some(Model::load_file("text-recognition.rten")?), ..Default::default() })?; let img = image::open("receipt.jpg")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); let line_texts = engine.recognize_text(&ocr_input, &line_rects)?; for line in line_texts.iter().flatten().filter(|l| l.to_string().len() > 1) { println!("{}", line); // Iterate individual words with their bounding boxes: for word in line.words() { let br = word.bounding_rect(); println!(" '{}' at ({}, {})", word, br.left(), br.top()); } } ``` ``` -------------------------------- ### OcrEngine.detectText (JavaScript) Source: https://context7.com/robertknight/ocrs/llms.txt Performs text detection without recognition, returning line and word bounding boxes. This is faster when only positional information is needed. ```APIDOC ## OcrEngine.detectText — Detection without recognition (JavaScript) ### Description Returns `DetectedLine[]` with word bounding boxes but no recognized text. Faster when only positions are needed. ### Method ```javascript // Detect text positions without running the recognition model. const detectedLines = ocrEngine.detectText(ocrInput); const result = detectedLines.map((line) => ({ lineRect: Array.from(line.rotatedRect().boundingRect()), words: line.words().map((word) => ({ rect: Array.from(word.boundingRect()), })), })); console.log(JSON.stringify(result, null, 2)); // Output: // [ // { // "lineRect": [10, 5, 200, 30], // "words": [ // { "rect": [10, 5, 80, 30] }, // { "rect": [90, 5, 200, 30] } // ] // } // ] ``` ``` -------------------------------- ### ImageSource::from_tensor — Create image input from a tensor Source: https://context7.com/robertknight/ocrs/llms.txt Constructs an `ImageSource` from an `NdTensorView` of `u8` or `f32` values in either CHW (channels first) or HWC (channels last) layout, specified via `DimOrder`. ```APIDOC ## ImageSource::from_tensor — Create image input from a tensor Constructs an `ImageSource` from an `NdTensorView` of `u8` or `f32` values in either CHW (channels first) or HWC (channels last) layout, specified via `DimOrder`. ```rust use ocrs::{DimOrder, ImageSource}; use rten_tensor::NdTensor; // CHW float tensor (e.g. from a machine learning pipeline). let tensor: NdTensor = NdTensor::zeros([3, 480, 640]); // 3×H×W let img_source = ImageSource::from_tensor(tensor.view(), DimOrder::Chw)?; // HWC u8 tensor (e.g. from a video frame). let hwc: NdTensor = NdTensor::zeros([480, 640, 3]); // H×W×3 let img_source_hwc = ImageSource::from_tensor(hwc.view(), DimOrder::Hwc)?; ``` ``` -------------------------------- ### OcrEngine::find_text_lines Source: https://context7.com/robertknight/ocrs/llms.txt Groups detected word bounding boxes into reading-order lines. It takes the unordered word rectangles and returns them organized into lines, with words within each line sorted left-to-right. ```APIDOC ## `OcrEngine::find_text_lines` — Group words into reading-order lines ### Description Takes the unordered word rectangles from `detect_words` and returns them grouped and sorted into reading order. Each element in the returned `Vec>` is one line, containing the word bounding boxes for that line in left-to-right order. ### Usage ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("document.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; let line_rects = engine.find_text_lines(&ocr_input, &word_rects); println!("Found {} lines", line_rects.len()); for (i, line) in line_rects.iter().enumerate() { println!(" Line {}: {} words", i, line.len()); } ``` ``` -------------------------------- ### TextItem trait Source: https://context7.com/robertknight/ocrs/llms.txt A common interface for `TextLine` and `TextWord`, providing access to text content and bounding geometry. ```APIDOC ## `TextItem` trait — Common interface for `TextLine` and `TextWord` Implemented by both `TextLine` and `TextWord`. Provides access to the character sequence and bounding geometry (axis-aligned and oriented). ### Usage Example ```rust use ocrs::{TextItem, TextLine, TextChar}; use rten_imageproc::Rect; // Build a TextLine manually (e.g. for testing). let chars = vec![ TextChar { char: 'H', rect: Rect::from_tlhw(0, 0, 20, 10) }, TextChar { char: 'i', rect: Rect::from_tlhw(0, 10, 20, 6) }, TextChar { char: ' ', rect: Rect::from_tlhw(0, 16, 20, 5) }, TextChar { char: 'O', rect: Rect::from_tlhw(0, 21, 20, 12) }, ]; let line = TextLine::new(chars); // TextItem methods: println!("Text: {}", line); // "Hi O" println!("Bounding rect: {:?}", line.bounding_rect()); // axis-aligned Rect println!("Rotated rect: {:?}", line.rotated_rect()); // RotatedRect (oriented) // Iterate words within the line: for word in line.words() { println!(" Word '{}', rect: {:?}", word, word.bounding_rect()); } // Output: // Word 'Hi', rect: Rect { top: 0, left: 0, height: 20, width: 16 } // Word 'O', rect: Rect { top: 0, left: 21, height: 20, width: 12 } ``` ``` -------------------------------- ### OcrEngine::detect_text_pixels Source: https://context7.com/robertknight/ocrs/llms.txt Generates a low-level text probability map for each pixel in the image. This is useful for debugging detection quality or creating custom text masks. ```APIDOC ## `OcrEngine::detect_text_pixels` — Low-level text probability map Returns a 2D `NdTensor` of shape `(H, W)` where each value is the probability that the pixel belongs to a text word. Useful for debugging detection quality or creating visual masks. ### Usage Example ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("page.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let text_map = engine.detect_text_pixels(&ocr_input)?; let threshold = engine.detection_threshold(); // default ~0.2 // Binarize into a text mask. let text_mask = text_map.map(|&p| if p > threshold { 1.0f32 } else { 0.0 }); let [height, width] = text_map.shape(); println!("Text probability map: {}×{}, threshold={:.2}", width, height, threshold); ``` ``` -------------------------------- ### OcrEngine::detect_words Source: https://context7.com/robertknight/ocrs/llms.txt Executes the text detection model to identify oriented bounding rectangles for each detected word. Useful for obtaining raw word positions before layout analysis. ```APIDOC ## `OcrEngine::detect_words` — Detect text word bounding boxes ### Description Runs the text detection model and returns an unordered `Vec` of oriented bounding rectangles, one per detected word. Use this when you need raw word positions before layout grouping. ### Usage ```rust use ocrs::{ImageSource, OcrEngine, OcrEngineParams}; use rten::Model; let engine = OcrEngine::new(OcrEngineParams { detection_model: Some(Model::load_file("text-detection.rten")?), ..Default::default() })?; let img = image::open("screenshot.png")?.into_rgb8(); let img_source = ImageSource::from_bytes(img.as_raw(), img.dimensions())?; let ocr_input = engine.prepare_input(img_source)?; let word_rects = engine.detect_words(&ocr_input)?; println!("Detected {} words", word_rects.len()); for rect in &word_rects { let br = rect.bounding_rect(); println!(" word at ({}, {}) size {}×{}", br.left(), br.top(), br.width(), br.height()); } ``` ``` -------------------------------- ### Find Changed Crates with Cargo-Release Source: https://github.com/robertknight/ocrs/blob/main/docs/release.md Use `cargo release changes` to identify which crates have been modified since the last release. This command helps in determining the scope of the upcoming release. ```bash cargo release changes ```