【Python・OpenCV】画像にテキストを描画する方法(cv2.putText)

※当サイトではアフィリエイト広告を利用しています

Python プログラミング 画像処理

【Python・OpenCV】画像にテキストを描画する方法(cv2.putText)

はじめに

OpenCVでは、さまざまな基本的な図形描画の他に、テキストを描画することもできます。
cv2.putText関数は文字を描画する関数です。
この関数の利用は、キャプションとしての文字、物体検出の結果情報、注釈付け、合成、GUI作成など、円を描画するシーンは多岐にわたります。

では、OpenCVでテキストを描画するcv2.putText関数について、解説していきましょう。

(広告) OpenCV関連書籍をAmazonで探す

テキストを描画

テキスト描画の使用場面

cv2.putText関数は、以下のような場面で使用されています。

  1. 物体検出結果の可視化:
    物体検出アルゴリズムで検出された物体の周りに、その物体の名前や確信度をテキストで書き込むことができます。これにより、検出結果を視覚的に確認しやすくなります。
  2. 警告やエラーメッセージの表示
    異常が検出された際にその旨を画面上にテキストで表示することができます。例えば「侵入者を検出しました」といったメッセージを映像に重ねて表示できます。
  3. デバッグ情報の表示
    コンピュータビジョンのアプリケーションを開発する際、各フレームの処理時間や特定の変数の値などをリアルタイムで画面上に表示し、デバッグに役立てることができます。

cv2.putText関数は画像やビデオに付加情報を視覚的に付与する場面で幅広く使われています。フォントの種類やサイズ、色、位置などをカスタマイズすることで、目的に合わせて効果的な表示ができます。

cv2.putText関数

cv2.putText関数の引数と戻り値は下の通りです。

cv2.putText(入力画像, text, org, fontFace, fontScale, color[, thickness[, lineType[,bottomLeftOrigin]]])

引数

