← all posts
// ocr · ocr-models

OCR models for forms and handwriting: choosing an OCR-capable model

A scanned intake form is rarely a clean, high-resolution capture. It's a phone photo taken sideways, or a fax faxed again, and whatever recognizer you pick has to eat that image as it arrives. That fact decides more of this project than the model.

Three kinds of tooling get thrown at this. A classical OCR engine turns pixels into characters. A layout parser decides which characters belong together and in what order. A vision-language model reasons about the page, guessing a value belongs to a label two lines up when the grid breaks. All three earn a place; none replaces the other two.

Here's the trap: a VLM is also a language model, trained to keep a sentence going in whatever direction sounds right. Feed it a smudged surname or a torn part number, and it hands back something plausible instead of admitting it can't read the mark. Plausible is worse than wrong, nobody checks it twice.

what the page is actually asking for

Forms and handwriting are their own category: applications, surveys, checklists, delivery slips, anything with a note added onto a printed template. You're pulling out printed labels, marked choices, handwriting, a signature standing in for presence, and the field-to-value link.

  • crossed-out answers
  • characters touching each other
  • pencil so faint it barely registers
  • check marks and boxes that may or may not be filled in
  • notes written outside the region anyone designed for

The design constraint is a matching problem: script, layout, handwriting style, resolution, output structure, deployment. I start with the boring stack, template registration, region cropping, printed OCR, a separate handwriting recognizer, and bring in a generative model only where it earns its place: rough handwriting, unstable layouts, a distant label-value pair, or triage.

Settle this without guessing: the same labeled pages through a classical engine, a layout parser, and a VLM, scored against one gate.

the trust problem sits after the crop

The scary failure isn't garbage output, that's easy to spot. It's a legible handwritten value attached to the wrong field, or a mark the model insists is there and isn't. Neither looks broken, so picking a model off a general vision benchmark is a mistake: benchmarks reward plausible answers, not exact transcription.

Build an abstention path on purpose. Low-resolution regions, clipped pages, glare, unreadable handwriting, totals that don't add up: all of that should raise an exception, not a guess. Confidence scores alone aren't enough, model-specific and often miscalibrated. Pair them with image-quality checks, format validators, cross-field arithmetic, a dictionary, and disagreement between passes.

Give reviewers something better than the raw page: store the bounding polygon for every field that matters, show the crop beside the proposed value. Review becomes verification, not retyping. Skip the coordinates and you're hunting the whole page instead.

Error rate calls a missing comma and a wrong account number the same size of mistake. Add exact-match scoring for identifiers, dates, amounts, units, and score field association and table geometry on their own.

A log entry worth keeping looks something like this:

page_id, source_hash, capture_device
crop / dewarp / denoise version
model + runtime revision
raw text, region, order, confidence
normalized value vs. what was seen

Never let the normalized field overwrite what the recognizer saw. An O that might be a zero, a 1 that might be an I: keep both, always.

once there's more than one page

Multi-page documents add a mistake that has nothing to do with character recognition. Page order and repeated headers need to survive intact. Don't hand a model an arbitrary bundle of scans and trust it to keep invoices from blurring together. Split documents deterministically, attach identifiers, state whether a table continues across a page boundary.

Anything a VLM produces from a document's own text is a proposal, not an instruction. A database write goes through schema validation outside the model, full stop. Text printed on a form is data, not a channel for changing what extraction is allowed to do.

Version everything together: model, preprocessing, dictionaries, schema, validation. When one changes, replay a stratified set: clean pages, ordinary noise, tricky layouts, fields that matter, pages already known to be hopeless.

Deployment is a cost question in technical clothing. Local keeps documents under your control and gets cheap at steady, high volume, but storage, memory, accelerator time, and maintenance are on you. A hosted API buys elasticity and a higher ceiling for weird pages, at the cost of retention, residency, and a bill that scales with volume. Hybrid routing earns its keep when privacy is strict and escalation stays visible.

What I still don't have a clean answer for: the VLM that explains a mismatched total in a paragraph reading perfectly reasonable and wrong. Abstention fires on low confidence, not on a wrong explanation delivered confidently. I haven't found a validator that catches "sounds right" the way it catches "doesn't add up."

#ocr-models#document-ai#vision