OCR Accuracy: Why Numbers Come Out Wrong

Updated 2026-09-05

SwipeScan does this from your phone camera — swipe over the number, it lands on the clipboard.

There is one answer underneath most of this, and it is not that the software is bad.

Text recognition works in two stages. A classifier produces candidate shapes with confidence scores; a language model then picks between them using context, which is why a smudged app1e comes back as “apple”. That second stage does an enormous amount of the work, and you never see it happening.

Digits have no second stage. In a serial that reads 4B7291, nothing makes 7 more plausible than 1 — no dictionary, no letter-frequency prior, no word to complete. The classifier output goes into your result uncorrected, and unlike a misspelled word, a misread digit looks exactly as valid as the right one.

Length multiplies the risk

Accuracy is quoted per character, which hides what happens to a whole number. If the character error rate is CER, the probability that an N-character string is entirely correct is (1 − CER)^N — every character has to survive independently, so the odds fall away as the string gets longer.

CER15 digits (IMEI)17 chars (VIN)19 digits
0.1%98.5%98.3%98.1%
1%86.0%84.3%82.6%
2%73.9%70.9%68.1%
5%46.3%41.8%37.7%

Read down a column and watch the same identifier come apart. The top row is a clean scan of printed text, and at that quality nothing here is a problem. But 1% CER, which most people would call accurate, already means roughly one long number in six is wrong. At 5% — an etched SIM tray, a fogged meter glass, a photograph of a screen — you are closer to a coin flip than a reading.

Nothing in the output tells you which ones failed. Prose absorbs this because words carry redundancy; a number carries none. That is the whole argument for checksums.

The shapes that collide

DigitCommonly confused withWorst in
0O, D, QAny face without a slashed zero
1l, I, 7Sans-serif faces where 1 is a plain vertical stroke
5SLow resolution, condensed type
8B, 3, 6Blurred or compressed images
6G, bHandwriting
2ZHandwriting, and stamped metal
9g, q, 4Small type with tight line spacing

Some typefaces make these pairs genuinely identical: in several sans-serif faces a lowercase l and the digit 1 are the same glyph, and no processing recovers a distinction that was never in the pixels. Good identifier schemes design the problem away — a VIN excludes I, O and Q from all seventeen positions for exactly this reason, so reading one proves an error occurred.

Seven-segment displays are a separate problem

Meters, clocks, scales, fuel pumps. These are not printed text, and general recognisers are not trained on them.

A seven-segment digit is a set of bars with visible gaps between them, and that gap is the difficulty. Many pipelines segment characters by finding connected regions of ink, and a seven-segment digit is not connected — it is up to seven separate blobs that a human brain assembles and a connected-component pass splits apart. A 1 is two short vertical bars at the right edge of an otherwise empty cell, which a classifier trained on printed type may discard as noise. An 8 differs from a 0 by one horizontal bar.

Tesseract needs separately trained data for these displays; the community maintains dedicated seven-segment training sets precisely because the default behaviour is poor. LCD panels add another problem: segment contrast falls off with viewing angle, so a display legible straight on can wash out photographed from the side.

This is why meter readings misfire so consistently. Reading an electric meter from a photo covers the trap of digits that must be excluded, and reading a water meter the same problem with red-background fractions among the whole units.

Too few pixels

This causes more errors than glyph confusion, and it is the easiest thing to fix.

Recognition engines are tuned for a specific scale. Tesseract’s guidance is around 300 dpi, putting lowercase letter height at roughly twenty pixels for 10pt text. Below about ten pixels there is very little chance of an accurate result, and below eight most text is stripped as noise before recognition begins — the engine does not misread it, it never sees it.

The consequence people miss: enlarging the image afterwards does nothing. Upscaling invents pixels, it does not recover information. If the digits were fifteen pixels tall when you pressed the shutter, they carry fifteen pixels of information no matter what size the file becomes, and no filter, sharpening pass or model recovers detail that was never sampled.

Check this before blaming the software. A phone screenshot viewed on a laptop at half size and re-captured can land under ten pixels of character height without looking small on screen, as can a photograph taken across a room and cropped afterwards. The fix happens at capture: move closer, zoom before you screenshot, crop in the viewfinder rather than an editor.

Four smaller causes

  • Compression. JPEG blocking artifacts cluster on high-contrast edges, exactly where digit strokes live. A paused video frame is the usual offender.
  • Contrast. Etched metal, dark-mode interfaces, grey-on-grey. Light engraved surfaces obliquely so grooves cast shadows rather than lighting flat.
  • Skew. Shot at an angle, a rectangular digit becomes a trapezoid. Engines correct rotation far better than perspective.
  • Segmentation. Touching digits read as one, or a wide digit splits in two. This changes the count of digits rather than their values, which makes it the easiest error class to catch automatically.

What actually fixes it

In order of effect:

  1. More pixels at capture time. Everything else is a rounding error next to this.
  2. Crop to only the digits, so labels, units and currency symbols cannot be mistaken for characters.
  3. Restrict the character set. An engine told to expect only digits cannot return an O — what our number extraction tool does, removing a category of error rather than reducing it.
  4. Verify with a check digit.

That last step is the only one that converts a probability into a yes or no.

An IMEI’s fifteenth digit is a Luhn checksum, catching every single-digit error and every adjacent transposition except swapping 0 and 9. A VIN’s ninth character is a mod-11 check digit that can be X.

An IBAN validates by moving the first four characters to the end, converting each letter to a number, and checking that the resulting integer leaves a remainder of 1 when divided by 97.

Those three are the trustworthy cases, and the tools for them run the check rather than leaving it to you: IMEI from a photo, VIN from a photo and IBAN from a photo. A checksum does not make that 86% better — it makes the missing 14% visible instead of silent, which is the part that matters.

Meter readings, serial numbers and MAC addresses have no check digit. Nothing validates them, so the compounding above applies in full and you must read the result back against the image yourself. That is why the number extraction tool puts digits in an editable field, and why a meter reading should always be compared against last month’s figure — the only control those numbers have. Where format rules exist, use them: phone numbers cap at 15 digits under E.164, covered in pulling phone numbers out of a photo. One rule is not about recognition at all — the same string can be two different quantities depending on the locale that reads it, which is the decimal separator problem.

The short version

  • Digits have no dictionary, so the language model that rescues misread words contributes nothing.
  • Accuracy compounds as (1 − CER)^N: at a 1% character error rate, a 19-digit number is fully correct only 82.6% of the time.
  • 0/O, 1/l, 5/S and 8/B collide, and in some typefaces 1 and l are literally the same glyph.
  • Seven-segment displays are disconnected bars, not a typeface, and need a separately trained model.
  • Aim for twenty pixels of character height, validate with a checksum where one exists, and read the result back yourself where none does.

Questions

Why is OCR accurate on words but wrong on numbers?

Words have a dictionary behind them. When the shape recogniser is unsure, a language model picks the plausible word. Digits have no such context — every value is equally likely, so a bad shape guess goes straight into the output.

How accurate is OCR on a long number?

Less than the per-character figure suggests. Accuracy compounds: at a 1% character error rate, a 19-digit number comes out fully correct only 82.6% of the time, because every single character has to survive.

Why can't OCR read my meter or clock display?

Seven-segment displays are not a typeface. General engines are trained on printed and handwritten text, and need a separately trained model to handle segmented digits at all.

Try the tool this guide is about

It runs in your browser — nothing uploaded, no account. The app adds the camera, offline use, and a paid scan history.

Related guides