Kiliyo Sign in

OCR · Evaluation · 30 September 2026

How to choose an OCR engine for your documents

We ran five open-source OCR engines on 25 kinds of difficult page. None was best at everything, all of them made the same mistake on look-alike codes, and one cheap preprocessing step took a table from 18% to 100%. Here is what we measured, and how to run the same test on your own pages.

Most teams choose an OCR engine from a demo, a leaderboard, or whatever their cloud provider offers. Then the real documents arrive: a crooked scan, a phone photo of a form, a table of figures saved as a low-quality JPEG. The engine that looked perfect in the demo now misreads an amount, drops a line, or confidently returns text that is not on the page. Usually nobody notices until the number is already in a database.

The problemOCR engines fail in different ways on different pages, and one accuracy figure hides which failure you are buying: a digit misread, a word left out, a word invented, or two columns read as one.
What goes inPage images or PDFs, and the correct text for each page. For our test: 25 pages drawn from known text, each damaged in one realistic way, and five engines running locally.
What comes outFor every engine and every page: which words were matched, misread, missing or invented; whether the key values (amounts, dates, IDs, names) came out exactly right; seconds per page; and a route for each page.

What we tested

We drew 25 pages from text we wrote ourselves, so the correct answer is known to the character. Each page reproduces one way documents arrive in real life. The letters, forms and tables are fictional: a harbour authority's tariff letter, a vessel arrival form, a statement of operations.

Contact sheet of the 25 test pages: clean and damaged letters, tables, forms, a phone photo, a yellowed page, rotated pages, a handwritten form, a watermarked letter and a blank page.
The 25 test pages. Each is damaged in exactly one way, so a failure can be traced to its cause.
  • Text layer: a born-digital PDF, and a PDF whose hidden text layer is garbled
  • Scan quality: clean 300 dpi, 150 dpi, 100 dpi, out of focus, heavy JPEG, noisy photocopy, faded print, phone photo, yellowed paper with show-through
  • Geometry: crooked by 4 degrees, sideways, upside down
  • Layout: two columns, a ruled financial table, the same table without rules
  • Content: 6–7 pt footnotes, look-alike codes, a form filled in by hand, five European languages, a DRAFT watermark, white-on-dark text, words cut off at the page edge, a blank page with specks

