Skip to content

Instantly share code, notes, and snippets.

@Xonxt
Last active October 6, 2020 20:44
Show Gist options
  • Save Xonxt/685b15c07a667dd8121ee44399266cfb to your computer and use it in GitHub Desktop.
Save Xonxt/685b15c07a667dd8121ee44399266cfb to your computer and use it in GitHub Desktop.
A function, that allows more flexibility when rendering text with OpenCV in Python. You can add text outline, draw a list of strings with just one call, and even align the text block horizontally or vertically relative to an anchor point.
import numpy as np
import cv2
from enum import Enum
class Align(Enum):
LEFT = 0
CENTER = 1
RIGHT = 2
class Valign(Enum):
TOP = 0
MIDDLE = 1
BOTTOM = 2
class Sorting(Enum):
NONE = 0
DSCN = 1
ASCN = 2
def draw_text(canvas, string, org=(0,0), align=Align.LEFT, valign=Valign.TOP, inner_pad=0, outer_pad=[0,0],
font_face=cv2.FONT_HERSHEY_PLAIN, font_size=2, font_color=(255, 255, 255), font_width=1, line_type=cv2.LINE_4,
outline=False, outline_color=(0, 0, 0), outline_width=2, darken_background=-1, background_color=None, sort=Sorting.NONE):
"""
A function for a more sophisticated and flexible text rendering. Using this instead of the standard cv2.putText() may result
in a small performance loss.
"""
max_width = 0
max_height = outer_pad[1] * 2
if not isinstance(string, list):
string = [string]
str_quantity = len(string)
# list of dimensions
dims_array = list()
# iterate through strings to calculate the box dimensions
for i, s in enumerate(string):
dims, _ = cv2.getTextSize(s, font_face, font_size, font_width)
dims_array.append(dims)
# calculate text block dimensions:
if dims[0] > max_width:
max_width = dims[0]
max_height += dims[1]
if i > 0 and i < str_quantity:
max_height += inner_pad
# set the maximum width of the text block
max_width = max_width + outer_pad[0] * 2
# if no image was supplied, just return the text block size
if canvas is None:
return (max_width, max_height)
# calculate the top-left point for the text block
tl = [org[0], org[1]]
br = [tl[0] + max_width, tl[1] + max_height]
# horizontal align:
if align == Align.RIGHT:
tl[0] = org[0] - max_width
br[0] = org[0]
elif align == Align.CENTER:
tl[0] = org[0] - max_width // 2
br[0] = org[0] + max_width // 2
# vertical align:
if valign == Valign.MIDDLE:
tl[1] = org[1] - max_height // 2
br[1] = org[1] + max_height // 2
elif valign == Valign.BOTTOM:
tl[1] = org[1] - max_height
br[1] = org[1]
if darken_background >= 0:
darken_background = np.clip(darken_background, 0, 1)
# if necessary, draw a background color
if background_color is not None and isinstance(background_color, tuple):
if darken_background < 0:
cv2.rectangle(canvas, (tl[0], tl[1]), (br[0], br[1]), background_color, outline_width)
cv2.rectangle(canvas, (tl[0], tl[1]), (br[0], br[1]), background_color, -1)
else:
overlay = np.zeros(canvas.shape, dtype=canvas.dtype)
cv2.rectangle(overlay, (tl[0], tl[1]), (br[0], br[1]), background_color, outline_width)
cv2.rectangle(overlay, (tl[0], tl[1]), (br[0], br[1]), background_color, -1)
canvas[:] = cv2.addWeighted(canvas, 1.0, overlay, darken_background, 1.0)
else:
# if necessary, darken the background of the text by the specified value
if 0 <= darken_background <= 1:
canvas[tl[1]:br[1], tl[0]:br[0]] = np.clip(np.uint8(canvas[tl[1]:br[1], tl[0]:br[0]]) * darken_background, 0, 255)
# sort the text by width, if necessary:
if sort == Sorting.NONE:
dims_array = enumerate(dims_array)
else:
dims_array = sorted(enumerate(dims_array), key=lambda x: x[1][0], reverse=(sort == Sorting.DSCN))
# iterate through text lines and draw them:
for i, (j, dim) in enumerate(dims_array):
dims = dim
s = string[j]
pt = (outer_pad[0] + int(tl[0]), outer_pad[1] + int(tl[1]) + (i+1) * dims[1] + i * inner_pad)
# draw the outline, when necessary
if outline:
cv2.putText(canvas, s, pt, font_face, font_size, outline_color, font_width + outline_width, line_type)
# draw the string
cv2.putText(canvas, s, pt, font_face, font_size, font_color[i] if isinstance(font_color, list) else font_color,
font_width, line_type)
# return the total width and height of the text block
return (max_width, max_height)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment