目次
概要
OpenCV の cv2.putText()
を使用して画像にテキストを描画する方法について解説します。
また、Pillow を使用して日本語のテキストを描画する方法についても記載しています。
cv2.putText
公式リファレンス: cv2.putText
img = cv2.putText(img, text, org, fontFace, fontScale,
color[, thickness[, lineType[, bottomLeftOrigin]]])
引数
名前 | 型 | デフォルト値 |
---|---|---|
img | ndarray | |
入力画像 | ||
text | str | |
文字列 | ||
org | tuple of 2 ints | |
描画位置 (baseline の始点) | ||
fontFace | int | |
フォントの種類 | ||
fontScale | float | |
フォントの倍率 | ||
color | int / tuple of ints | |
色 | ||
thickness | int | 1 |
文字の太さ | ||
line_type | LineTypes | cv2.LINE_8 |
線の描画方法 | ||
bottomLeftOrigin | bool | False |
True の場合、左下を原点として扱う |
返り値
名前 | 説明 | ||
---|---|---|---|
img | 出力画像 |
注意点として、日本語などの Ascii 文字以外は描画できないため、そのような文字を描画したい場合は Pillow を使います。
lineType=cv2.LINE_AA
を指定すると、アンチエイリアスが有効になり、文字のジャギーが軽減します。
- 色は
color
で指定します。1 チャンネル画像の場合はint
、3 チャンネル画像の場合は(int, int, int)
で指定します。(例:color=(255, 0, 0)
) - 線の太さは
thickness
で指定します。負の値を指定した場合は塗りつぶしになります。 - 描画は引数に渡した配列を直接変更します。
- 点の座標や大きさは
float
ではなく、int
で指定します。
In [1]:
import cv2
from IPython.display import Image, display
def imshow(img):
"""ndarray 配列をインラインで Notebook 上に表示する。"""
ret, encoded = cv2.imencode(".jpg", img)
display(Image(encoded))
In [2]:
import cv2
import numpy as np
# 描画用の画像を生成する。
img = np.zeros((100, 300, 3), dtype=np.uint8)
cv2.putText(
img,
"Hello World", # テキスト
(0, 30), # テキストの位置 (ベースラインの左端)
fontFace=cv2.FONT_HERSHEY_SIMPLEX, # フォントの種類
fontScale=1.0, # フォントのスケール
color=(255, 255, 255), # フォントの色
thickness=2, # フォントの太さ
lineType=cv2.LINE_AA, # 描画方法
)
imshow(img)
テキストの大きさを取得する
retval, baseLine = cv2.getTextSize(text, fontFace, fontScale, thickness)
公式リファレンス: cv2.getTextSize
引数
名前 | 型 | デフォルト値 |
---|---|---|
text | str | |
文字列 | ||
fontFace | int | |
フォントの種類 | ||
fontScale | float | |
フォントの倍率 | ||
thickness | int | 1 |
文字の太さ |
返り値
名前 | 説明 | ||
---|---|---|---|
(w, h) | 文字の大きさ | ||
baseLine | ベースラインまでの距離 |
引数の解釈は以下のようになっています。
文字を囲む矩形とベースラインを描画する例を紹介します。
In [3]:
img = np.zeros((100, 300, 3), dtype=np.uint8)
text = "Hello World" # 描画する文字
fontface = cv2.FONT_HERSHEY_SIMPLEX # フォントの種類
fontscale = 1.0 # 文字のスケール
thickness = 2 # 文字の太さ
x, y = 50, 50 # ベースラインの始点
# 文字列を描画した際の大きさを取得する。
(w, h), baseline = cv2.getTextSize(text, fontface, fontscale, thickness)
print(f"size: ({w}, {h}), baseline: {baseline}")
# 文字を囲む矩形を描画する。
cv2.rectangle(img, (x, y - h), (x + w, y + baseline), (0, 0, 255), thickness)
# ベースラインを描画する。
cv2.line(img, (x, y), (x + w, y), (0, 255, 255), thickness)
# 文字列を描画する。
cv2.putText(img, text, (x, y), fontface, fontscale, (255, 255, 255), thickness)
imshow(img)
size: (176, 22), baseline: 10
また、cv2.getTextSize()
で指定した丁度収まる fontScale の値を取得できます。
retval, baseLine = cv2.getTextSize(text, fontFace, fontScale, thickness)
公式リファレンス: cv2.getFontScaleFromHeight
引数
名前 | 型 | デフォルト値 |
---|---|---|
fontFace | int | |
フォントの種類 | ||
pixelHeight | int | |
高さ | ||
thickness | int | 1 |
文字の太さ |
返り値
名前 | 説明 | ||
---|---|---|---|
fontFace | フォントの倍率 |
In [4]:
import cv2
import numpy as np
img = np.zeros((100, 300, 3), dtype=np.uint8)
text_h = 20
text = "Hello World" # 描画する文字
fontface = cv2.FONT_HERSHEY_SIMPLEX # フォントの種類
fontscale = cv2.getFontScaleFromHeight(fontface, text_h) # 文字のスケール
thickness = 2 # 文字の太さ
x, y = 50, 50 # ベースラインの始点
# 文字列を描画した際の大きさを取得する。
(text_w, text_h), baseline = cv2.getTextSize(text, fontface, fontscale, thickness)
print(f"size: ({text_w}, {text_h}), baseline: {baseline}")
# 文字を囲む矩形を描画する。
cv2.rectangle(img, (x, y - text_h), (x + text_w, y + baseline), (0, 0, 255), thickness)
# ベースラインを描画する。
cv2.line(img, (x, y), (x + text_w, y), (0, 255, 255), thickness)
# 文字列を描画する。
cv2.putText(img, text, (x, y), fontface, fontscale, (255, 255, 255), thickness)
imshow(img)
size: (159, 20), baseline: 9
日本語のテキストを描画する
cv2.putText()
は簡単にテキストの描画が行えますが、以下の欠点があります。
- 日本語が描画できない
- フォントの種類が用意されたもの以外選択できない
In [5]:
import cv2
import numpy as np
# 描画用の画像を生成する。
img = np.zeros((100, 300, 3), dtype=np.uint8)
cv2.putText(
img,
"日本語", # テキスト
(0, 30), # テキストの左下の位置
fontFace=cv2.FONT_HERSHEY_SIMPLEX, # フォントの種類
fontScale=1.0, # フォントのスケール
color=(255, 255, 255), # フォントの色
thickness=2, # フォントの太さ
lineType=cv2.LINE_AA, # 描画方法
)
imshow(img)
そのため、日本語を描画したい場合、Pillow のテキストを描画する関数を使用することをおすすめします。
In [6]:
import cv2
import numpy as np
from PIL import Image as PILImage, ImageDraw, ImageFont
def put_text(
img,
text,
org,
fontname,
fontsize=10,
color=(0, 0, 0),
):
# PIL の Image に変換する。
img = PILImage.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
font = ImageFont.truetype(fontname, size=fontsize)
draw = ImageDraw.Draw(img, mode="RGBA")
draw.text(org, text, fill=color, font=font)
return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
def get_text_size(img, text, org, fontname, fontsize=10):
# PIL の Image に変換する。
img = PILImage.fromarray(cv2.cvtColor(img, cv2.COLOR_RGB2BGR))
font = ImageFont.truetype(fontname, size=fontsize)
draw = ImageDraw.Draw(img, mode="RGBA")
text_box = draw.textbbox(org, text, font=font)
return tuple(text_box[2:])
# 描画用の画像を生成する。
img = np.zeros((100, 300, 3), dtype=np.uint8)
# Ubuntu の場合 (IPA フォント)
# インストールされていない場合は、sudo apt install -y fonts-ipafont でインストールする。
font_name = "ipagp.ttf"
# Windows の場合
# font_name = "meiryo.ttc"
text = "日本語"
position = (0, 0)
fontsize = 30
# テキストのサイズを取得する。
text_w, text_h = get_text_size(img, text, position, font_name, fontsize)
cv2.rectangle(img, position, (text_w, text_h), (255, 255, 255), -1)
print(f"text size: ({text_w}, {text_h})")
# テキストを描画する。
img = put_text(
img,
text,
position,
font_name,
fontsize,
color=(255, 0, 0), # RGB で指定
)
imshow(img)
text size: (90, 29)
コメント