【Python入門】画像に文字を書き込む【OpenCV/putText関数】

この記事では、PythonとOpenCVを用いて画像に文字を書き込む方法を解説します。

管理人は…

  1. OCR(画像から文字を読み込む)
  2. DeepLで翻訳
  3. 翻訳結果を画像に書き込む

ということを行ってAR的な翻訳ツールの作成に挑戦しています。
現状、日本語を書き込む処理が出来ていないためOCR結果を書き込むだけにしていますが、イメージはこんな感じです。

目次

文字を書き込む関数”putText”関数

画像に文字を書き込むにはOpenCVのputText関数を使用します。

putText関数の引数は以下の通りです。

  • img:書き込む画像
  • text:書き込む文字
  • org:書き込む座標(左下)
  • fontFace:文字のフォント
  • fontScale:文字サイズ
  • color:文字の色(青,緑,赤)
  • thickness:文字太さ
  • lineType:線の種類

少しややこしい箇所は以下の通り

書き込む座標は左下

そのままですが、指定した座標を左下として文字を書き込みます。
文字の大きさに注意しましょう。

文字のフォントの種類

  • CV_FONT_HERSHEY_SIMPLEX
  • CV_FONT_HERSHEY_PLAIN
  • CV_FONT_HERSHEY_DUPLEX
  • CV_FONT_HERSHEY_COMPLEX
  • CV_FONT_HERSHEY_TRIPLEX
  • CV_FONT_HERSHEY_COMPLEX_SMALL
  • CV_FONT_HERSHEY_SCRIPT_SIMPLEX
  • CV_FONT_HERSHEY_SCRIPT_COMPLEX

各フォントを出力してみると以下の通りです。
↓全フォント出力のコード↓

import cv2 as cv
import numpy as np

# 黒い背景を作成
img = np.zeros((800,1500,3), np.uint8)

# ここにプログラムを追加して、文字を描画します
font = [
        "cv.FONT_HERSHEY_SIMPLEX",
        "cv.FONT_HERSHEY_PLAIN",
        "cv.FONT_HERSHEY_DUPLEX",
        "cv.FONT_HERSHEY_COMPLEX",
        "cv.FONT_HERSHEY_TRIPLEX",
        "cv.FONT_HERSHEY_COMPLEX_SMALL",
        "cv.FONT_HERSHEY_SCRIPT_SIMPLEX",
        "cv.FONT_HERSHEY_SCRIPT_COMPLEX"
    ]

num=0
for f in font:
    cv.putText(img,f,(20,(num+1)*80),num,2,(0,255,0),2,cv.LINE_AA)
    num+=1

cv.imshow("Draw Text", img)
cv.waitKey(0)

↓結果↓

公式ページに詳細(『小さいサイズのsans-serifフォントです』など)が書いてあります。

ちなみに日本語の書き込みは非対応のため、日本語を書き込むためには独自で関数を作成する必要があります。

文字サイズはフォントごとに違う

上の結果画像を見てわかるように、文字サイズはフォントごとに異なります。
(画像はすべてfontScale=2.0です)
使いたいフォントを出力して、サイズを見ながらfontScale(文字サイズ)を設定しましょう。

文字の色はRGBではなくBGR(青、緑、赤)

色の並びはRGB(赤、緑、青)が標準的なイメージですが、BGR(青、緑、赤)の順番です。
そのため、青・緑・赤を指定する場合は以下の通りです。

青:(255,0,0)
緑:(0,255,0)
赤:(0,0,255)

線の種類は3種類

線の種類は以下の4種類があります。

  • cv.FILLED
  • cv.LINE_4
  • cv.LINE_8
  • cv.LINE_AA

実際に結果を見てみましょう。
コードは以下の通りです。

import cv2 as cv
import numpy as np

# 黒い背景を作成
img = np.zeros((800,1500,3), np.uint8)

# ここにプログラムを追加して、文字を描画します
cv.putText(img,"cv.FILLED",(20,150),0,5,(0,255,0),2,cv.FILLED)
cv.putText(img,"cv.LINE_4",(20,300),0,5,(0,255,0),2,cv.LINE_4)
cv.putText(img,"cv.LINE_8",(20,450),0,5,(0,255,0),2,cv.LINE_8)
cv.putText(img,"cv.LINE_AA",(20,600),0,5,(0,255,0),2,cv.LINE_AA)

cv.imshow("Draw Text", img)
cv.waitKey(0)

正直よくわかりませんね。。。
“cv.LINE_AA”の先頭の”c”がちょっと滑らかかな…?ぐらいですね。

実際のコード

注意点はこれぐらいにして、実際にコードを見てみましょう。

ポイントは…
・37行目で左上、右下の座標を使って左下の座標を作成する
・39行目のputText関数
です。

#システムの利用を宣言する
import sys
import os

#PyOCRを読み込む    
from PIL import Image
import pyocr

#OpenCVの利用を宣言する(画像に四角を書き込む際に使用)
import cv2

#Tesseractのインストール場所をOSに教える
tesseract_path = "C:\Program Files\Tesseract-OCR"                   
if tesseract_path not in os.environ["PATH"].split(os.pathsep):      
    os.environ["PATH"] += os.pathsep + tesseract_path               

#OCRエンジンを取得する
tools = pyocr.get_available_tools()                                 
if len(tools) == 0:                                                 
    print("OCRエンジンが指定されていません")                        
    sys.exit(1)                                                     
else:
    tool = tools[0]                                                 
    

#画像の読み込み
file_path = "image/English_2.png"                                   
img = Image.open(file_path)                                         
img2 = cv2.imread(file_path)                                        

#文字と座標を読み取る
box_builder = pyocr.builders.WordBoxBuilder(tesseract_layout=6)     
text_position = tool.image_to_string(img,lang="jpn",builder=box_builder)    

#取得した座標と文字を出力し、画像に枠と読み取った文字を書き込む
for res in text_position:                                           
    position = [res.position[0][0],res.position[1][1]]              
    cv2.rectangle(img2,res.position[0],res.position[1],(0,0,255),2) 
    cv2.putText(img2,res.content,position,cv2.FONT_HERSHEY_SIMPLEX,1.0,(0,255,0,),2,cv2.LINE_AA) 
    
#四角を書き込んだ画像を表示する
cv2.imshow("image",img2)                                            
cv2.waitKey(0)                                                      

↓説明コメントあり↓

↓結果↓

無事、文字の枠の左下を起点として読み取った文字を書き込むことが出来ました!
この書き込む文字を日本語に対応させられれば、DeepLの翻訳結果を書き込めますね。
それはまた次回以降の記事で書いていきます。

ということで今回の記事はここまで!
ご覧いただきありがとうございました。