読者です 読者をやめる 読者になる 読者になる

にせねこメモ

はてなダイアリーがUTF-8じゃないので移ってきました。

適当に書いてフォントを作る

Python 画像処理 フォント

以前、 mashabow さんが、紙に書いた手書きの文字から手書きフォントを自動で生成する、という試みをしていた。

てきとうに書いて作ったフォント - しろもじ作業室

これが2008年のことである。当時この自動生成についての動画を見て感激した覚えがある。そして、更に自動化を進めたシステムが使えればいいのになあと思っていたが、実装する技術力はそのときの自分にはなかった。

一方それから8年近く経って(そんなに前なのか…)、今なら時間もあるし、それを実現する技術力もついたかなあと思ったので、作ってみた。縛りとしては、動作にあたって有料のソフトを必要としないというものである。

完成書体の見本

f:id:nixeneko:20160206093201p:plain
フォントは次からダウンロードできる。

フォント作成の流れ

1. 書き込みフォームをつくる

フォントにしたい文字のリストをつくる。

あいうえおかきくけこさしすせそたちつてとなにぬねのはひふへほまみむめもやゆよらりるれろ
わゐゑをんがぎぐげござじずぜぞだぢづでどばびぶべぼぱぴぷぺぽぁぃぅぇぉゃゅょっゎ
アイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロ
ワヰヱヲンガギグゲゴザジズゼゾダヂヅデドバビブベボパピプペポァィゥェォャュョッヮヵヶヴ
ゝゞヽヾ゛゜ー、。,.・…‥〜&:;?!※〒〃々〆〇仝〓―‐/\
‘’“”()〔〕[]{}〈〉《》「」『』【】
♪☆★○●◎◇◆□■§△▲▽▼¶→←↑↓ ̄_†‡

みたいな感じで。これをテキストファイルに保存し(list.txt)、次のように python スクリプトを実行する。これにより文字を書き込むための書き込みフォームを生成する。

python3 handfontgen/formgen.py -o zenkaku.pdf list.txt

するとこんな感じのPDFができあがる。
f:id:nixeneko:20160206100738p:plain
次のリンクから生成されたPDFが見られる。

2. 印刷して書き込む

1. で作ったPDFを印刷し、薄い青色の四角の中に文字を書き込む。
書き込んだ後はスキャンして画像データとして取り込む。

取り込んだデータはこんな風である。
f:id:nixeneko:20160206101911j:plain

3. フォント生成

Python スクリプトを次のように実行する。スキャンした画像ファイルは scanned 以下に保存したとする。 fontmetadata.xml にはフォントの設定を書いておく。

python3 handfontgen/fontgen.py -m fontmetadata.xml output.otf scanned/

実行してしばらく待つと output.otf が出力される。

f:id:nixeneko:20160206075343p:plain
Windows にちゃんとフォントとして認識された。

フォント生成スクリプト

スクリプト本体や必要なデータファイル、サンプル類をまとめて Github に上げた。
github.com

動作に必要なソフト・ライブラリ

Python ライブラリ

インストール・実行方法

ここでは Ubuntu にインストールして実行する方法を示す。開発自体は Windows 7Cygwin を使って行っていたので、 Windows でも動くと思うが特に解説はしない。

ソフト・ライブラリのインストール

端末を開いて、

sudo apt update
sudo apt upgrade
sudo apt install fontforge potrace zbar-tools libcairo2-dev python3-numpy \ 
python3-cairosvg python3-pypdf2 python3-pip libffi-dev
pip3 install qrcode
OpenCV3のインストール

必要なパッケージをインストール。

sudo apt install libopencv-dev build-essential checkinstall cmake pkg-config \
yasm libtiff5-dev libjpeg-dev libjasper-dev libavcodec-dev libavformat-dev \
libswscale-dev libdc1394-22-dev libxine2-dev libgstreamer0.10-dev \
libgstreamer-plugins-base0.10-dev libv4l-dev python3-dev python3-numpy \
libtbb-dev libqt4-dev libgtk2.0-dev libfaac-dev libmp3lame-dev \
libopencore-amrnb-dev libopencore-amrwb-dev libtheora-dev libvorbis-dev \
libxvidcore-dev x264 v4l-utils git

OpenCV をとってきてコンパイルし、インストールする。

git clone https://github.com/Itseez/opencv.git
cd opencv
git checkout 3.1.0
mkdir build
cd build
cmake -D CMAKE_BUILD_TYPE=RELEASE \
-D CMAKE_INSTALL_PREFIX=/usr/local \
-D BUILD_opencv_java=OFF -D WITH_IPP=OFF \
-D PYTHON_EXECUTABLE=/usr/bin/python3.4 ..
make
sudo make install
sudo sh -c 'echo "/usr/local/lib" > /etc/ld.so.conf.d/opencv.conf'

これにて必要なもののインストールは完了。

Github からフォント生成用のコードをとってくる

cd ~
git clone https://github.com/nixeneko/handfontgen.git

実行

ダウンロードしたフォルダに移動する。

cd ~/handfontgen

以下、カレントディレクトリが ~/handfontgen であるとする。

テキストファイルから書き込む用のPDFファイルの作成

