Skip to main content
Developer Guide

Tesseract OCR in Python
with pytesseract.

A complete, tested guide to pytesseract — installation, the core API, image preprocessing, PDFs, confidence scores, PSM/OEM configuration, performance and the errors people actually hit.

Quickstart (three lines)

Install the engine first, then run this. The full setup follows below.

ocr.py
import pytesseract
from PIL import Image

text = pytesseract.image_to_string(Image.open("image.png"))
print(text)

Install pytesseract

pytesseract is only a wrapper — it calls the Tesseract binary, so the engine must be installed first.

bash
pip install pytesseract pillow
# optional, for preprocessing:
pip install opencv-python numpy
# optional, for PDF input:
pip install pdf2image

If the engine is not on your PATH (common on Windows), point pytesseract at it explicitly:

python
import pytesseract
pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

New to the engine? See the installation guide for Windows, macOS, Linux, Docker and WSL.

Core API

pytesseract exposes one function per output type. Pick the one that matches what you need.

FunctionReturnsUse when
image_to_stringPlain textYou only need the recognised text
image_to_dataWord boxes + confidenceHighlighting text, filtering low-confidence words
image_to_boxesPer-character boxesCharacter-level geometry
image_to_pdf_or_hocrSearchable PDF or hOCRBuilding searchable PDFs or web overlays
image_to_osdOrientation and script detectionDetecting rotation or script before OCR
image_to_alto_xmlALTO XMLArchival / library pipelines
api.py
import pytesseract
from PIL import Image
from pytesseract import Output

img = Image.open("image.png")

text = pytesseract.image_to_string(img)                 # plain text
data = pytesseract.image_to_data(img, output_type=Output.DICT)  # boxes + conf
osd  = pytesseract.image_to_osd(img)                    # orientation / script
pdf  = pytesseract.image_to_pdf_or_hocr(img, extension="pdf")   # searchable PDF

Configuration: PSM, OEM, languages and whitelisting

Pass options as a space-separated string to config=.

config.py
# Single block of text, LSTM engine, English
text = pytesseract.image_to_string(img, lang="eng", config="--oem 3 --psm 6")

# Digits only (receipt totals, meter readings)
text = pytesseract.image_to_string(img, config="--psm 7 -c tessedit_char_whitelist=0123456789.")

# Mixed languages
text = pytesseract.image_to_string(img, lang="eng+fra")
PSMModeBest for
3Fully automatic (default)Standard documents
4Single column of variable sizesArticles, single-column pages
6Single uniform block of textParagraphs, labels
7Single text lineOne-line captions, single fields
8Single wordIndividual words
11Sparse textReceipts, scattered UI text
13Raw lineSingle line without Tesseract hacks

OEM modes: --oem 1 (LSTM only, default in v5), --oem 0 (legacy), --oem 3 (default/auto). Full reference in the documentation.

Image preprocessing

Clean input is the single biggest factor in accuracy. These are the steps that matter most.

preprocess.py
import cv2, numpy as np, pytesseract
from PIL import Image

image = cv2.imread("receipt.jpg")
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# Upscale small text to ~300 DPI equivalent
gray = cv2.resize(gray, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)

# Denoise, then Otsu threshold to pure black/white
blur = cv2.GaussianBlur(gray, (5, 5), 0)
_, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

text = pytesseract.image_to_string(Image.fromarray(binary))

Word positions and confidence scores

Use image_to_data to get per-word boxes and a 0–100 confidence score, then filter noise.

confidence.py
from pytesseract import Output

data = pytesseract.image_to_data(img, output_type=Output.DICT)
for text, conf in zip(data["text"], data["conf"]):
    if text.strip() and float(conf) > 60:   # drop low-confidence noise
        print(round(float(conf)), text)

OCR a PDF in Python

Tesseract takes images, so rasterise PDF pages first with pdf2image (which needs the poppler tools).

pdf.py
import io, pytesseract
from pdf2image import convert_from_path
from pypdf import PdfWriter, PdfReader

pages = convert_from_path("scan.pdf", dpi=300)   # needs poppler
writer = PdfWriter()
for page in pages:
    pdf_bytes = pytesseract.image_to_pdf_or_hocr(page, extension="pdf")
    writer.add_page(PdfReader(io.BytesIO(pdf_bytes)).pages[0])
with open("scan_searchable.pdf", "wb") as f:
    writer.write(f)

On Windows, pass the poppler bin folder via poppler_path=. For a deeper workflow (OCRmyPDF, layout fidelity, large files), see the documentation on output formats.

Performance

pytesseract shells out to the CLI for every call, so throughput depends on how you structure it.

ApproachWhenTrade-off
pytesseract per callScripts and one-off jobsSpawns a process each call — slow in loops
Batch into multi-page TIFFMany pages, same settingsOne process for many pages
multiprocessingMany independent imagesUses all CPU cores; more memory
tesserocrHigh-volume, in-processNative binding, more setup

Error catalog

The errors below account for most pytesseract problems.

ErrorCauseFix
TesseractNotFoundErrorBinary not installed or not on PATHInstall the engine or set pytesseract.pytesseract.tesseract_cmd.
(-215:Assertion failed) src.type() == CV_8UC1Thresholding a 3-channel imageConvert with cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) first.
Error opening data file ...fra.traineddataLanguage pack missingInstall the language package or set TESSDATA_PREFIX.
Empty outputLow DPI, wrong PSM, or no textUpscale, try --psm 6/7/11, preprocess.
Very slow in a loopOne process per callBatch, use multiprocessing, or tesserocr.

Test and measure accuracy

Measure character and word error rates instead of eyeballing output.

eval.py
import pytesseract, jiwer
from PIL import Image

hypothesis = pytesseract.image_to_string(Image.open("sample.png"))
reference  = open("sample.gt.txt").read()

print("CER:", jiwer.cer(reference, hypothesis))
print("WER:", jiwer.wer(reference, hypothesis))

Keep a small set of representative images with ground-truth text as regression fixtures, and re-run when you change preprocessing or config.

Python FAQ

How do I use Tesseract OCR in Python?

Install the Tesseract engine first, then pip install pytesseract pillow. Open the image with Pillow and call pytesseract.image_to_string(img).

Why do I get TesseractNotFoundError?

pytesseract cannot find the tesseract binary. Install the engine, put it on the PATH, or set pytesseract.pytesseract.tesseract_cmd to the full path.

How do I improve accuracy?

Upscale to ~300 DPI, grayscale, threshold, denoise, deskew, and set the right --psm. Use the correct lang= and, for fixed fields, a character whitelist.

How do I OCR a PDF?

Use pdf2image (with poppler) to convert pages to images, run pytesseract on each, and merge with image_to_pdf_or_hocr(..., extension="pdf").

How do I get confidence scores?

Use image_to_data(..., output_type=Output.DICT) and filter on the conf list.

Is pytesseract slow?

Each call spawns a process. Batch, use multiprocessing, or switch to the in-process tesserocr binding for high throughput.

Go deeper on the engine and the ecosystem.