Pythonで画像処理をする場合はOpenCVが便利ですが、細かい機能はPillow等のライブラリが優秀だったりします。ここではPillowを使って日本語フォントを任意画像に描画する方法を紹介します。
こんにちは。wat(@watlablog)です。
多目的に使える画像処理としては「文字入れ」があります。ここではPythonのPillowを使って画像に文字を入れる方法を紹介します!
前半は本記事で習得して出来るようになることや、ライブラリについての補足説明です。てっとり早くコードが見たい方は目次からジャンプしてみて下さい!
また当ブログではできるだけ詳細な説明を心がけていますが、簡単なコードは飛ばしています。Python初心者の方は「Pythonインストール方法とAnacondaを使わない3つの理由」や「Pythonページ」から読み進めて頂くと、僕と同じ開発環境を揃えたり、簡単なプログラミングについて触れているので参考になると思います。
他にも外部のサイトになりますが、PyQ(パイキュー)というPythonに特化したプログラミング学習サービスがあります。そこでは基本から応用までみっちりコースが組まれていますので、初学者の大きな味方になると思います。
僕自身もPyQに登録して実際にコースを受講しています。
興味のある方はまず「PyQでPython学習!実際に登録してみた感想と気になる料金」をお読み頂ければ、どんな感じの学習ができるかのイメージを掴むことが出来ます。
Pythonで画像に文字を入れると出来るようになる3つの事!
①補足説明を入れることが出来る
科学技術系の業務を行っている人は、実験で得られた写真等の画像を使って何かを説明することが多いと思います。
例えば画像内に毎回単位や決まった文章を入れなければならない場合、一度ExcelやPowerPoint等に貼り付けて文字を入れたり、GIMP等の汎用画像処理ソフトを使って文字を入れたりすることがまず思い浮かぶと思います。
しかし、手動で1枚1枚そのような作業をしていると、枚数が100枚や1000枚になった時に気が遠くなってきます。
もしPython等のプログラムを使って同じ作業が自動で出来れば、これは相当な生産性向上になります。
②日付や署名を入れることが出来る
スマホやデジカメで撮影した写真には日付を入れて記念にすることがあります。でも毎回日付付きで撮影している人はいないのではないでしょうか?
他にも、自分で描いたイラストをネットに公開するイラストレータは、著作権を無視した一部の人に勝手に使用されないよう、「SAMPLE」の半透明文字や自分の署名を入れることがあると思います。
このような日付や署名といった文字入れもプログラム的に自動で入れられるようにしておけばこれも生産性向上に寄与します。
③動画にテロップを入れることが出来る【YouTuberにオススメ】
プログラム的に画像に文字を入れることが出来るようになれば、それは動画にも入れることができることになるのと同義です。
「Pythonでブログの広告が目立つかどうか「動的」に評価する方法」では動画からフレーム(画像)を抜き出して、そのフレームに対して画像処理をするという方法を習得しました。
つまり画像処理を1つ覚えればすぐに動画に転用することができるということです。
動画に文字を入れることができれば、テロップを自分で挿入できるということになります。
色々カスタマイズをしたいYouTuberの方には相当オススメですね。
OpenCVとPillowを併用する理由
OpenCVは画像処理ライブラリの王道
この記事の後半ではOpenCVとPillowという2つの画像処理用のライブラリを使います。
普通はどちらか1つのライブラリを使えば事足りるでしょう。
OpenCVは言わずと知れた王道の画像処理ライブラリです。C++等を含めた様々なプログラミング言語でも同じライブラリで同じ処理が出来ます。
OpenCVを使えばこれら様々な言語で培われた知見がインターネット上に山のようにあります。これらを利用できるだけでもOpenCVを使うメリットがあります。
Pillowを使えば日本語フォントが使える
OpenCVだけあれば大体のことはできますが、今回の文字入れプログラムで日本語を使えないというデメリットがあります。
Pillowはその辺対応していますので、今回はPillowに文字入れ部分を担当してもらいます。
そして、通常の画像処理ではOpenCVを使った方が都合が良いので、特殊な部分のみその他のライブラリを使い、入出力はOpenCVに対応させるようにコーディングしようと思います。
Python/OpenCV/Pillowで文字入れするコード
全コード
詳細コード説明をする前にまずは全体のコードの概要を説明します。
インポートするパッケージはPillowことPIL、OpenCVことcv2、NumPyです。PILからはImage、ImageFont、ImageDrawの3つです。
画像を読み込み、def文で作成した画像に文字を入れる関数を実行、文字を入れた処理後の画像を表示させるという流れです。
画像に書き込む文字列はmessageに書いてある内容で、英語と日本語を織り交ぜてテストしてみます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
from PIL import Image, ImageFont, ImageDraw import cv2 import numpy as np # 画像に文字を入れる関数 def img_add_msg(img, message): font_path = 'C:\Windows\Fonts\meiryo.ttc' # Windowsのフォントファイルへのパス font_size = 24 # フォントサイズ font = ImageFont.truetype(font_path, font_size) # PILでフォントを定義 img = Image.fromarray(img) # cv2(NumPy)型の画像をPIL型に変換 draw = ImageDraw.Draw(img) # 描画用のDraw関数を用意 # テキストを描画(位置、文章、フォント、文字色(BGR+α)を指定) draw.text((50, 50), message, font=font, fill=(255, 255, 255, 0)) img = np.array(img) # PIL型の画像をcv2(NumPy)型に変換 return img # 文字入りの画像をリターン img = cv2.imread('lena.jpg', 1) # カラー画像読み込み message = 'Hello World (ハローワールド)' # 画像に入れる文章 img = img_add_msg(img, message) # 画像に文字を入れる関数を実行 # 画像を表示させる(何かキーを入力すると終了) cv2.imshow('title', img) cv2.waitKey(0) cv2.destroyAllWindows() |
作成した関数の説明
フォントの設定
まずは書き込む文字列のフォント種類、サイズを指定してPILで認識できるフォント定義をします。
1 2 3 |
font_path = 'C:\Windows\Fonts\meiryo.ttc' # Windowsのフォントファイルへのパス font_size = 24 # フォントサイズ font = ImageFont.truetype(font_path, font_size) # PILでフォントを定義 |
font_pathで設定しているパスは、Windowsが持っているフォントファイル(.ttc)までのパスです。
筆者の僕はWindows10を使っていますが、Windowsであれば大体同じフォルダにフォントファイルがインストールされていると思います。
WindowsでFontsフォルダを見ていても、普段ExcelやPowerPointで使っているフォント名とファイル名が合わずわかりにくいです。外部サイトですが非常にわかりやすいフォント一覧を載せている「Windows10によってインストールされるフォント」を見ると一発でファイル名がわかるので、是非参考にして下さい。
また、PILは英語ですが公式ドキュメントもわかりやすいです。ここで使っているImageFont.truetypeは以下のリンクに公式ページがありますので、是非こちらも参考にして下さい。
公式ドキュメント:ImageFont Module:Pillow
OpenCV⇔PIL画像変換
このページでは、より汎用性を持たせたコードにするため、基本仕様をOpenCVに合わせています。
そのため、OpenCV仕様で読んできた画像をPIL仕様に変換して画像処理、最後はPIL仕様の画像をOpenCV仕様に再変換ということをしています。
まず以下がOpenCV仕様からPIL仕様へ変換する部分のコードです。
1 2 |
img = Image.fromarray(img) # cv2(NumPy)型の画像をPIL型に変換 draw = ImageDraw.Draw(img) # 描画用のDraw関数を用意 |
OpenCV(cv2)仕様はNumPyで扱う配列と同じ形式なので、Image.fromarrayを使ってPIL仕様に変換しています。こちらも公式ドキュメントがあるので、参考にしていただければと思います。
公式ドキュメント:Image Module:Pillow
そしてPIL仕様からOpenCV仕様への変換は以下のコードで行います。OpenCVはNumPyと同じなので、これはこのブログではお馴染みの変換ですね。
1 |
img = np.array(img) # PIL型の画像をcv2(NumPy)型に変換 |
画像に文字列を書き込む(描画する)
文字列を画像に描画するために、ImageDraw.Drawで描画用の入れ物定義をします(インスタンスという?)。
そして、作成された描画用インスタンスに対し、.text関数で文字列messageを書き込みます。ここで、位置、上で説明したフォント設定font、文字列の色fillを引数にします。
文字色はBGRとαの順に並んでいます。ここではBGRを全て255とすることで白色を表現しています。
1 2 3 4 |
draw = ImageDraw.Draw(img) # 描画用のDraw関数を用意 # テキストを描画(位置、文章、フォント、文字色(BGR+α)を指定) draw.text((50, 50), message, font=font, fill=(255, 255, 255, 0)) |
公式ドキュメント:ImageDraw Module:Pillow
実行結果
以下が実行結果で得られる画像です。題材は標準テスト画像であるレナさんにしました。レナさんについてのコラムは「Python/OpenCVで画像の二値化をする方法」で記載しましたが、久しぶりの登場ですね。
まとめ
本ページでは、PythonのOpenCVとPillowを使った画像への文字入れを習得しました。
OpenCVの汎用性を維持しつつ、ピンポイントでPillowを使うコーディングをしていますので、普段OpenCVで実施している画像処理プログラムにもシームレスに展開できます。
画像の文字入れは汎用性のある処理です!是非マスターしましょう!
Twitterでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!
コメント