【Python】文字を1文字ずつ描画して画像に保存するコード例

テキストの文字を画像化して保存する Python コード例です。

文字を1つずつ描画して、1文字ずつ画像ファイル (.png) に保存していくコードです。

似たような文字を、自動でグループ分けしようと思って書きました。

【Python】フォントから『類似文字』の一覧を作成するコード例

文字は、フォントファイルを指定して描画します。

画像の余白も自動で取り除いて、文字の部分だけが残るようにしました。

文字の描画は、Pillowピロウ という Python ライブラリで行いました。

Pillow マニュアルの場所

コード例で使用したところの Pillow マニュアルです。

(Pillow) Windows Installation 『Pillow』のインストール方法

PIL.ImageFont.truetype(font=None, size=10, index=0, encoding='', layout_engine=None) フォント指定

PIL.Image.new(mode, size, color=0) 画像オブジェクト作成

PIL.ImageDraw.Draw(im, mode=None) 描画オブジェクト作成

ImageDraw.text(xy, text, fill=None, font=None, anchor=None, spacing=4, align='left', direction=None, features=None, language=None, stroke_width=0, stroke_fill=None, embedded_color=False) テキストを描画する

Image.getbbox() 余白を除いた領域の座標を取得

Image.crop(box=None) 画像を切り抜く

Image.save(fp, format=None, **params) 画像をファイルに保存する

Python マニュアルの場所

コード例で使用したところの Python マニュアルです。

ord(c) オード関数。文字の『Unicode コードポイントを表す整数』を取得する

class pathlib.Path(*pathsegments) パスオブジェクトを作成

PurePath.joinpath(*other) パスを連結する

エフ f から始まる文字列 f'' は、『エフストリング (f-string)』と呼ばれるものでした。

(f-string) フォーマット済み文字列リテラル

フォントファイルの場所

M+ FONTS を使わせていただきました。

M+ FONTS | JAPANESE

コード例では、『mplus-1m-regular.ttf』を使用しました。

文字がとても読みやすかったです。ありがとうございます。

コード例

テキストの文字を『1文字ずつ』描画して、画像ファイルに保存していく Python コード例です。

from pathlib import Path
from PIL import Image, ImageFont, ImageDraw

def main():
    # (設定 1/7) 文字列を決めます。
    text = '鑑(かんが)みるぽほ゜。.・,gg990oO'

    # (設定 2/7) 画像の保存フォルダを決めます。
    data_dir = Path(r'F:\project\images')

    # (設定 3/7) フォントファイルを決めます。
    # (M+ FONTS を使わせていただきました)
    # https://mplus-fonts.osdn.jp/about.html
    font_file = r'F:\project\fonts\mplus-1m-regular.ttf'
    font_size = 64
    font = ImageFont.truetype(font=font_file, size=font_size)

    # (設定 4/7) 背景色を『黒 (0, 0, 0)』に決めます。
    # .getbbox() メソッドが、黒を余白とみなしてくれるので、
    # 黒を使います。
    background_color = (0, 0, 0)

    # (設定 5/7) フォントの色を決めます。
    font_color = (255, 255, 255)

    # (設定 6/7) テキストの描画位置を決めます。
    position = (0, 0)

    # (設定 7/7) 画像サイズを決めます。
    # フォントサイズと画像サイズは、だいたいの値です。
    # 文字が画像の中に納まるように、何回か試して決めました。
    image_size = (96, 96)

    # テキストの文字を 1 つずつ取り出して、描画して保存していきます。
    for (n, letter) in enumerate(text):
        # (描画 1/5) 画像 (Image) オブジェクトを作ります。
        im = Image.new(mode='RGB', size=image_size, color=background_color)

        # (描画 2/5) 描画 (ImageDraw) オブジェクトを作ります。
        draw = ImageDraw.Draw(im)

        # (描画 3/5) 文字 (letter) を書きます。
        draw.text(xy=position, text=letter, font=font, fill=font_color)

        # (描画 4/5) 画像が 0 でない (色が黒でない) 領域の
        # 座標 (left, upper, right, lower) を取得します。
        bbox = im.getbbox()

        # (描画 5/5) 取得した座標で切り出します。
        im_crop = im.crop(box=bbox)

        # Unicode コードポイントを表す整数を取得します。
        # オード関数 ord() は、Python の組み込み関数です。
        code_point = ord(letter)

        # ファイル名を決めます。
        # (例) '{テキストの中での位置}_{Unicode コードポイント}.png'
        name = f'{n}_{code_point}.png'

        # ファイルパスを決めます。
        file = data_dir.joinpath(name)

        # 保存します。
        im_crop.save(file)
    return

