Four Python libraries cover almost all text detection done outside research code. They differ less in accuracy than in which detector they wrap, what shape their output has, and how much they pull in at install time.
| Library | Detector inside | Detection-only call | Output | Licence |
|---|---|---|---|---|
| EasyOCR | CRAFT | reader.detect() |
boxes as [x_min, x_max, y_min, y_max] plus free-form polygons |
Apache-2.0 |
| PaddleOCR | PP-OCR (DB-family) | TextDetection().predict() |
quadrilaterals per line | Apache-2.0 |
| docTR | DBNet (db_resnet50) or LinkNet |
detection_predictor() |
relative boxes [xmin, ymin, xmax, ymax, score] |
Apache-2.0 |
| MMOCR | DBNet, DBNet++, PSENet, PANet, FCENet, TextSnake | MMOCRInferencer(det=...) |
polygons | Apache-2.0 |
All four run on CPU; all are faster with a CUDA GPU. Install them in separate virtual environments: PaddleOCR (PaddlePaddle) and MMOCR (PyTorch + MMCV) do not enjoy sharing one.
EasyOCR
pip install easyocr
import easyocr
reader = easyocr.Reader(["en"]) # downloads CRAFT + a recognizer on first run
horizontal, free = reader.detect("photo.jpg", min_size=20, text_threshold=0.7, low_text=0.4)
for x_min, x_max, y_min, y_max in horizontal[0]:
print("box", x_min, y_min, x_max - x_min, y_max - y_min)
for polygon in free[0]:
print("polygon", polygon) # list of [x, y] points for curved text
detect() runs only CRAFT. reader.readtext("photo.jpg") runs detection and recognition and returns (box, text, confidence) triples. EasyOCR is the easiest install; it is also the slowest of the four on CPU because CRAFT’s post-processing is heavy.
PaddleOCR (3.x API)
pip install paddlepaddle paddleocr
from paddleocr import TextDetection
model = TextDetection(model_name="PP-OCRv5_mobile_det")
for result in model.predict("photo.jpg", batch_size=1):
result.print() # dt_polys: one quadrilateral per text line, dt_scores
result.save_to_img("out/")
PaddleOCR 3.x reorganised its API around pipeline and module classes; older tutorials that call PaddleOCR(...).ocr(img, rec=False) describe the 2.x interface. The mobile detector is the same family of model the detector on this site runs in the browser; the server detector is larger and more accurate. Both are DB-style networks.
docTR
pip install "python-doctr[torch]"
from doctr.io import DocumentFile
from doctr.models import detection_predictor
detector = detection_predictor(arch="db_resnet50", pretrained=True)
pages = DocumentFile.from_images("photo.jpg")
result = detector(pages)
for xmin, ymin, xmax, ymax, score in result[0]["words"]: # relative coordinates, 0-1
print(xmin, ymin, xmax, ymax, score)
docTR (Mindee) is the cleanest code base of the four and the best documented. It is document-first: its defaults assume straight text, and assume_straight_pages=False switches on rotated boxes. Choose it when your inputs are scans and forms rather than street scenes.
MMOCR
pip install -U openmim && mim install mmengine "mmcv>=2.0.0" mmdet && pip install mmocr
from mmocr.apis import MMOCRInferencer
inferencer = MMOCRInferencer(det="DBNet") # or "DBNetpp", "PSENet", "PANet", "FCENet", "TextSnake"
result = inferencer("photo.jpg", return_vis=False)
polygons = result["predictions"][0]["det_polygons"]
scores = result["predictions"][0]["det_scores"]
MMOCR is the research toolbox: many detectors behind one interface, training configs for every benchmark on the datasets page, and the heaviest install. Pick it when you need to compare architectures or train your own.
Choosing
- Fastest path to boxes and text: EasyOCR.
- Best accuracy per megabyte, multilingual, CPU-friendly: PaddleOCR.
- Documents, clean code, production service: docTR.
- Research, custom training, many detectors: MMOCR.
- No install at all: the detector on this site, which runs PaddleOCR’s models through ONNX Runtime in the browser and exports JSON in the same box format as the table above.
Making outputs comparable
Every library uses a different coordinate convention. Convert everything to {x, y, width, height} in pixels of the original image before comparing, and remember that EasyOCR’s horizontal list orders values as x_min, x_max, y_min, y_max, not x, y, x, y.