Opencv-Python, draw text with fontsize in pixels

Question:

In the opencv python, we use fontscale or thickness to show the font size, but if I want my font exactly to be 20px, how can I do that?
How can I change the scale/thickness in a way to compute my desired point size?

cv2.putText(img_inpainted,boxes['text'][i],(x,y),cv2.FONT_HERSHEY_PLAIN,1,(120,145,152),1,2)

I want the size of text exactly to be L px. How could I go doing that?

I searched and thought a lot, couldn’t find any way

Asked By: Arnav

||

Answers:

There’s a roundabout way. First you need to know the size of text for a given arbitrary fontScale. Then, assuming the Hershey vector fonts scale linearly, you can calculate desired pixel height into a corresponding fontScale.

There exists the function cv.getTextSize() to get you the size of a not-quite-bounding box for some given text. It’s giving a box including ascenders, but excluding descenders… and the baseline goes lower than any descenders among the regular alphabet. I’m guessing they render the text’s actual baseline at the height of the origin, and the extra baseline value tells us how much further down the drawn text can go still.

Here’s a rough outline because I won’t explore the effect of the thickness parameter for now, except to assume it’s 1.

# calculating a factor here
fontScale = 100
fontFace = cv.FONT_HERSHEY_PLAIN

((fw,fh), baseline) = cv.getTextSize(
    "", fontFace=fontFace, fontScale=fontScale, thickness=1) # empty string is good enough
factor = (fh-1) / fontScale

# using the factor now
text = "Hello, World!"
thickness = 1
height_in_pixels = 30 # or 20, code works either way
fontScale = (height_in_pixels - thickness) / factor
(w,h) = (500, 100)
canvas = np.zeros((h, w), 'uint8')
# I'm gonna center it
((fw, fh), baseline) = cv.getTextSize(
    text=text, fontFace=fontFace, fontScale=fontScale, thickness=thickness)
org = ((w-fw)//2, (h+fh)//2)
cv.putText(
    img=canvas, text=text, org=org,
    fontFace=fontFace, fontScale=fontScale, color=255, thickness=thickness)

that ought to be 30 pixels

cv.rectangle(canvas, org, (org[0] + fw, org[1] - fh), 128)
cv.line(canvas, (org[0], org[1]+baseline), (org[0] + fw, org[1]+baseline), 128)

same with "bounding box" and baseline

Answered By: Christoph Rackwitz
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.