名称説明
入力画像(必須)テキストを描画する画像データ
text(必須)描画するテキスト
org(必須)テキストの左下の座標。(x座標, y座標)の並びのタプル
fontFace(必須)フォントの種類の指定。HersheyFontsを参照。
fontScale(必須)フォントサイズのスケール係数(float)
color(必須)テキストの色 (BGR表記)
thickness(オプションテキストの線の太さ(デフォルト:1)
lineType(オプション線の種類。LineTypesで定義される値を設定します。(デフォルト:cv2.LINE_8)
bottomLeftOrigin(オプション座標系の原点がどこにあるかを指定(デフォルト:False、画像の左上が原点)

OpenCVには、組み込みフォントであるHersheyFontsが用意されています。HersheyFontsはベクターフォントで、リサイズやスムージングが可能です。主なHersheyFontsは以下の通りです。

フォントの種類特徴
cv2.FONT_HERSHEY_SIMPLEX標準的なゴシック体 フォント
cv2.FONT_HERSHEY_PLAIN小さいサイズのゴシック体 フォント
cv2.FONT_HERSHEY_DUPLEX通常サイズのゴシック体 フォント(cv2.FONT_HERSHEY_SIMPLEX より太い)
cv2.FONT_HERSHEY_COMPLEX通常サイズのスクリプト体 フォント
cv2.FONT_HERSHEY_TRIPLEX通常サイズのスクリプト体 フォント(cv2.FONT_HERSHEY_COMPLEX より太い)
cv2.FONT_HERSHEY_COMPLEX_SMALL小さいサイズのスクリプト体 フォント
cv2.FONT_HERSHEY_SCRIPT_SIMPLEX手書き風 フォント
cv2.FONT_HERSHEY_SCRIPT_COMPLEX手書き風 フォント(cv2.FONT_HERSHEY_SCRIPT_SIMPLEX より太く、デザインが異なる)

引数のlineTypeLineTypesに示す3種類のいずれかとなります。デフォルトはcv2.LINE_8です。

線の種類説明
cv2.LINE_44 連結
cv2.LINE_88 連結(デフォルト)
cv2.LINE_AAアンチエイリアス処理された線

戻り値

入力画像にテキストが描画された状態の画像データが返されます。

使い方

以下にサンプルコードを示します。

import cv2
import numpy as np

# 空の画像を作成
image = np.zeros((650, 1000, 3), dtype=np.uint8)

# 使用するフォントのリスト
fonts = [cv2.FONT_HERSHEY_SIMPLEX,
         cv2.FONT_HERSHEY_PLAIN,
         cv2.FONT_HERSHEY_DUPLEX,
         cv2.FONT_HERSHEY_COMPLEX,
         cv2.FONT_HERSHEY_TRIPLEX,
         cv2.FONT_HERSHEY_COMPLEX_SMALL,
         cv2.FONT_HERSHEY_SCRIPT_SIMPLEX,
         cv2.FONT_HERSHEY_SCRIPT_COMPLEX]

# フォントの名前
font_names = ["FONT_HERSHEY_SIMPLEX",
              "FONT_HERSHEY_PLAIN",
              "FONT_HERSHEY_DUPLEX", 
              "FONT_HERSHEY_COMPLEX",
              "FONT_HERSHEY_TRIPLEX",
              "FONT_HERSHEY_COMPLEX_SMALL",
              "FONT_HERSHEY_SCRIPT_SIMPLEX",
              "FONT_HERSHEY_SCRIPT_COMPLEX"]

# 文字色の配列
text_colors = [(0, 0, 255),        # 赤
               (0, 128, 255),      # オレンジ
               (0, 255, 255),      # 黄色
               (0, 255, 0),        # 緑
               (255, 0, 0),        # 青
               (255, 0, 128),      # 紫
               (255, 0, 255),      # ピンク
               (255, 255, 255)]    # 白

y = 50  # 最初のテキストの垂直位置
font_scale = 1.5  # フォントのスケール
thickness = 2  # 線の太さ

# 各フォントについてテキストを描画
for i, font in enumerate(fonts):
   text = font_names[i]
   text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)
   x = 50  # テキストの水平位置
   color = text_colors[i % len(text_colors)]  # 文字色を循環させる
   cv2.putText(image, text, (x, y), font, font_scale, color, thickness, cv2.LINE_AA)
   y += text_size[1] + 50  # 次のテキストの垂直位置を計算

# 画像を表示
cv2.imshow("cv2.putText: codevace.com", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

このコードでは、まず650x1000の真っ黒の画像を作成します。
次に、HersheyFontsのリストと、それぞれのフォント名のリストを定義します。
その後、ループを使って各フォントについて、そのフォント名のテキストを画像に描画しています。
各テキストの描画位置は、cv2.getTextSize関数を使ってテキストの実際のサイズを取得し、前のテキストの位置に基づいて配置するためのx、y座標を計算します。
最後に、cv2.imshow関数を使って画像を表示し、キーが押されるまで待機します。

実行すると、以下のような画像が表示されます。

すこし高度なテキストの描画方法

透過テキスト

背景が透過するように、テキストを描画することもできます。
cv2.addWeighted関数を使った、背景が透過したテキストを描画する方法を紹介します。

以下がサンプルコードをです。

import cv2
import numpy as np

# 背景画像を読み込む
background_image = cv2.imread("image.jpg")

# 背景画像と同じサイズの空の画像を作成
text_image = np.zeros_like(background_image)

# 描画するフォントを設定する
font = cv2.FONT_HERSHEY_DUPLEX
font_scale = 3.0
font_color = (0, 255, 0)  # RGB値 (緑)
thickness = 10 # 線の太さ

# テキストを描画する
text = 'Hello, OpenCV!'
text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)
text_x = (text_image.shape[1] - text_size[0]) / 2  # 画像の中央に配置
text_y = (text_image.shape[0] + text_size[1]) / 2  # 画像の中央に配置
cv2.putText(text_image, text, (int(text_x), int(text_y)), font, font_scale, font_color, thickness, cv2.FILLED)

# 画像を合成する
alpha = 0.5  # テキスト画像の不透明度
cv2.addWeighted(background_image, 1, text_image, alpha, 0, dst=background_image)

# 画像を表示
cv2.imshow("Transparent Text: codevace.com", background_image)
cv2.waitKey(0)
cv2.destroyAllWindows()

手順は以下の通りです:

  1. 背景画像を読み込みます。
  2. テキストレイヤー用の空画像を作成します。
  3. 空画像にテキストを描画します。
  4. cv2.addWeighted関数で背景画像とテキストレイヤーを合成します。第4引数がテキストレイヤーの不透明度を表します。
  5. 合成した画像を表示します。

cv2.addWeighted関数の呼び出し部分がポイントです:

cv2.addWeighted(background_image, 1, text_image, alpha, 0, dst=background_image)

この関数は、background_image + alpha*text_imageの計算を各ピクセルで行い、結果をbackground_imageに上書きします。alphaを0.5とすると、背景画像に50%透過のテキスト画像が重ね合わされた画像になります。

実行すると、背景画像の上に半透明のテキストが重ねられた画像が表示されます。alpha値を調整することで、テキストの透過度を変更できます。

このようにして、cv2.addWeighted関数を使うと比較的簡単に、背景が透過したテキストを描画することができます。

cv2.addWeighted関数についてはこちらの記事で紹介しています。

入力画像として、下の画像を使用しました。

アウトラインテキスト

テキストにアウトラインを付けることもできます。これには2回cv2.putText()関数を呼び出す必要があります。1回目は背景色でテキストを描画し、2回目は文字色でわずかに線の太さを太くしてテキストを描画します。

import cv2
import numpy as np

# 空の画像を作成
image = np.zeros((350, 1000, 3), dtype=np.uint8)

# 描画するフォントを設定する
font = cv2.FONT_HERSHEY_DUPLEX # フォントの種類
text = 'Hello, OpenCV!' # 描画するテキスト
font_scale = 3.5 # フォントの大きさ
font_color = (0, 255, 0) # ベース テキスト カラー:緑
thickness = 10 # ベースのテキストの線の太さ
outline_color = (0, 0, 255)  # アウトライン テキスト カラー:赤
outline_thickness = thickness * 2 # アウトラインテキストの線の太さ

# テキストを描画する
text_size, _ = cv2.getTextSize(text, font, font_scale, thickness)
text_x = (image.shape[1] - text_size[0]) / 2  # 画像の中央に配置
text_y = (image.shape[0] + text_size[1]) / 2  # 画像の中央に配置
# 先にアウトラインのテキストを描画
cv2.putText(image, text, (int(text_x), int(text_y)), font, font_scale, outline_color, outline_thickness, cv2.LINE_AA)
cv2.putText(image, text, (int(text_x), int(text_y)), font, font_scale, font_color, thickness, cv2.LINE_AA)

# 画像を表示
cv2.imshow("Outline Text: codevace.com", image)
cv2.waitKey(0)
cv2.destroyAllWindows()

テキストの線の太さをわずかに変えることで、1回目の太い線の内側にベースのテキストが描画されるようになり、アウトラインテキストの効果が出ます。アウトラインの量はoutline_thicknessの値で調整できます。

つまり、2回のcv2.putText()呼び出しを組み合わせ、テキストの線の太さを変えることで擬似的なアウトラインテキストを実現します。

おわりに

今回はOpenCVを使って画像にテキストを描画する基本的な方法から、すこし高度なテクニックまでご紹介しました。

シンプルなcv2.putText()関数一つで、画像に情報を視覚的に付与することができます。
タイトルやキャプション、アノテーションなど、用途は多岐に渡ります。フォントの種類、サイズ、色、配置など、様々なオプションを調整することで、テキストのスタイルもカスタマイズ可能です。
さらに、アンチエイリアシングの適用や、外部フォントの利用、合成なども可能です。

また、OpenCVのHersheyFontsはシンプルでありながら多様なので、多くのシーンで活用できますが、欧文フォントであることが短所と言えます。
日本語の描画は外部フォントを使う方法で実現できます。
この方法は別の記事で紹介したいと思います。

ご質問や取り上げて欲しい内容などがありましたら、コメントをお願いします。
最後までご覧いただきありがとうございました。

参考リンク

■(広告)OpenCVの参考書としてどうぞ!■

-Python, プログラミング, 画像処理
-