EasyOCR vs Tesseract vs PaddleOCR vs RapidOCR, tested
EasyOCR does not beat Tesseract on clean printed pages. On 127 of them it came last, with 12,623 of 14,693 book words and 1,855 of 2,418 invoice numbers. Tesseract read 13,858 and 2,337. PaddleOCR beat Tesseract on both, with 14,076 words and every number. RapidOCR read 2,415 numbers in 0.6 seconds a page, but slightly fewer words, 13,744 against 13,858. Tesseract still uses the least memory and disk, but a tilt of more than about 2 degrees, or a shadow, breaks it unless you fix the image first. PaddleOCR and RapidOCR did not need that. If you want one default, use RapidOCR. All invoices and all damage here are made by code, so test your own pages too.
Try it on your PDF, $0.006 a page
That button is our own hosted tool, and it runs Tesseract, with the limits below. More on that.
Which one to use
- Want one default: RapidOCR. It read at least 2,370 of 2,418 numbers on every set, with no image fixes. It took 0.6 seconds a page on its default threads and 2.5 on one core.
- Every character matters and you can wait: PaddleOCR. It led every set on words, and it never fell below 2,411 numbers. It took 20.5 seconds a page on this Mac.
- A small server or clean scans: Tesseract. 40 MB on disk and 75 MB of memory, against 2.8 GB for RapidOCR. It also writes searchable PDF, hOCR and TSV, and it took 0.6 seconds a page on one core.
- EasyOCR: I would skip it for printed documents. It came last on 5 of 8 sets for words, and its last release is from September 2024.
Results on 8 kinds of page
Each cell is words right / numbers right. Words are out of 14,693 on 55 real printed book scans. Numbers are out of 2,418 on 72 made-up invoices.
| Your page | Tesseract | Tesseract, image fixed first | EasyOCR | RapidOCR | PaddleOCR |
|---|---|---|---|---|---|
| Clean scan | 13,858 / 2,337 | No fix needed | 12,623 / 1,855 | 13,744 / 2,415 | 14,076 / 2,418 |
| Tilted 7 degrees | 3,655 / 13 | 13,741 / 2,324 | 8,788 / 1,647 | 13,766 / 2,414 | 14,030 / 2,418 |
| Deep shadow, 35% light | 6,769 / 839 | 13,841 / 2,370 | 12,615 / 1,838 | 13,873 / 2,415 | 14,144 / 2,418 |
| Grainy scan | 13,817 / 2,079 | 13,857 / 2,366 | 12,634 / 1,762 | 13,885 / 2,412 | 14,008 / 2,418 |
| Phone style mix | 6,666 / 813 | 13,847 / 2,351 | 8,577 / 1,737 | 13,886 / 2,414 | 14,122 / 2,418 |
| White text on black | 13,861 / 2,345 | No fix needed | 12,599 / 1,945 | 13,934 / 2,415 | 14,076 / 2,418 |
| Low resolution, about 100 dpi | 13,763 / 2,225 | Not tested here | 11,517 / 1,281 | 14,002 / 2,404 | 14,089 / 2,418 |
| Very low resolution, about 75 dpi | 13,208 / 1,307 | Not tested here | 9,239 / 822 | 13,996 / 2,370 | 14,019 / 2,411 |
These are the same pages and the same scoring as my
image preprocessing test.
The two low resolution rows reuse the pages of my
DPI test. A word counts when it
appears in order with exact case. A number counts when the right row
holds the exact text. The third column is Tesseract after the deskew
and divide steps from that page. Tesseract ran with psm 3 and
--dpi 300, or the true dpi on low resolution pages.
EasyOCR and RapidOCR ran on their default settings. PaddleOCR ran with
three image helpers turned off, as the code below shows. I sorted the
boxes of all three into lines first (see below).
- Fixing the image first closes most of the gap for Tesseract on words. On numbers, it still stays behind RapidOCR and PaddleOCR: 13,847 / 2,351 on the phone style set, against 13,886 / 2,414 and 14,122 / 2,418.
- Tesseract's table setting helps less than you might hope. At psm 4, it read 2,349 of the same 2,418 numbers.
- At 72 dpi the invoices gave Tesseract 1,307 numbers, with 954 wrong. RapidOCR read 2,370. Scan at 300 dpi if you can.
- RapidOCR read the book pages better at a third of their size, 14,002 words against 13,744. I did not find out why, but it is worth a try on your own pages.
What each one costs
| Engine | Seconds a page, default threads | Seconds a page, one core | Peak memory | Disk | Last release |
|---|---|---|---|---|---|
| Tesseract 5.5.3 | 0.6 | 0.6 | 75 MB | 40 MB | Oct 28, 2026 (5.5.4) |
| EasyOCR 1.7.2 | 5.8 | 7.7 | 26.1 GB | 1.0 GB | Sep 24, 2024 |
| RapidOCR 3.10.0 | 0.6 | 2.5 | 2.8 GB | 290 MB | Oct 8, 2026 |
| PaddleOCR 3.7.0 | 20.5 | Not run | 18.5 GB | 984 MB | Jun 11, 2026 |
I ran 22 pages one at a time, on the CPU of a Mac with 18 cores and 128 GB of memory, with other jobs running beside mine. Disk is the install plus the model files. Peak memory is what one process reached across those 22 pages, on a machine with memory to spare. I did not test how low it can go on a small server. PaddleOCR used about one core on its default threads. I did not try its thread settings.
The first run of EasyOCR and PaddleOCR also downloads model files. RapidOCR's come inside the pip package. EasyOCR on this Mac's GPU took 1.4 seconds a page, so a GPU helps it a lot. That is still more than twice the time of RapidOCR on CPU.
Why EasyOCR lost
Here is where the 563 numbers it missed on clean invoices went. A dollar sign read as S is a plain misread. So is a cut number: in 180 of the 182, the front part is in no box to its left. A lost cell or row can be my line sort as much as EasyOCR.
| What happened | Numbers | Printed | Read as |
|---|---|---|---|
| Number cut short at a comma or a dot | 182 | $1,682.23 |
682.23 |
| Dollar sign read as a letter | 127 | $169.13 |
S169.13 |
| One digit cell not found in its row | 126 | 1 |
Nothing |
| Whole row lost | 27 | ||
| Other misreads | 101 | 1 |
11 |
On book pages it read a as &, opened
quotes as ((, and joined I told into
Itold. It gave 47 wrong numbers a confidence of 90% or
more on clean pages, so its score will not always warn you.
So I tried its own settings on every 6th page (22 pages, 2,729 words and 399 numbers):
| Setting | Words right | Numbers right | Numbers wrong |
|---|---|---|---|
| EasyOCR defaults | 2,397 | 261 | 117 |
mag_ratio=2 |
2,397 | 261 | 117 |
decoder="beamsearch" |
2,054 | 261 | 120 |
width_ths=1.0 |
2,392 | 257 | 116 |
width_ths=2.0 |
2,383 | 261 | 118 |
link_threshold=0.2 |
2,401 | 257 | 116 |
low_text=0.3 |
2,370 | 261 | 112 |
min_size=10 |
2,397 | 261 | 117 |
| Tesseract, for scale | 2,587 | 379 | 14 |
| RapidOCR, for scale | 2,564 | 399 | 0 |
| PaddleOCR, for scale | 2,623 | 399 | 0 |
No setting fixed it. None raised the numbers, the best one added 4 words, and the beam search decoder lost 343 words. mag_ratio=2 gave the same text as the defaults on all 22 pages, because these pages are already taller than EasyOCR's default canvas_size of 2560 pixels, so both shrink to the same size. min_size=10 changed the text on 2 pages and no score, and I stopped a min_size=5 run because it was too slow. On these 22 pages, RapidOCR and PaddleOCR, as set in the code below, read every number.
Boxes are not text
Tesseract gives you lines. The other three give you boxes. On book pages the order changed at most 15 words for RapidOCR and PaddleOCR. For EasyOCR on phone style pages, my line sort cost 1,905 words: in its own order it read 10,482, and the table shows 8,577. On invoices each cell is its own box, so the rows fall apart: RapidOCR in the order it returned read 20 numbers in the right row. Sorted into lines, the same output read 2,415. If your pages hold tables, you need this:
import math
import statistics
def to_lines(boxes, texts):
"""Sort OCR boxes into lines of text, top to bottom, left to right."""
tilts = []
for b in boxes:
(x0, y0), (x1, y1) = b[0], b[1]
if abs(x1 - x0) > 3 * abs(b[3][1] - y0):
tilts.append(math.atan2(y1 - y0, x1 - x0))
tilt = statistics.median(tilts) if tilts else 0
cos, sin = math.cos(tilt), math.sin(tilt)
items = []
for b, text in zip(boxes, texts):
x, y = sum(p[0] for p in b) / 4, sum(p[1] for p in b) / 4
items.append((y * cos - x * sin, x * cos + y * sin, math.dist(b[0], b[3]), text))
height = statistics.median(i[2] for i in items)
rows = []
for item in sorted(items, key=lambda i: i[0]):
if rows and item[0] - rows[-1][-1][0] < height / 2:
rows[-1].append(item)
else:
rows.append([item])
return [" ".join(i[3] for i in sorted(r, key=lambda i: i[1])) for r in rows]
It takes out the page tilt first. My first version used the height of each box on the page. On a tilted page that made one long line look many lines tall, so separate lines merged. Use the height along the side of the box, as here. It gave the same lines as my scorer on all 3,317 pages I compared.
The code for each
Each Python block ran as printed, on one of my pages.
Tesseract
brew install tesseract # or apt-get install tesseract-ocr
pip install pytesseract
import pytesseract
print(pytesseract.image_to_string("page.jpg", config="--dpi 300"))
RapidOCR
pip install rapidocr onnxruntime
from rapidocr import RapidOCR
engine = RapidOCR()
result = engine("page.jpg")
for box, text, conf in zip(result.boxes, result.txts, result.scores):
print(round(conf, 2), text)
With the helper above, in a file named lines.py:
from rapidocr import RapidOCR
from lines import to_lines
result = RapidOCR()("page.jpg")
print("\n".join(to_lines(result.boxes.tolist(), result.txts)))
PaddleOCR
pip install paddleocr paddlepaddle
from paddleocr import PaddleOCR
ocr = PaddleOCR(
lang="en",
use_doc_orientation_classify=False,
use_doc_unwarping=False,
use_textline_orientation=False,
)
page = ocr.predict("page.jpg")[0]
for text, conf in zip(page["rec_texts"], page["rec_scores"]):
print(round(float(conf), 2), text)
Those three flags turn off the page rotation check, the page unwarping and the text line rotation check. It took a model download on first run.
EasyOCR
pip install easyocr
import easyocr
reader = easyocr.Reader(["en"], gpu=False)
for box, text, conf in reader.readtext("page.jpg"):
print(round(conf, 2), text)
Test it on your own pages
My pages are not your pages. Type out one page into
page.txt, and count what an engine finds:
import difflib
from rapidocr import RapidOCR
from lines import to_lines
result = RapidOCR()("page.jpg")
text = " ".join(to_lines(result.boxes.tolist(), result.txts))
truth = open("page.txt").read().split()
match = difflib.SequenceMatcher(None, truth, text.split(), autojunk=False)
found = sum(b.size for b in match.get_matching_blocks())
print(f"{found} of {len(truth)} words")
Do not choose by confidence. Read Tesseract confidence score for why. If you stay with Tesseract, see how to improve Tesseract accuracy and tessdata_best vs fast. For a whole PDF, see PDF to Markdown in Python and scanned PDF to text.
If you do not want to build it
PDF OCR to Markdown is our Apify Actor. It runs Tesseract, not PaddleOCR or RapidOCR. A default run has 1 GB of memory and a quarter of a CPU core, and both of those used more than that here. It renders each scanned page at 300 dpi in gray, turns it upright, deskews up to 5 degrees and rebuilds tables, and on tables with lines it checks the math. It reads digital PDFs from their text layer, with no OCR. You paste links to PDFs or images and get Markdown back, with nothing to install.
- $0.006 a page, plus $0.00005 a run at the default 1 GB. Failed and blank pages are free.
- Links in a sheet? Use Bulk OCR from Google Sheets and CSV, $0.005 an OCR page.
- Pages are read inside the run. They are not sent to any AI service.
I did not run these tests on it, so no number above describes it. It has no shadow step, so if your pages are photos with shadows, try RapidOCR or PaddleOCR first.
What I did not test
- Real phone photos and real invoices. All 72 invoices are made up, and every shadow, tilt, fade and grain is mine, added by code. Only the 55 book pages and the 5 handwritten pages are real scans.
- NVIDIA GPUs. The one GPU run was EasyOCR on this Mac. I did not run PaddleOCR on Linux, or on any GPU.
- Any language but English. All four support more.
- Text in the wild, such as street signs and labels. I make no claim about those.
- Pages with two columns, dense forms, or curved pages.
- Settings for RapidOCR and PaddleOCR. EasyOCR got a settings test because it scored lowest. Tesseract's psm and image fixes come from my other tests, linked above.
- RapidOCR's larger models, PaddleOCR's layout and table models, and PaddleOCR-VL.
- Any machine but this Mac.
Questions people ask
Is EasyOCR better than Tesseract?
Not on clean printed pages. On 127 clean pages Tesseract read 13,858 of 14,693 book words and 2,337 of 2,418 invoice numbers. EasyOCR read 12,623 and 1,855. EasyOCR did hold up better than plain Tesseract on tilted, shadowed and phone style pages: at 7 degrees it kept 1,647 numbers, and Tesseract kept 13. PaddleOCR and RapidOCR beat both there.
Is PaddleOCR better than Tesseract?
On accuracy, yes, on every set I ran. It read all 2,418 numbers on clean pages, and 14,076 words against 13,858. The price is time and memory: 20.5 seconds a page on this Mac against 0.6, and 18.5 GB of memory against 75 MB.
Is EasyOCR faster than Tesseract?
No. On CPU, one page at a time, EasyOCR took 5.8 seconds a page and Tesseract took 0.6. On this Mac's GPU, EasyOCR took 1.4 seconds. RapidOCR took 0.6 on CPU.
What is RapidOCR?
RapidOCR runs PaddleOCR's text models on ONNX Runtime, so you do not install PaddlePaddle. In my run it used the small PP-OCRv6 models, and PaddleOCR used the medium ones. It read a little less here and ran much faster.
Does EasyOCR need a GPU?
No. With gpu=False it ran on CPU at 5.8 seconds a page. It prints a warning that a GPU is much faster. I tested one GPU, the one in this Mac, and it took 1.4 seconds a page.
Can any of these read handwriting?
Better than you might expect, on one neat hand. On 5 pages of one neat manuscript, of 929 words, PaddleOCR found 840, RapidOCR 747, Tesseract 452 and EasyOCR 271. That is one writer on 5 pages, so try your own.
How I tested: Tesseract 5.5.3 with its default English model, EasyOCR 1.7.2 with torch 2.15.0, RapidOCR 3.10.0 with onnxruntime 1.31.1, and PaddleOCR 3.7.0 with paddlepaddle 3.3.1, on Python 3.12 on an arm64 Mac. Book pages are 55 proofread Wikisource scans from 11 books. The 5 handwritten pages are from one neat manuscript in the same set. The invoices are drawn with their own slight tilt and a light blur, to look scanned. Low resolution book pages are shrunk copies. The scripts and their output are in our private repo. Sources, read October 31 and November 1, 2026: EasyOCR, RapidOCR, PaddleOCR, Tesseract, and the release dates on Tesseract's releases page and PyPI for EasyOCR and RapidOCR. We make the Apify Actors. The four engines and Wikisource are projects we do not make.