[PYTHON] Make a function to describe Japanese fonts with OpenCV

Introduction

This is a continuation of Last time.

The function cv2.putText () that draws text in OpenCV cannot use Japanese. Since it is possible with PIL, there are many methods on the web that use PIL only for that part, but I have published a unique function that can be an alternative to cv2.putText () just because I tried it for the time being. There was no place. So I made it myself. I'm sorry if there is a standard method just because my search skill is low.

version:  OpenCV 4.1.2.30  Pillow 7.0

review

Draw characters with OpenCV cv2.putText (img, text, org, fontFace, fontScale, color, thickness)

-* img * Image. Needless to say, OpenCV images. -* Text * Text. ** Japanese is not available . It is not possible to start a new line with a line feed code. - org * Specify the ** coordinates at the bottom left of the text with (x, y). - FontFace * font. Only a few types such as cv2.FONT_HERSHEY_SIMPLEX can be specified. -* FontScale * Font size. Essential for troublesome things. The size of "1" depends on the font. -* Color * Text color. Needless to say, if it is an RGB image, the order is (b, g, r) instead of RGB. -* Thickness * Line thickness. Optional and default value is 1.

Draw characters with PIL ImageDraw.text (xy, text, fill, font)

The target is an ImageDraw.Draw object created from a PIL image.

-* xy * Specify the coordinates of ** upper left ** of the text with (x, y). -* Text * Text. Japanese is OK. Line breaks using \ n are also OK. -* Fill * Text color. Needless to say, for RGB images, (r, g, b). -* Font * Font. Specify the font and size with ImageFont.truetype.

That means

Functionize

cv2.imshow () cannot be used Google Colab has its own function ** cv2_imshow () **. Following that, we named the original function that describes Japanese fonts in OpenCV ** cv2_putText () **.

First, prepare two functions. This is a function to convert OpenCV and PIL, which I wrote in this article.

python


import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont

def pil2cv(imgPIL):
    imgCV_RGB = np.array(imgPIL, dtype = np.uint8)
    imgCV_BGR = np.array(imgPIL)[:, :, ::-1]
    return imgCV_BGR

def cv2pil(imgCV):
    imgCV_RGB = imgCV[:, :, ::-1]
    imgPIL = Image.fromarray(imgCV_RGB)
    return imgPIL

Part 1

python


def cv2_putText_1(img, text, org, fontFace, fontScale, color):
    x, y = org
    b, g, r = color
    colorRGB = (r, g, b)
    imgPIL = cv2pil(img)
    draw = ImageDraw.Draw(imgPIL)
    fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
    draw.text(xy = (x,y), text = text, fill = colorRGB, font = fontPIL)
    """
I'll add it here later
    """
    imgCV = pil2cv(imgPIL)
    return imgCV

It is the same as many predecessors to make a PIL image, draw Japanese text on it, and then return it to an OpenCV image, but cv2.putText (img, text, org, fontFace, fontScale, color, thickness) The feature is that it can be used in the same way as . Of course, if you say "I want to use Japanese, but the font and size are fixed", you can set the default arguments.

Let's compare the output results of cv2.putText () and cv2_putText ().

python


import numpy as np
import cv2
from PIL import Image, ImageDraw, ImageFont

def pil2cv(imgPIL):
    #The ones listed above

def cv2pil(imgCV):
    #The ones listed above

def cv2_putText_1(img, text, org, fontFace, fontScale, color):
    #The ones listed above

