Image Processing #7 - OpenCV Text


You can download the source codes here(https://github.com/raspberry-pi-maker/OpenCV)

Basic text output using putText


putText function Draws a text string.
Python: cv2.putText(img, text, org, fontFace, fontScale, color[, thickness[, lineType[, bottomLeftOrigin]]]) → None

Python: cv.PutText(img, text, org, font, color) → None
Parameters:
  • img – Image.
  • text – Text string to be drawn.
  • org – Bottom-left corner of the text string in the image.
  • fontCvFont structure initialized using InitFont().
  • fontFace – Font type. One of FONT_HERSHEY_SIMPLEX, FONT_HERSHEY_PLAIN, FONT_HERSHEY_DUPLEX, FONT_HERSHEY_COMPLEX, FONT_HERSHEY_TRIPLEX, FONT_HERSHEY_COMPLEX_SMALL, FONT_HERSHEY_SCRIPT_SIMPLEX, or FONT_HERSHEY_SCRIPT_COMPLEX, where each of the font ID’s can be combined with FONT_ITALIC to get the slanted letters.
  • fontScale – Font scale factor that is multiplied by the font-specific base size.
  • color – Text color.
  • thickness – Thickness of the lines used to draw a text.
  • lineType – Line type. See the line for details.
  • bottomLeftOrigin – When true, the image data origin is at the bottom-left corner. Otherwise, it is at the top-left corner.
The function putText renders the specified text string in the image. Symbols that cannot be rendered using the specified font are replaced by question marks. See getTextSize() for a text rendering code example.



import argparse
import numpy as np
import cv2

parser = argparse.ArgumentParser(description="OpenCV Example")
parser.add_argument("--thick", default = 3, type=int, help="font thickness")
parser.add_argument("--scale", default = 2.0, type=float, help="font thickness")
args = parser.parse_args()

w = 640
h = 480
channel = 3

img = np.zeros((h, w, channel), np.uint8)


red = (0, 0, 255)
green = (0, 255, 0)
blue = (255, 0, 0)
white = (255, 255, 255)
yellow = (0, 255, 255)
cyan = (255, 255, 0)
magenta = (255, 0, 255)

y_pos = 50

location = (20, y_pos)
font = cv2.FONT_HERSHEY_SCRIPT_SIMPLEX  # hand-writing style font
cv2.putText(img, 'Hello OpenCV', location, font, fontScale = args.scale, color = yellow, thickness = args.thick)

location = (20, y_pos + 50)
font = cv2.FONT_ITALIC  # italic font
cv2.putText(img, 'OpenCV Cooking', location, font, fontScale = args.scale, color = red, thickness = args.thick)

location = (20, y_pos + 100)
font = cv2.FONT_HERSHEY_SIMPLEX  # normal size sans-serif font
cv2.putText(img, 'Hello spypiggy', location, font, fontScale = args.scale,  color = blue, thickness = args.thick)

location = (20, y_pos + 150)
font = cv2.FONT_HERSHEY_COMPLEX  # normal size serif font
cv2.putText(img, 'Hello NVIDIA Jetson ', location, font, fontScale = args.scale, color = green, thickness = args.thick)


cv2.imshow("drawing", img)
cv2.waitKey(0)


Run the code.


python exam6-1.py




Text line spacing does not match. And some text is out of bounds on the canvas. To solve this problem, you need to find out the size of text in the canvas, and then change the canvas size or adjust the font size.


Get text box size using getTextSize

Calculates the width and height of a text string.
Python: cv2.getTextSize(text, fontFace, fontScale, thickness) → retval, baseLine
Python: cv.GetTextSize(textString, font)-> (textSize, baseline)
Parameters:
  • text – Input text string.
  • text_string – Input text string in C format.
  • fontFace – Font to use. See the putText() for details.
  • fontScale – Font scale. See the putText() for details.
  • thickness – Thickness of lines used to render the text. See putText() for details.
  • baseLine – Output parameter - y-coordinate of the baseline relative to the bottom-most text point.
  • baseline – Output parameter - y-coordinate of the baseline relative to the bottom-most text point.
  • font – Font description in terms of old C API.
  • text_size – Output parameter - The size of a box that contains the specified text.
The function getTextSize calculates and returns the size of a box that contains the specified text. That is, the following code renders some text, the tight box surrounding it, and the baseline:

Let's try to get the canvas size suitable for the text output before printing the text.



import argparse
import numpy as np
import cv2

parser = argparse.ArgumentParser(description="OpenCV Example")
parser.add_argument("--thick", default = 3, type=int, help="font thickness")
parser.add_argument("--scale", default = 2.0, type=float, help="font thickness")
args = parser.parse_args()

channel = 3

red = (0, 0, 255)
green = (0, 255, 0)
blue = (255, 0, 0)
white = (255, 255, 255)
yellow = (0, 255, 255)
cyan = (255, 255, 0)
magenta = (255, 0, 255)

x_leading = 20
y_leading = 20

def get_canvas_size(text, font):
    y_pos = y_leading
    y_size = 0
    x_size = 0
    for t, f in zip(text, font):
        (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)     
        y_pos += (label_height + baseline + y_leading)   
        if(label_width > x_size - x_leading):
            x_size = label_width + x_leading
        if(y_pos > y_size):
            y_size = y_pos 
    print('canvas size : W[%d] H[%d]'%(x_size, y_size))        
    img = np.zeros((y_size, x_size, channel), np.uint8)
    return img
            

text = ('Hello OpenCV', 'OpenCV Cooking', 'Hello spypiggy', 'Hello NVIDIA Jetson')
font = (cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, cv2.FONT_ITALIC, cv2.FONT_HERSHEY_SIMPLEX, cv2.FONT_HERSHEY_COMPLEX)
color = (red,green, blue, white)

img = get_canvas_size(text, font)
y_pos = 0
for t, f, c in zip(text, font, color):
    (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)
    y_pos += label_height + baseline + y_leading
    location = (20, y_pos)
    cv2.putText(img, t, location, f, fontScale = args.scale, color = c, thickness = args.thick)

cv2.imshow("drawing", img)
cv2.waitKey(0)


Run the code.

python exam6-2.py



Now you can see the text is printed properly on the canvas of the right size.


Changing the background color using np.fill and cv2.merge functions

We used the np.zeros function to create a canvas with a black background. You can create canvases of various colors using the np.full function.




import argparse
import numpy as np
import cv2

parser = argparse.ArgumentParser(description="OpenCV Example")
parser.add_argument("--thick", default = 3, type=int, help="font thickness")
parser.add_argument("--scale", default = 2.0, type=float, help="font thickness")
args = parser.parse_args()

channel = 3


red = (0, 0, 255)
green = (0, 255, 0)
blue = (255, 0, 0)
white = (255, 255, 255)
yellow = (0, 255, 255)
cyan = (255, 255, 0)
magenta = (255, 0, 255)

x_leading = 20
y_leading = 20

'''
This function get a color value for canvas background
'''
def get_canvas_size(text, font, color):
    y_pos = y_leading
    y_size = 0
    x_size = 0
    for t, f in zip(text, font):
        (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)     
        y_pos += (label_height + baseline + y_leading)   
        if(label_width > x_size - x_leading):
            x_size = label_width + x_leading
        if(y_pos > y_size):
            y_size = y_pos 
    print('canvas size : W[%d] H[%d]'%(x_size, y_size))

    B = np.full((y_size, x_size, 1), color[0],  dtype=np.uint8)
    G = np.full((y_size, x_size, 1), color[1],  dtype=np.uint8)
    R = np.full((y_size, x_size, 1), color[2],  dtype=np.uint8)

    img = cv2.merge((B, G, R))
    return img
            

text = ('Hello OpenCV', 'OpenCV Cooking', 'Hello spypiggy', 'Hello NVIDIA Jetson')
font = (cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, cv2.FONT_ITALIC, cv2.FONT_HERSHEY_SIMPLEX, cv2.FONT_HERSHEY_COMPLEX)
color = (red,green, blue, white)

img = get_canvas_size(text, font, yellow)
y_pos = 0
for t, f, c in zip(text, font, color):
    (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)
    y_pos += label_height + baseline + y_leading
    location = (20, y_pos)
    cv2.putText(img, t, location, f, fontScale = args.scale, color = c, thickness = args.thick)

cv2.imshow("drawing", img)
cv2.waitKey(0)

Run the code.


python exam6-3.py




Changing the text background color usingcv2.rectangle

We will use the cv2.getTextSize function we used earlier to fill in the rectangular area surrounding the text.



import argparse
import numpy as np
import cv2

parser = argparse.ArgumentParser(description="OpenCV Example")
parser.add_argument("--thick", default = 3, type=int, help="font thickness")
parser.add_argument("--scale", default = 2.0, type=float, help="font thickness")
args = parser.parse_args()

channel = 3


red = (0, 0, 255)
green = (0, 255, 0)
blue = (255, 0, 0)
white = (255, 255, 255)
yellow = (0, 255, 255)
cyan = (255, 255, 0)
magenta = (255, 0, 255)
gray = (127, 127, 127,)
x_leading = 20
y_leading = 20

'''
This function get a color value for canvas background
'''
def get_canvas_size(text, font, color):
    y_pos = y_leading
    y_size = 0
    x_size = 0
    for t, f in zip(text, font):
        (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)     
        y_pos += (label_height + baseline + y_leading)   
        if(label_width > x_size - x_leading):
            x_size = label_width + x_leading
        if(y_pos > y_size):
            y_size = y_pos 
    print('canvas size : W[%d] H[%d]'%(x_size, y_size))

    B = np.full((y_size, x_size, 1), color[0],  dtype=np.uint8)
    G = np.full((y_size, x_size, 1), color[1],  dtype=np.uint8)
    R = np.full((y_size, x_size, 1), color[2],  dtype=np.uint8)

    img = cv2.merge((B, G, R))
    return img
            

text = ('Hello OpenCV', 'OpenCV Cooking', 'Hello spypiggy', 'Hello NVIDIA Jetson')
font = (cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, cv2.FONT_ITALIC, cv2.FONT_HERSHEY_SIMPLEX, cv2.FONT_HERSHEY_COMPLEX)
color = (red,green, blue, white)

img = get_canvas_size(text, font, yellow)
y_pos = 0
box_offset_x = 10
box_offset_y = 10
rectangle_bgr = gray
for t, f, c in zip(text, font, color):
    (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)
    y_pos += label_height + baseline + y_leading
    location = (x_leading, y_pos)
    box_coords = ((x_leading - box_offset_x , y_pos - (label_height + baseline ) ), (x_leading + label_width , y_pos + box_offset_y))
    cv2.rectangle(img, box_coords[0], box_coords[1], rectangle_bgr, cv2.FILLED)
    cv2.putText(img, t, location, f, fontScale = args.scale, color = c, thickness = args.thick)

cv2.imshow("drawing", img)
cv2.waitKey(0)

Run the code.


python exam6-4.py




Outline Text using multiple cv2.putText

You can create a outline text by adjusting the cv2.putText function's org parameter  a little bit forward, backward, left, or right.



#-*- coding:utf-8 -*-
import argparse
import numpy as np
import cv2

parser = argparse.ArgumentParser(description="OpenCV Example")
parser.add_argument("--thick", default = 4, type=int, help="font thickness")
parser.add_argument("--scale", default = 4.0, type=float, help="font thickness")
args = parser.parse_args()

w = 640
h = 480
channel = 3

img = np.zeros((h, w, channel), np.uint8)


red = (0, 0, 255)
green = (0, 255, 0)
blue = (255, 0, 0)
white = (255, 255, 255)
yellow = (0, 255, 255)
cyan = (255, 255, 0)
magenta = (255, 0, 255)

x_leading = 20
y_leading = 20


def get_canvas_size(t, f):
    y_pos = y_leading
    y_size = 0
    x_size = 0
    (label_width, label_height), baseline = cv2.getTextSize(t, f, fontScale = args.scale, thickness = args.thick)     
    y_pos += (label_height + baseline + y_leading)   
    if(label_width > x_size - x_leading):
        x_size = label_width + x_leading
    if(y_pos > y_size):
        y_size = y_pos 
    print('canvas size : W[%d] H[%d]'%(x_size, y_size))        
    img = np.zeros((y_size, x_size, channel), np.uint8)
    return img
            

text = 'Hello OpenCV'
font = cv2.FONT_HERSHEY_COMPLEX

img = get_canvas_size(text, font)
y_pos = 0
thick = 4
(label_width, label_height), baseline = cv2.getTextSize(text, font, fontScale = args.scale, thickness = args.thick)
y_pos += label_height + baseline + y_leading

location = (20 - thick, y_pos)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20 + thick, y_pos)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20,  y_pos - thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20,  y_pos + thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)

location = (20 - thick, y_pos - thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20 + thick, y_pos + thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20 - thick,  y_pos - thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)
location = (20 + thick,  y_pos + thick)
cv2.putText(img, text, location, font, fontScale = args.scale, color = red, thickness = args.thick)

location = (20 , y_pos)
cv2.putText(img, text, location, font, fontScale = args.scale, color = white, thickness = args.thick)

cv2.imshow("drawing", img)
cv2.waitKey(0)

Run the code.


python exam6-5.py




Be Careful : OpenCV does not support text output using various fonts. PIL is a good way to print text using a variety of fonts such as "Arial, Hevetica, ..".  For text output using PIL, see my other post https://opencvcooking.blogspot.com/2019/12/basic-cooking-2-pil-text.html. If you want to print non-English characters, you should use PIL, which allows you to directly call fonts containing those characters.



댓글

이 블로그의 인기 게시물

OpenCV Installation - Rasbian Buster, Jessie, DietPi Buster

Creating TetrisClock using OpenCV #1