Getting the bounding box of the recognized words using python-tesseract
Asked Answered
I

9

65

I am using python-tesseract to extract words from an image. This is a python wrapper for tesseract which is an OCR code.

I am using the following code for getting the words:

import tesseract

api = tesseract.TessBaseAPI()
api.Init(".","eng",tesseract.OEM_DEFAULT)
api.SetVariable("tessedit_char_whitelist", "0123456789abcdefghijklmnopqrstuvwxyz")
api.SetPageSegMode(tesseract.PSM_AUTO)

mImgFile = "test.jpg"
mBuffer=open(mImgFile,"rb").read()
result = tesseract.ProcessPagesBuffer(mBuffer,len(mBuffer),api)
print "result(ProcessPagesBuffer)=",result

This returns only the words and not their location/size/orientation (or in other words a bounding box containing them) in the image. I was wondering if there is any way to get that as well

Iatric answered 30/12, 2013 at 0:15 Comment(1)
may help github.com/tesseract-ocr/tesseract/wiki/…Blackstock
M
133

Use pytesseract.image_to_data()

import pytesseract
from pytesseract import Output
import cv2
img = cv2.imread('image.jpg')

d = pytesseract.image_to_data(img, output_type=Output.DICT)
n_boxes = len(d['level'])
for i in range(n_boxes):
    (x, y, w, h) = (d['left'][i], d['top'][i], d['width'][i], d['height'][i])
    cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.imshow('img', img)
cv2.waitKey(0)

Among the data returned by pytesseract.image_to_data():

  • left is the distance from the upper-left corner of the bounding box, to the left border of the image.
  • top is the distance from the upper-left corner of the bounding box, to the top border of the image.
  • width and height are the width and height of the bounding box.
  • conf is the model's confidence for the prediction for the word within that bounding box. If conf is -1, that means that the corresponding bounding box contains a block of text, rather than just a single word.

The bounding boxes returned by pytesseract.image_to_boxes() enclose letters so I believe pytesseract.image_to_data() is what you're looking for.

Mini answered 6/1, 2019 at 6:23 Comment(4)
This is actually the correct answer for this question. But might be ignored by people due to complexity of this methodVitellus
Do you know the meaning of other columns(level, page_num, block_num, par_num, line_num, word_num) in the output generated by image_to_data?Abdul
This work only for tesseract >= 3.05. I need a solution for lower version.Glister
When I ran this, the output from pytesseract showed that basically the whole image was the bounding box: i.imgur.com/E9dKc3L.pngKamin
Z
21

tesseract.GetBoxText() method returns the exact position of each character in an array.

Besides, there is a command line option tesseract test.jpg result hocr that will generate a result.html file with each recognized word's coordinates in it. But I'm not sure whether it can be called through python script.

Zincograph answered 30/12, 2013 at 2:18 Comment(1)
I get result.hocr file with the command, though the file is HTML format.Sweetscented
H
17

Python tesseract can do this without writing to file, using the image_to_boxes function:

import cv2
import pytesseract

filename = 'image.png'

# read the image and get the dimensions
img = cv2.imread(filename)
h, w, _ = img.shape # assumes color image

# run tesseract, returning the bounding boxes
boxes = pytesseract.image_to_boxes(img) # also include any config options you use

# draw the bounding boxes on the image
for b in boxes.splitlines():
    b = b.split(' ')
    img = cv2.rectangle(img, (int(b[1]), h - int(b[2])), (int(b[3]), h - int(b[4])), (0, 255, 0), 2)

# show annotated image and wait for keypress
cv2.imshow(filename, img)
cv2.waitKey(0)
Hillel answered 20/4, 2018 at 12:16 Comment(2)
Why y-coordinate is subtracted from the height of the imageDonndonna
I believe the pytesseract and opencv have different notions of the origin of the image (top left or bottom left), or at least that's what I I seemed to experience when I wrote the answer. If it works without the h there, great.Hillel
C
7

Using the below code you can get the bounding box corresponding to each character.

import csv
import cv2
from pytesseract import pytesseract as pt

pt.run_tesseract('bw.png', 'output', lang=None, boxes=True, config="hocr")

# To read the coordinates
boxes = []
with open('output.box', 'rb') as f:
    reader = csv.reader(f, delimiter = ' ')
    for row in reader:
        if(len(row)==6):
            boxes.append(row)

# Draw the bounding box
img = cv2.imread('bw.png')
h, w, _ = img.shape
for b in boxes:
    img = cv2.rectangle(img,(int(b[1]),h-int(b[2])),(int(b[3]),h-int(b[4])),(255,0,0),2)

cv2.imshow('output',img)
Caucasoid answered 13/7, 2017 at 11:45 Comment(1)
doesn't work, boxes is unknown parameter in lastest pytesseractAlkaline
I
4

Would comment under lennon310 but don't have enough reputation to comment...

To run his command line command tesseract test.jpg result hocr in a python script:

from subprocess import check_call

tesseractParams = ['tesseract', 'test.jpg', 'result', 'hocr']
check_call(tesseractParams)
Inconspicuous answered 18/10, 2018 at 18:21 Comment(0)
I
4

To get bounding boxes over words:

import cv2
import pytesseract
from pytesseract import Output

img = cv2.imread('test-01.jpg')
d = pytesseract.image_to_data(img, output_type=Output.DICT)
n_boxes = len(d['level'])
for i in range(n_boxes):
    if (d['text'][i] != ""):
        (x, y, w, h) = (d['left'][i], d['top'][i], d['width'][i], d['height'][i])
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 2) # in-place operation

cv2.imwrite('result.png', img)
Incognizant answered 16/11, 2020 at 6:53 Comment(0)
D
2

Some examples are answered aove which can be used with pytesseract, however to use tesserocr python library you can use code given below to find individual word and their bounding boxes:-

    with PyTessBaseAPI(psm=6, oem=1) as api:
            level = RIL.WORD
            api.SetImageFile(imagePath)
            api.Recognize()
            ri = api.GetIterator()
            while True::
                word = ri.GetUTF8Text(level)
                boxes = ri.BoundingBox(level)
                print(word,"word")
                print(boxes,"coords")
                if not ri.Next(level):
                     break
Demoniac answered 5/5, 2020 at 12:56 Comment(0)
I
0

As already mentioned, you can use pytesseract's image_to_boxes. You can check my Docker Hub repo https://hub.docker.com/r/milanhlinak/tesseract-image-to-boxes - a simple Flask application with Tesseract 5.0.0.

Illconsidered answered 16/1, 2022 at 20:51 Comment(0)
L
0

This is the ONLY solution that draws a rectangle around each word. Other working solutions draw boxes around blocks of text as well, which results in a mess if the image contains too many words. Here is the image I am using:

enter image description here

And here is the code:

import cv2
import pytesseract  # version '0.3.10'
from pytesseract import Output

img = cv2.imread("images/easy_text.png")

# Extract recognized data
data = pytesseract.image_to_data(img, output_type=Output.DICT)
n_boxes = len(data["text"])

for i in range(n_boxes):
    # Skip -1 confidence, because they correspond with blocks of text
    if data["conf"][i] == -1:
        continue
    # Coordinates
    x, y = data["left"][i], data["top"][i]
    w, h = data["width"][i], data["height"][i]

    # Corners
    top_left = (x, y)
    bottom_right = (x + w, y + h)

    # Box params
    green = (0, 255, 0)
    thickness = 3  # pixels

    cv2.rectangle(img, top_left, bottom_right, green, thickness)

# Save the image
output_image_path = "images/image_with_boxes.jpg"
cv2.imwrite(output_image_path, img)

And here is the result:

enter image description here

Lutanist answered 16/4, 2024 at 7:37 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.