The engines are all free and ran on one laptop, CPU only: Tesseract 5, RapidOCR (PaddleOCR's models on ONNX Runtime), PaddleOCR 3 and Docling from IBM, plus the PDF's own text layer where one exists. Tesseract and RapidOCR also ran a second time with automatic preprocessing (rotate, deskew, upscale, flatten the background, remove table rules), shown as + prep.

How we scored

Every word of the correct text lands in exactly one bucket, and every extra word the engine produces is counted too.

matchedRead exactly right.
misreadRead, but wrong: 23,540 became 123,540.
missingOn the page, not in the output.
inventedIn the output, not on the page.

We also track key values separately: the amounts, dates, reference numbers and names that a business process depends on. A page can be 98% right and still wrong in the one number that matters, so key values are what we rank by.

The results

EngineKey values rightWords rightMisreadMissingInventedSeconds / page
PDF text layer (2 of 25 pages)50.0%50.3%0.7%49.0%47.9%0.00
Tesseract70.4%88.3%3.4%8.3%4.7%0.95
Tesseract + prep92.6%97.7%1.7%0.7%0.7%0.81
RapidOCR96.2%97.9%1.1%1.0%1.6%2.37
RapidOCR + prep96.2%98.1%0.8%1.1%3.2%2.31
PaddleOCR94.8%93.2%1.8%4.9%1.2%65.95
Docling95.3%94.9%1.4%3.6%2.6%20.04

All 25 pages. Misread, missing and invented are shares of the words on the page. The PDF text layer only applies to the 2 pages that have one: it is perfect on one and useless on the other. Times are per page on a laptop CPU, after models are loaded.

On the averages, RapidOCR gets the most key values right (96.2%) at 2.3 seconds a page. Plain Tesseract comes last (70.4%), but with preprocessing it rises to 92.6% and is still the fastest engine at 0.8 seconds. PaddleOCR and Docling are close on accuracy but much slower on a CPU: 66 and 20 seconds a page. The averages hide the most useful part, though. Here is every page:

ScenarioPDF text layerTesseractTesseract + prepRapidOCRRapidOCR + prepPaddleOCRDocling
Born-digital PDF100%100%100%100%100%100%92%
PDF with a broken text layer0%100%100%100%100%100%92%
Clean 300 dpi scann/a100%100%100%100%100%92%
Low-resolution scan (150 dpi)n/a94%100%100%100%100%100%
Very low resolution (100 dpi)n/a92%92%100%100%92%92%
Out-of-focus scann/a92%92%100%100%100%100%
Heavily compressed JPEGn/a22%100%100%100%100%96%
Crooked scan (4 degrees)n/a100%100%100%100%100%100%
Page scanned sideways (90 degrees)n/a100%100%85%100%100%100%
Page scanned upside downn/a0%100%78%100%0%78%
Noisy photocopyn/a55%55%73%73%73%73%
Faded, low-contrast printn/a100%100%100%77%100%100%
Phone photo of a formn/a82%100%100%91%100%100%
Yellowed paper with show-throughn/a100%100%100%89%67%100%
Two-column layoutn/a100%100%100%100%100%89%
Financial table with rulesn/a18%100%100%100%100%100%
Borderless financial tablen/a100%100%100%100%100%98%
Small print and footnotes (6-7 pt)n/a100%100%100%100%100%100%
Codes, IDs and look-alike charactersn/a70%70%65%65%85%85%
Form filled in by handn/a0%55%82%91%82%91%
Accented and Nordic charactersn/a20%20%100%100%100%100%
DRAFT watermark and a stampn/a81%81%94%94%88%81%
White-on-dark and shaded textn/a100%100%100%100%100%93%
Words cut off at the page edgen/a100%100%100%100%100%100%
Blank page with scanner specksn/a3 inventedcleancleanclean6 inventedclean
98% or more of key values right90–98%70–90%below 70%

What we learned

1. Don't OCR a page that already contains its text

A PDF exported from Word or InDesign already holds its text. Reading it took 0.005 seconds and was 100% correct. OCR on the same page took between 0.8 and 66 seconds and could only add errors. The text layer can also lie, though. Our second PDF looks identical on screen, yet its hidden text is garbage, as happens with a broken font encoding or a failed old OCR pass. Trusting it scores 0.7%. A quick check of whether the text looks like words catches it. So the first step of any pipeline is triage, not OCR.

2. A cheap fix beat a bigger model on tables

Plain Tesseract got 18% of the figures right on our ruled financial table, and 22% on the JPEG copy of it. The same table without ruling lines scored 100%. The rules break Tesseract's line finding, and it returns fragments like Totareveue—SSS. Painting long straight lines white before OCR, a few lines of OpenCV, took it to 100% on both. The heavier engines coped with rules on their own, but at 3 to 80 times the time per page.

3. Preprocessing has to be decided per page

The same preprocessing that fixed tables made other pages worse. Contrast stretching cost RapidOCR 23 points of key values on the faded page, and despeckling cost Tesseract on the photocopy. Upscaling the 150 dpi table on its own made Tesseract worse, until the rules were removed too. Fixes should follow from what triage finds on each page, not be applied to everything.

4. Every engine read the look-alike codes the same wrong way

Printed reference codes such as part number 0O1l-7B8-IS5, serial SN-8B0O-lI15 and batch Q0-2026-O8.
Part numbers that mix the letter O with zero, and a lowercase L with one.

All six configurations turned 0O1l-7B8-IS5 into 0011-7B8-IS5, and Q0-2026-O8 into Q0-2026-08. Tesseract also dropped the subscript in HCO3 and the × sign. No engine fixes this on its own, because in many fonts those characters really are ambiguous. The fix sits outside OCR: validate codes against their format (check digits, known prefixes, a lookup in your own records) and send failures to a person.

5. Noise turns into digits

On the noisy photocopy, no engine got more than 73% of key values. The worst errors are the plausible ones. Tesseract read a gross tonnage of 23,540 as 123,540, because a speck became a 1, and a length of 187.4 as 167.4. Both pass any "is this a number?" check. Only a business rule, such as a cross-check against another field, or a person would catch them.

6. Handwriting and accents split the field

A printed vessel arrival form with the answers written in blue handwriting.
The handwritten form. Plain Tesseract got none of the answers exactly right; RapidOCR with preprocessing got 91%.

On the handwritten form, plain Tesseract got none of the answers exactly right: it read MARIS AURORA as SMARTS AURORA and 23,540 as 23500. RapidOCR and Docling got 82 to 91%, with errors like 03/04/2026 read as 03104/2026. On the five-language page, Tesseract with its default English model turned Þórður into bordur and Gebühren into Gebthren, getting 20% of the key words. The other three engines got every accented word right. Tesseract does better with the right language packs installed, and that is exactly the kind of detail a demo never shows.

7. Engines miss what the document is, not just what it says

Our watermarked letter carries a large diagonal "DRAFT – NOT FOR EXECUTION". Tesseract, PaddleOCR and Docling returned the letter and left the watermark out entirely. RapidOCR caught the word DRAFT but not the rest. For a contract or a claim, that watermark decides whether the document can be acted on at all. If document status matters in your process, check for it separately.

8. Some engines find text on blank pages

On a blank separator page with scanner dust, Tesseract returned 3 words and PaddleOCR 6. Triage recognised the blank page and skipped it, which is why the + prep version got it right. One result was reassuring: on words cut off at the page edge (REQUISITION NUMBE), none of these engines "completed" the word. General-purpose AI models are more tempted to, which is why the test is there.

9. Speed is a design decision

At 0.8 seconds a page, Tesseract with preprocessing gets through 10,000 pages in about two and a quarter hours on one laptop. PaddleOCR with default settings on the same CPU would need about a week. A GPU and tuned settings change that a lot, but the point stands: the engine you choose sets your hardware bill, and the cheapest setup sends each page to the lightest engine that handles it.

The pattern behind all of this: there is no single best OCR engine, only a best route for each kind of page. Read the text layer when it is good, skip blank pages, fix the pages that need fixing, send easy pages to a fast engine and hard ones to a stronger engine or a person, and check the values that matter against rules.

Run the same test on your documents

Our pages are synthetic on purpose, so every error can be traced to its cause. They show how engines fail. Only your own pages show how often. The tool we built for this post, ocr-bakeoff, runs on your own computer. Nothing is uploaded unless you add a cloud engine yourself.

You haveYou give itYou get
Scans, and the correct text for some of themThe scans, plus a .txt file with the correct text for each of 20 to 50 pagesAccuracy per engine and per page, key values, every error, speed
Born-digital PDFsThe PDFs. Their own text becomes the answer key, and the tool OCRs damaged copies: office scan, fax, phone photo, crooked, fadedHow each engine would cope if these documents arrived as scans
Scans only, no correct textThe scansTriage for every page, and how far the engines agree with each other
pip install -r requirements.txt
python -m ocrbakeoff demo --open           # the 25 pages from this post
python -m ocrbakeoff serve                 # the same, from a web page
python -m ocrbakeoff run my-scans/ --truth my-truth/ --open

The output is one HTML report plus results.json, results.csv and every engine's raw text, so you can check any number yourself.

We are preparing the code for public release. Until then, email us and we will send it to you.

Limits of this test

  • One page per scenario. It shows how each engine fails, not how often. Your own sample tells you that.
  • The handwriting is a handwriting-style font, which is easier than real handwriting.
  • We used default settings. Every engine can be tuned, and tuning is part of choosing one.
  • Timings are for one laptop CPU. Compare engines within this run, not against other benchmarks.
  • This measures words and values, not table structure (which cell a number belongs to). That needs a different check, which we will cover in a later post.
  • We did not include commercial cloud engines or large vision-language models. The tool supports them, and we will add them in a follow-up.

Have this problem at volume?

Send us 20 of your pages. We'll tell you which engine fits, and what it would cost.

We run the bake-off on a sample of your documents, label the correct text, and send back the report: which engine or route fits your pages, what it gets wrong, where a person still needs to look, and the cost per 1,000 pages. Your files stay on our own server and are deleted afterwards.

hk24@kiliyo.com Email us