ゲレの工房

ゲーム好きの中の人が、自分が作りたいアプリを作る記録です

OpenCVとPillowで外部フォントを使った文字を書く

FF14に出てくるエオルゼア文字翻訳アプリ「言語を超える力」。内部としてはTensorFlowを用い、物体検出の推論結果をOpenCVで加工して表示しています。詳しくは以前の記事を。

blog.gelehrte.com

ここで用いている「Object Detection API」とサンプルスクリプト「Object Detection Tools」では推論結果をOpenCVのputTextで書き込んでいました。しかしputTextは組み込みのフォントしか使えず、フォントがイマイチで、結果があまりキレイに表示されませんでした。

この文字を外部フォントを使ってキレイにしたいという話です。

参考にした記事

OpenCVで日本語フォントを描写する を関数化する

今回は日本語フォントである必要はないですが、どのフォントでも使えるように出来る点に注目しました。

qiita.com

Python】Pillow ↔ OpenCV 変換

TensorFlowとObject Detection ToolsではOpenCVで推論結果を画像に書き込んでいました。その書き込み途中のOpenCVの画像をPillowの画像に変換し、そこでテキストを書き込みます。上記の「OpenCVで日本語フォントを描写する を関数化する」でも変換を行っているのですが、この記事の変換関数の方が使いやすいと思い、参考にさせていただきました。

qiita.com

Noto Sans Japanese

Google Fontsの一つ。今回はこのフォントを使い表示しました。
fonts.google.com

実装

私が実装したコードを参考にどうぞ

Pillow ↔ OpenCV 変換部分

def pil2cv(image):
    ''' PIL型 -> OpenCV型 '''
    new_image = np.array(image, dtype=np.uint8)
    if new_image.ndim == 2:  # モノクロ
        pass
    elif new_image.shape[2] == 3:  # カラー
        new_image = cv2.cvtColor(new_image, cv2.COLOR_RGB2BGR)
    elif new_image.shape[2] == 4:  # 透過
        new_image = cv2.cvtColor(new_image, cv2.COLOR_RGBA2BGRA)
    return new_image

def cv2pil(image):
    ''' OpenCV型 -> PIL型 '''
    new_image = image.copy()
    if new_image.ndim == 2:  # モノクロ
        pass
    elif new_image.shape[2] == 3:  # カラー
        new_image = cv2.cvtColor(new_image, cv2.COLOR_BGR2RGB)
    elif new_image.shape[2] == 4:  # 透過
        new_image = cv2.cvtColor(new_image, cv2.COLOR_BGRA2RGBA)
    new_image = Image.fromarray(new_image)
    return new_image

上記の変換関数を使って、OpenCVの画像に文字を書き込む部分

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

推論結果のテキストを書き込む部分

colorBGR = (0,0,0)
img = cv2_putText_2(img = img,
              text = information,
              org = (box[1] + 5, box[2] - 15),
              fontFace = font_name,
              fontScale = int(font_size),
              color = colorBGR)

これはObject Detection Toolsの下記の部分を書き直して使いました。詳しくはObject Detection Toolsを。簡単に説明すると、

  • img : OpenCVの画像
  • information : 書き込むテキスト
  • box : TensorFlowによって推論された座標。この座標を使いやすい形に変えれば、いろんな用途に使えると思います。
cv2.putText(img, information, (box[1] + 15, box[2] - 15), \
  cv2.FONT_HERSHEY_SIMPLEX, 1, color, 1, cv2.LINE_AA)

Google Fonts

特にインストールする必要がなく、Pythonスクリプトから絶対・相対パスを通せば使えます。

font_name = '..\\..\\fonts\\NotoSansJP-Bold.otf'

結果

上記のFF14エオルゼア文字翻訳アプリ「言語を超える力」の出力結果が以下のようになりました。

終わりに

とりあえず表示上はきれいになりました。ただ、「言語を超える力」はTensorFlowの推論なので、学習データをもっと上げないと精度自体は上がらないです。もっと学習データを増やさないとですね。今回はここまで。それでは。


広告