Advance Guide

Spatial Layout Reconstruction

How RustO! reconstructs human-readable 2D spatial layouts for multi-column tables, invoices, receipts, and forms.

Standard OCR engines return a flat list of disconnected bounding boxes, losing table structures, column gaps, and line indentations.

RustO! includes a built-in Spatial Layout Reconstruction Engine that analyzes 2D geometric relationships to produce formatted, visually aligned text.

🎯 How the Algorithm Works

Rendering diagram...

Visual Comparison: Output Modes

Consider a standard retail invoice with two item rows and two columns:

1. Flat Line List (output: "lines")

Item Description
Amount
Coffee Latte
$4.50
Croissant
$3.50
Total
$8.00

(Notice how column relationships are flattened into a single vertical sequence).

2. Reconstructed Spatial Text (output: "spatial")

Item Description                       Amount
Coffee Latte                            $4.50
Croissant                               $3.50
─────────────────────────────────────────────
Total                                   $8.00

(Column headers, tabular items, and total rows remain aligned in their original 2D positions).


βš™οΈ Tuning Spatial Parameters

Spatial reconstruction is controlled at runtime via OcrRunOptions:

let options = OcrRunOptions {
    output: OutputGranularity::Spatial,
    line_y_threshold: Some(0.5), // Vertical row clustering tolerance
    word_x_threshold: Some(0.4), // Horizontal word & column spacing tolerance
    ..Default::default()
};

Parameter Guidelines

ParameterDefaultWhen to IncreaseWhen to Decrease
lineYThreshold0.5Increase (0.7 - 0.9) if slightly wavy, handheld, or skewed receipt lines get fragmented into multiple lines.Decrease (0.2 - 0.35) for dense spreadsheets or multi-line tables where rows are packed tightly together.
wordXThreshold0.4Increase (0.6 - 0.8) to merge spaced words across wider gaps into single phrases.Decrease (0.2 - 0.3) to preserve distinct column boundaries in tightly aligned data tables.

πŸ’‘ Practical Examples by Platform

Rust

let spatial_text = match ocr.detect_text(&image_source, &OcrRunOptions {
    output: OutputGranularity::Spatial,
    line_y_threshold: Some(0.5),
    word_x_threshold: Some(0.4),
    ..Default::default()
})? {
    DetectTextResult::Spatial(text) => text,
    _ => unreachable!(),
};
println!("{spatial_text}");

React Native

const formattedLayout = await detectText(
  { uri: 'file:///path/to/invoice.jpg' },
  {
    output: 'spatial',
    lineYThreshold: 0.5,
    wordXThreshold: 0.4,
  }
);
console.log(formattedLayout);