mrkeyoor.com_
Wed 05 Aug 19:57 UTC
PyPIAI / MLupdated 05 Aug 2026

pytesseract

pytesseract is a thin Python wrapper around Google's Tesseract OCR engine. It does not contain any OCR code itself: each call shells out to the tesseract binary installed on your system and parses what comes back. Through it you get image_to_string for plain text, image_to_data for a TSV of words with bounding boxes and confidence scores, image_to_boxes for character boxes, image_to_osd for orientation and script detection, and searchable PDF, hOCR, or ALTO XML output. It accepts PIL images, numpy arrays, or file paths, and reads any of the 100+ languages Tesseract has traineddata for.

Verdict

The path of least resistance to Tesseract from Python and fine for clean scanned documents, but it is a subprocess wrapper around a 20-year-old engine: for photos, handwriting, or volume work, start with a modern OCR library instead.

API stability5/5The 0.3.x line has been current since 2019 and image_to_string has looked the same for a decade; nothing here breaks between releases.
Docs3/5One long README with good examples and no docs site; the parameters that actually determine output quality (psm, oem, tessedit variables) are documented in Tesseract's manual, not the wrapper's.
Maintenance4/5Steadily maintained by a small team with a July 2026 push and about 21 open issues and PRs; the scope is tiny, which keeps it healthy, but releases are infrequent.
Ecosystem4/5Plays directly with Pillow, OpenCV, and numpy, and inherits Tesseract's huge traineddata ecosystem; it is the default OCR answer in countless tutorials and pipelines.

Use it if

  • You are OCRing clean printed or scanned documents and want a permissive Apache-licensed stack that runs on CPU anywhere Tesseract installs
  • You need word-level bounding boxes and confidence scores (image_to_data) for downstream layout logic or redaction
  • You want searchable PDFs or hOCR output straight from images with one function call
  • You need one of Tesseract's 100+ language packs, including scripts the deep learning OCR projects cover poorly
Skip it if

Setup reality

pip install pytesseract is the easy half; the OCR engine is a system dependency you install separately (apt install tesseract-ocr on Debian/Ubuntu, brew install tesseract on macOS, a community installer on Windows), plus per-language packs like tesseract-ocr-deu. On Windows you almost always have to point pytesseract.pytesseract.tesseract_cmd at the exe path because it is not on PATH. Docker images must bake the binary in. Pillow is required for image handling, and real quality tuning happens through Tesseract's cryptic --psm and --oem config strings, which are documented in Tesseract's own manual, not here.

Patterns

OCR an image to plain textimage-to-text

from PIL import Image
import pytesseract

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

Passing a file path string instead of a PIL image skips pytesseract's conversion, but then the file must be a format Tesseract itself supports.

Point at the tesseract binary (Windows and custom installs)set-binary-path

import pytesseract

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

print(pytesseract.get_tesseract_version())

TesseractNotFoundError almost always means this line is missing. get_tesseract_version() is the quickest sanity check that wiring works.

OCR non-English textother-languages

from PIL import Image
import pytesseract

print(pytesseract.get_languages(config=""))  # what is installed

text = pytesseract.image_to_string(Image.open("brief.png"), lang="deu")
mixed = pytesseract.image_to_string(Image.open("menu.png"), lang="eng+fra")

Each language needs its traineddata pack installed on the system (e.g. apt install tesseract-ocr-deu); lang="eng+fra" runs multiple languages at once but slows recognition.

Tune page segmentation and engine modepsm-oem-config

from PIL import Image
import pytesseract

# psm 6: assume a single uniform block of text; oem 3: default LSTM engine
custom_config = r"--oem 3 --psm 6"
text = pytesseract.image_to_string(Image.open("receipt.png"), config=custom_config)

# single line of text, digits only
digits = pytesseract.image_to_string(
    Image.open("meter.png"),
    config=r"--psm 7 -c tessedit_char_whitelist=0123456789",
)

Wrong psm is the number one cause of garbage output: the default expects a full page, so single lines, sparse text, and receipts each need their own mode.

Get words with boxes and confidence scoreswords-with-confidence

from PIL import Image
import pytesseract
from pytesseract import Output

data = pytesseract.image_to_data(Image.open("form.png"), output_type=Output.DICT)
for i, word in enumerate(data["text"]):
    conf = int(data["conf"][i])
    if word.strip() and conf > 60:
        print(word, conf, (data["left"][i], data["top"][i], data["width"][i], data["height"][i]))

conf is -1 for non-word rows (blocks, lines), so filter before trusting it. Filtering below roughly 60 removes most hallucinated fragments.

Get character-level bounding boxescharacter-boxes

from PIL import Image
import pytesseract

img = Image.open("plate.png")
for line in pytesseract.image_to_boxes(img).splitlines():
    ch, x1, y1, x2, y2, _ = line.split(" ")
    print(ch, x1, y1, x2, y2)

Box coordinates use the bottom-left origin (Tesseract convention), not the top-left origin PIL and OpenCV use; flip y before drawing.

Produce a searchable PDFsearchable-pdf

import pytesseract

pdf_bytes = pytesseract.image_to_pdf_or_hocr("scan.png", extension="pdf")
with open("scan-searchable.pdf", "w+b") as f:
    f.write(pdf_bytes)

The output layers invisible text over the original image. For whole multi-page documents, ocrmypdf wraps this workflow with rotation and cleanup.

Detect page rotation and scriptorientation-detection

from PIL import Image
import pytesseract

osd = pytesseract.image_to_osd(Image.open("sideways.png"))
print(osd)  # includes 'Rotate: 90' and 'Script: Latin'

OSD needs the osd traineddata pack installed and fails on images with little text. Rotate the image by the reported angle before running OCR.

Preprocess with OpenCV before OCRopencv-preprocessing

import cv2
import pytesseract

img = cv2.imread("photo.jpg")
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
gray = cv2.resize(gray, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
_, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)

text = pytesseract.image_to_string(thresh)

OpenCV loads BGR while pytesseract assumes RGB, so convert (or grayscale) first. Upscaling small text and Otsu thresholding are the two cheapest accuracy wins.

Stop runaway OCR jobs with a timeouttimeout-handling

import pytesseract

try:
    text = pytesseract.image_to_string("huge-scan.tiff", timeout=5)
except RuntimeError:
    text = ""  # tesseract was terminated after 5 seconds

Noisy images can make Tesseract grind for minutes. The timeout kills the subprocess and raises RuntimeError, which you must catch.

Get several output formats in one OCR passmultiple-outputs-one-pass

import pytesseract

text, boxes = pytesseract.run_and_get_multiple_output(
    "page.png", extensions=["txt", "box"]
)

Runs recognition once instead of once per format; supports mixing txt, pdf, hocr, box, and tsv. Worth it when you need text plus coordinates.

Alternatives

PackageRegistryPick it when
easyocrPyPIYou want deep learning OCR with much better accuracy on photos and scene text, pip-installable with optional GPU.
paddleocrPyPIYou need strong layout analysis, table recognition, or top-tier accuracy on Chinese and mixed-language documents.
tesserocrPyPIYou want the same Tesseract engine through direct C++ bindings for real throughput instead of subprocess calls.