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
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)
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)
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
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)
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)