if __name__ == '__main__':
    main()

実行結果

文字の部分だけを保存した画像ファイルができました。余白もありません。

実際に文字を描画して保存たときの画像ファイルぐんです。

ところで、1文字ずつだと、フォントが持っていた色々な余白が失われてしまいました。

人間でも、1文字だけでは余白が分かりませんから、仕方がないと思います。

フォントにもよりますが、余白が無いと、『ジー g』と『きゅう 9』がそっくりですね。

『文字の見た目』が役に立つと思った話

例えば、検索エンジンでキーワードを検索するときです。

『見た目が似ている文字』は、あまり区別せずに、一緒に検索したいなって思ったんですよね。

例えば漢字です。字体が異なるものがたくさんありました。

例えば記号です。ドットとか中点(なかてん、中黒、なかぐろ)とかピリオドとか、見た目がほとんど同じ、というものがたくさんありました。

何も無いという『空白文字』でさえ、種類がいくつもありました。

そういった似たような文字たちは、人が文章を読むときみたいに、あまり区別せずに検索したいなって思ったわけです。

文字の正規化にも、限界を感じていたところです。

では、どうしたらいいのか?

『文字を画像化して、似たものを事前にリストアップしておけばいいのではないか?』

そう思ったんですね。

文字の見た目』が役に立つと思ったわけです。

それで、『文字の見た目』が似ているもの調べるために、文字の画像化が必要になりました。

文字(を表すデータ)にフォントを適用して、画像として扱おうと思い立ちました。

人と同じように、文字を見た目で解釈しようという発想です。

画像化したら、次は機械学習か何かで、似た文字を分類していく感じですね。

そうして、最終的に『似た文字の辞書』を作れたらいいなと、そう思いました。

それがあれば、あいまいな検索ができるんじゃないかと。

例えば、"ド・モルガン" なら、正規表現で "ド[・.,o゜]モルガン" みたいな形式に自動変換して、検索できるんじゃないかと。

入力された検索キーワードを1文字ずつチェックして、似た文字の候補があれば、正規表現に含めていこうという作戦です。

結局、プログラムで『人間のように』文字を扱うためには、文字の見た目が必要なんだなって思いましたね。

実際、フォントがなければ、人間はコンピュータの中の文字を読めないわけですし。

『このバイト列は〇〇だな』とか、いちいち対応を覚えていないと読めないです。

あと、本当は1文字ずつじゃなくて、5文字くらいのかたまりで解釈したいところです。

文章を目で追っているときに、その瞬間、その瞬間で認識している文字って、だいたい5文字くらいだったんですよね。

顔文字みたいに、1文字ずつだと、ミスなのか意図したものなのか分からない場面でも、前後の文字から判断できそうです。

1つ文字の表現方法が複数あるケースにも対応できそうです。

濁点付きの文字とか、アクセント記号の表現とか。

そういったものも、文字を画像として扱う過程をへることで、何とかできるんじゃないかと。

さらにいえば、『発音』も役に立つんじゃないかと思っています。

読み仮名ではなくて、音の波形データのことですね。

自分は、文章を読むときに、あたまの中でよく音読しています。

耳の感覚も使って、文字を読んでいました。

人間って、文章を理解するときに、本当に色々な感覚を駆使しているんだなって思いますね。

人と同じような読み方をプログラムに取り入れる試みは、これまで何回も見かけていました。

それで、自分もやってみたいなと、前々からつねづね思っていました。

だって、面白そうじゃないですか。

ただ、あれもこれも同時にプログラムするのは無理なので、まずは文字を画像にしてみるところから書いてみました。

タイトルとURLをコピーしました