PDF ファイルを生成する。サンプルデータとして使ったPDFの生成は次のようなコマンドを実行するとできる。

python3 handfontgen/formgen.py -o zenkaku.pdf sampledata/list_kana.txt sampledata/list_kigou.txt
python3 handfontgen/formgen.py -o hankaku.pdf -t resources/charbox_template_5-8-5_5-4-5.svg sampledata/list_ascii.txt
python3 handfontgen/formgen.py -o testkanzi.pdf sampledata/list_kanzi-test.txt

出力されたものが sampledata/pdf/ 以下に入っている。出来上がったPDFを印刷し、文字を書き込む。

スキャンした画像からフォントを生成する

サンプルとして、書き込んだ画像を sampledata/scanned_300dpi/ 以下に用意した。
サンプルのフォントを生成するには次のコマンドを実行する。

python3 handfontgen/fontgen.py -m sampledata/fontmetadata.xml tekitou.otf sampledata/scanned_300dpi/

これでしばらく待つと tekitou.otf が生成される。生成されたものが sampledata/otf/tekitou.otf である。

また、上ではSVGファイルを一時ファイルとして書き出しているのだが、文字を追加する際にいちいち全てを書き出していると時間がかかる。スキャン画像からフォントを生成する処理は、

  • SVGファイルの生成
  • SVGファイル群からフォントを生成

の2つの処理に分けることができる。これだと追加があった文字だけを処理できるので時間の節約になる場合がある。

python3 handfontgen/scanchars.py glyphs/ sampledata/scanned_300dpi/
python3 handfontgen/fontgenfromsvg.py tekitou.otf glyphs/ sampledata/fontmetadata.xml

出力されるフォントについては上の場合と変わらない。

何をやっているのか?: 自動生成の原理

0. 書き込みフォームの生成

四隅のマーカーが乗ったSVGの上に、一文字分の領域(これは別のSVGファイルで定義されている)を並べていく。
この際、指定された文字のリストから一文字ずつ文字を書き込み文字コードデータのQRコードを埋め込んでいる。さらに右下には一文字分の領域にマーカーで指定された部分の領域情報についてのQRコードを埋め込む。一ページ分ができたらPDFに変換する。これを指定された文字のリストが空になるまで繰り返す。

最後にPDFを1つのファイルにまとめる。

なお、文字幅についてはページごとのQRコードで指定しているため、半角と全角など幅がことなる場合にはシートを分ける必要がある。

1. 傾き補正

四隅のマーカーの中心を結んだ四角い領域を切り出す。

2. 1文字ずつに分割

  1. 左端と上端にあるマーカーの黒い部分を抽出し、そこで1文字分ずつに分割する。
  2. フォーム右下端にあるQRコードを zbar で読み取り、文字が書かれる領域のサイズを取得する。

3. 文字をSVGにする

1文字ずつの領域に切り分けられたそれぞれに対して処理を行う。

  1. 「┛」「┏」の形のマーカーをテンプレートマッチングにより位置を検出し、そのマーカーではさまれた四角形を切り出す。
  2. QRコードにより文字情報(ここでは文字のコードポイント)を取得する。
  3. 文字のコードポイントをファイル名として、 Potrace によってベクタ化しSVGとして書き出す。

4. SVGをもとにフォントを生成する。

  1. SVGファイルをリストアップする。
  2. SVGをそのファイル名で特定される文字のところにインポートしフォントとして出力するための Fontforge スクリプトを生成する。
  3. Fontforge でそのスクリプトを実行し、フォントを生成する。

所感

  • 今回は、サンプルとしてアップロードする画像ファイルを軽くしたかったので、300dpiでスキャンした画像を使用したが、 8×8mm は300dpiだと 94×94px であり、フォントの 1000×1000 のメッシュに比べると解像度が粗い。 600dpi でも試したが問題なく動いているようだった。フォントで表現できる最大の解像度でスキャンしようとすると 3200dpi 位となり、ファイルサイズはかなりの大きさになりそう。そこまで大きなものは試してないので動くかわからないが。
  • マーカー乗っけたりQRコード埋め込んだりしてるのは、最初に書き込みフォームの形を決めうちしたくなかったため、後工程で情報が取り出せるように埋め込んだというもの。
  • 一文字分の領域のテンプレートとなっているSVGファイルを編集すれば、文字を書く領域を別のサイズにした書き込みフォームが作れる。ただこのSVGファイルが72dpi基準で作られている(Adobe Illustrator)ので、Inkscape(90dpi)とかで編集しようとすると面倒そう。
  • 手書き文字を、特にアルファベットにおいて、同じ幅で並べるといささか奇妙に思える。プロポーショナルな出力ができるようにしたらよいのかもしれない。
  • ゴミに弱い。スキャン時についたゴミはフォントにそのまま残ってしまうので、SVG生成に回す前にゴミとりをしないといけない。ゴミとり機構を乗せるといいのかもしれない。
  • こうして作ったフォントをみるとベースラインがきれいに並ばないので、不恰好である。書き込みフォームにベースラインの表示を入れてもいいかもしれない。
  • コマンド一発でフォントが出来上がるとなんだか有りがたみがない……。