Guidestutorial

Text detection with OpenCV: EAST and DB through cv2.dnn

Two complete, runnable scripts. OpenCV's dnn module loads the EAST and DBNet detectors without a deep-learning framework, and wraps their post-processing for you.

last verified 2026-09-05 · opencv-python 4.x · numpy

OpenCV’s dnn module ships two high-level wrappers, TextDetectionModel_DB and TextDetectionModel_EAST, that load a pretrained network, run it, and do the post-processing (thresholding, unclipping, non-maximum suppression) inside OpenCV. You get boxes back with no PyTorch or TensorFlow installed. Everything below was checked against OpenCV 4.x’s text-spotting tutorial; the model files come from the links on that page.

Setup

pip install "opencv-python>=4.8" numpy

Model files:

  • DB: DB_IC15_resnet18.onnx (trained on ICDAR 2015, best for scene text) or DB_TD500_resnet50.onnx (trained on MSRA-TD500, better for long lines). Both are linked from the OpenCV text spotting tutorial.
  • EAST: frozen_east_text_detection.pb, the frozen TensorFlow graph from the same tutorial.

DBNet: polygons for any shape

import cv2
import numpy as np

detector = cv2.dnn.TextDetectionModel_DB("DB_IC15_resnet18.onnx")
detector.setBinaryThreshold(0.3)
detector.setPolygonThreshold(0.5)
detector.setMaxCandidates(200)
detector.setUnclipRatio(2.0)
# Normalisation values the model was trained with; keep them exactly.
detector.setInputParams(
    scale=1.0 / 255.0,
    size=(736, 736),
    mean=(122.67891434, 116.66876762, 104.00698793),
    swapRB=False,
)

image = cv2.imread("photo.jpg")
polygons, confidences = detector.detect(image)

for quad, score in zip(polygons, confidences):
    pts = np.array(quad, dtype=np.int32).reshape(-1, 1, 2)
    cv2.polylines(image, [pts], isClosed=True, color=(74, 242, 144), thickness=2)
    x, y = pts[0][0]
    cv2.putText(image, f"{score:.2f}", (int(x), int(y) - 4), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (74, 242, 144), 1)

cv2.imwrite("photo-db.jpg", image)
print(f"{len(polygons)} text regions")

What the knobs mean (all four are the DBNet post-processing parameters):

Setter Effect
setBinaryThreshold probability above which a pixel is text
setPolygonThreshold minimum mean score inside a region to keep it
setUnclipRatio how far the shrunken kernel is expanded back to the full text; raise it if boxes are tight, lower it if neighbours merge
setMaxCandidates cap on regions considered

The input size does not have to be 736 × 736, but both sides must be multiples of 32. Larger sizes find smaller text and cost time quadratically.

EAST: rotated boxes, very fast

import cv2
import numpy as np

detector = cv2.dnn.TextDetectionModel_EAST("frozen_east_text_detection.pb")
detector.setConfidenceThreshold(0.5)
detector.setNMSThreshold(0.4)
detector.setInputParams(
    scale=1.0,
    size=(320, 320),          # multiples of 32
    mean=(123.68, 116.78, 103.94),
    swapRB=True,
)

image = cv2.imread("photo.jpg")
boxes, confidences = detector.detect(image)   # each box is 4 points of a rotated rectangle

for quad in boxes:
    pts = np.array(quad, dtype=np.int32).reshape(-1, 1, 2)
    cv2.polylines(image, [pts], isClosed=True, color=(74, 242, 144), thickness=2)

cv2.imwrite("photo-east.jpg", image)

EAST outputs rotated rectangles, so it copes with tilted signs but cannot follow curves. A 320 × 320 input is what the original tutorial used; 640 × 640 finds smaller words at four times the cost.

Which one?

DB (DB_IC15_resnet18) EAST
Output polygons (returned as 4-point quads by OpenCV) rotated rectangles
Curved text yes no
Long lines fair (use the TD500 model) splits them
Speed on CPU moderate fast
Age 2020 2017

For anything new, start with DB. Keep EAST for embedded CPUs where its speed matters and the text is straight.

Reading the text afterwards

OpenCV also has cv2.dnn.TextRecognitionModel, which runs a CRNN recognizer on each crop; the tutorial page shows the vocabulary file and preprocessing. In practice, once you need recognition it is simpler to move to a toolkit that bundles both steps: see text detection in Python, or use the detector on this site, which runs a DB-family model and a recognizer in the browser.

Common problems

  • Nothing detected. Check swapRB and mean; the DB models expect BGR input with the mean above, EAST expects RGB.
  • Boxes offset from the text. detect() returns coordinates in the original image space only when you pass the original image; do not resize before calling it.
  • Slow. Reduce the input size, or build OpenCV with CUDA and call detector.setPreferableBackend(cv2.dnn.DNN_BACKEND_CUDA).