def main():
    img = np.full((200,400,3), (160,160,160), dtype=np.uint8)

    #Ordinarily cv2.putText()Draw text with
    text = "OpenCV"
    x, y = 50, 100
    fontCV = cv2.FONT_HERSHEY_SIMPLEX
    fontScale = 1
    colorBGR = (255,0,0)
    thickness = 1

    cv2.putText(img = img,
                text = text,
                org = (x,y),
                fontFace = fontCV,
                fontScale = fontScale,
                color = colorBGR,
                thickness = thickness)
    """
I'll add it here later
    """

    #Draw Japanese text with your own function
    text = "Japanese too\n possible"
    x, y = 200,100
    fontPIL = "Dflgs9.TTC" #DF Reiga Song
    size = 40
    colorBGR = (255,0,0) # cv2.putText()As with, defined in the order of BGR
    
    img = cv2_putText_1(img = img,
                        text = text,
                        org = (x,y),
                        fontFace = fontPIL,
                        fontScale = size,
                        color = colorBGR)

    cv2.imshow("cv2_japanese_test", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

if __name__ == "__main__":
    main()

The result is this. cv_jp_font_test_1.png

The y coordinate should be the same value, but the height is off. This is because, as I wrote in the review section, * org * in cv2.putText () specifies the lower left, and * xy * in ʻImageDraw.text ()` specifies the upper right. Let's process it so that you can understand it.

python


# cv2_putText_1()Add the following to the comment line of
    w, h = draw.textsize(text, font = fontPIL)
    draw.rectangle([(x,y), (x+w,y+h)], outline = (255,0,0), width = 1)
    draw.ellipse([(x-3,y-3), (x+3,y+3)], None, (255,0,0), 1)

# main()Add the following to the comment line of
    (w, h), b = cv2.getTextSize(text = text,
                                fontFace = fontCV,
                                fontScale = fontScale,
                                thickness = thickness)
    pt1 = (x, y - h)
    pt2 = (x + w, y + b)
    cv2.rectangle(img, pt1, pt2, (0,0,255), 1)
    cv2.circle(img, (x,y), 5, (0,0,255))

The result is this. cv_jp_font_test_2.png

In the previous article, I didn't use the baseline obtained by cv2.getTextSize (), but this time I tried to draw a rectangle including it. I'm not sure why the PIL rectangle doesn't fit the Japanese text subtly. Perhaps the bug mentioned by this person is related.

Anyway, to make your own function compatible with * org * in cv2.putText (), you need to modify this part.

Part 2

Here is a modified version of the height standard.

python


def cv2_putText_2(img, text, org, fontFace, fontScale, color):
    x, y = org
    b, g, r = color
    colorRGB = (r, g, b)
    imgPIL = cv2pil(img)
    draw = ImageDraw.Draw(imgPIL)
    fontPIL = ImageFont.truetype(font = fontFace, size = fontScale)
    w, h = draw.textsize(text, font = fontPIL)
    draw.text(xy = (x,y-h), text = text, fill = colorRGB, font = fontPIL)
    imgCV = pil2cv(imgPIL)
    return imgCV

You can get an image like this by changing cv2_putText_1 inmain ()to cv2_putText_2. Similar to cv2.putText (), I was able to draw the text by specifying the lower left. cv_jp_font_test_3.png

However, I don't like the specification that * org * specifies the lower left in cv2.putText (), so I prefer cv2_putText_1 ().

Part 3

If you specify the font and font size with cv2.putText (), the size of the text to be drawn is determined. If you calculate the appropriate size with the specified font based on it, you can modify the existing program as shown in here with minimal modification. You can change to TrueType fonts! I thought, but I stopped because it was troublesome. ..

At the end

If you make it a function, you can use Japanese fonts in the same way as cv2.putText (). It was a story. However, of course, note that Japanese is not available in the window name of cv2.imshow () or the file name of cv2.imwrite ().

By the way, how can we create (b, g, r) from the tuple (r, g, b)? In my function this time, I take out each element and change the order to make a new tuple, but it is not an elegant solution. You could convert the tuples to a list, reverse the order, and then convert them back to tuples, but that's far from elegant.

python


r, g, b = 0, 128, 255
RGB = (r, g, b)
BGR = tuple(list(RGB)[::-1])
print (RGB)  # (0, 128, 255)
print (BGR)  # (255, 128, 0)

Please let me know if there is a nice way to experience aha, such as ʻimg [:,:, :: -1] `when converting an RGB image to BGR.

Recommended Posts

Make a function to describe Japanese fonts with OpenCV
How to make a recursive function
Make the function of drawing Japanese fonts in OpenCV general
How to make a surveillance camera (Security Camera) with Opencv and Python
I tried to make an image similarity function with Python + OpenCV
A memorandum to make WebDAV only with nginx
How to make a dictionary with a hierarchical structure.
I want to make a game with Python
Try to make a "cryptanalysis" cipher with Python
Try to make a dihedral group with Python
[Python] How to handle Japanese characters with openCV
How to make Linux compatible with Japanese keyboard
Make a function decorator
Load a photo and make a handwritten sketch. With zoom function. Tried to make it.
Try to make a command standby tool with python
[Practice] Make a Watson app with Python! # 2 [Translation function]
How to make a shooting game with toio (Part 1)
How to call a function
Easy to make with syntax
Make a fortune with Python
Make a fire with kdeplot
Associate Python Enum with a function and make it Callable
I want to make a blog editor with django admin
Experiment to make a self-catering PDF for Kindle with Python
I want to make a click macro with pyautogui (desire)
How to make a simple Flappy Bird game with pygame
I want to make a click macro with pyautogui (outlook)
I tried to make a motion detection surveillance camera with OpenCV using a WEB camera with Raspberry Pi
[5th] I tried to make a certain authenticator-like tool with python
Tokyo Corona: Try to make a simple prediction from open data with the exponential function curve_fit
[Road to Python Intermediate] Call a class instance like a function with __call__
Rubyist tried to make a simple API with Python + bottle + MySQL
[2nd] I tried to make a certain authenticator-like tool with python
Make it possible to output a log to a file with go echo
[Introduction to Python] How to split a character string with the split function
Let's make a GUI with python.
Make a sound with Jupyter notebook
[Python 3.8 ~] How to define a recursive function smartly with a lambda expression
How to make a slack bot
Make a cat detector with Google Colabratory (Part 2) [Python] ~ Use OpenCV ~
[3rd] I tried to make a certain authenticator-like tool with python
Let's make a breakout with wxPython
How to make a command to read the configuration file with pyramid
Make a simple OMR (mark sheet reader) with Python and OpenCV
How to make a crawler --Advanced
Try to make a web service-like guy with 3D markup language
[Python] Make the function a lambda function
Make a recommender system with python
I tried to make a periodical process with Selenium and Python
I tried to make a 2channel post notification application with Python
How to make a deadman's switch
[Introduction] I want to make a Mastodon Bot with Python! 【Beginners】
[Blender] How to make a Blender plugin
Make a filter with a django template
I tried to make a todo application using bottle with python
[4th] I tried to make a certain authenticator-like tool with python
Let's make a graph with python! !!
Create a video player with PySimpleGUI + OpenCV 3 Addition of mask function
[1st] I tried to make a certain authenticator-like tool with python
Let's make a supercomputer with xCAT
How to make a crawler --Basic