ひょんな理由で tesseract の使い方を知る必要に迫られたので、簡単に調査。取り急ぎ、次の情報が得られることが目標。
- 認識された文字(≠単語)のテキストデータ (UTF-8)
- それらの位置情報(左上点の座標と幅と高さ)
もちろん、プログラム的にこれらの情報を分析等に使いたいので、Python から tesseract を使う場合によく使われている pyocr もインストールして、これを使って上記を取り出してみる。
tesseract とは
tesseract は Hewlett-Packard で開発された OCR エンジンで、2005 年にオープンソース化された後、2006 年からは Google が開発を進めている。本日2019年6月9日の最新バージョンは 4.0。
なお Python から tesseract を使う場合、pyocr というパッケージが有名なもよう。こちらも今回は使ってみる。
導入方法
4.0 の Windows バイナリは公式で配布されておらず、Ubuntu 18.04 では apt でインストールできるとのこと。そのため Windows 環境でのお試しならば WSL で Windows 上に Ubuntu 18.04 環境を作り、そこに apt でインストールするのが(自分的には)楽だった。
$ apt install tesseract-ocr-jpn
tesseract 自体は多言語対応しており、各言語向けの学習データも apt でインストールできる。上記コマンドは日本語用の学習データをダウンロード対象に指定しており、その結果この依存関係に設定された tesseract 本体も同時にインストールしてくれる。なお Python から tesseract を使うのに便利なパッケージ pyocr
についても apt でインストールできる (python-pyocr
と python3-pyocr
)。OS 標準の Python 環境で使いたい場合はこちらもインストールしておくと良いだろう。Anaconda 等で非標準の Python 環境を作っている場合は普通に pip install pyocr
しておく。
tesseract の動作確認(コマンドを使用)
最低限の動作確認として、tesseract コマンドで OCR 処理を実行してみる。
tesseract をコマンドラインインタフェースで使う場合、もっとも単純な方法は次のように文字認識をかけたい画像ファイルと、結果のファイル名をコマンドラインに指定する:
$ tesseract image.tiff output -l jpn # output.txt が生成される
出力先ファイル名の拡張子は出力形式に応じて自動的に補完されるので指定不要らしい。標準形式は .txt で、認識された文字列が平文テキストで格納されただけのもの。何かの分析や他のプログラムに接続する場合、もっと情報量の多い TSV 形式などにすると良いだろう。例えば次の画像 "image.png" を認識した結果を TSV に出力する例は、次のようになる。
$ tesseract image.png output -l jpn tsv $ column -ts $'\t' output.tsv level page_num block_num par_num line_num word_num left top width height conf text 1 1 0 0 0 0 0 0 467 140 -1 2 1 1 0 0 0 62 64 346 48 -1 3 1 1 1 0 0 62 64 346 48 -1 4 1 1 1 1 0 62 64 346 48 -1 5 1 1 1 1 1 62 77 190 32 92 tesseract 5 1 1 1 1 2 261 66 66 46 93 を 5 1 1 1 1 3 328 64 80 46 94 試す
うん、きっちり認識できている…と思いきや、画像と座標を照らし合わせると「を」と「試す」の切れ目が不自然な位置に来ているね。「言」と「式」の間に両単語の切れ目があると認識されているようだ。まあ、ともあれ。インストールした tesseract が動くことは確認できたので、良しとしよう。
なお最後の引数に指定した tsv
は tesseract のインストール先に置かれた設定ファイルの名前だったりする。その中には KEY=VALUE
の形で設定値が並んでおり、設定ファイルを介さずともコマンドラインオプション -c
を使えば同じように設定値を指定できる。たとえば文字単位での認識結果を出力する設定ファイル makebox
の内容は tessedit_create_boxfile=1
とだけ書いてあるので、次のようなコマンドラインで実行すれば同じ効果を得ることができる:
$ tesseract image.png output -l jpn -c tessedit_create_boxfile=1 $ column -ts' ' output.box t 62 32 77 63 0 e 80 31 97 57 0 s 106 32 119 57 0 s 127 32 141 57 0 e 148 31 161 57 0 r 176 32 188 57 0 a 191 32 210 57 0 c 216 31 234 57 0 t 237 32 252 63 0 を 261 28 326 74 0 試 328 30 358 76 0 す 377 30 408 73 0
続いてプログラム的な処理につなげるべく Python からの呼び出しを試してみよう。
pyocr を通した利用
何はともあれ pyocr を import する。また画像のロード用に Pillow も import しておく。
>>> import pyocr >>> from PIL import Image
pyocr は実行環境にインストールされた OCR ツール類をスキャンしてリストアップする pyocr.get_available_tools()
関数を提供している。最初はこれで tesseract が認識されていることを確認しておくと良さそうだ。
>>> tools = pyocr.get_available_tools() >>> len(tools) 2 >>> tools[0].get_name() 'Tesseract (sh)' >>> tools[1].get_name() 'Tesseract (C-API)'
ちなみに get_available_tools()
が返しているのは Python の module で、上記の例では一つ目の tool として tesseract コマンド実行で連携する pyocr.tesseract
が、二つ目の tool として libtesseract の API 利用で連携する pyocr.libtesseract
が返ってきている。これらの間には機能差があるため、場合によって使い分けが必要になると思われる。また、たとえば tesseract コマンドを必ず使うのであれば get_available_tools()
を使わずに、直接 tool = pyocr.libtesseract
などとしても良い。
さて、文字認識を実行するには上記のように取得したモジュールの image_to_string()
を呼べばよい。この関数には、OCR を実行したい画像データを指定するほか、認識に使用する言語、領域の切り出し方式(?)を指定する。ここでは pyocr.tesseract(コマンド連携版)を使い、当初の目的通り文字単位での切り出しを試してみる。
>>> ocr = pyocr.get_available_tools()[0] # または ocr = pyocr.tesseract >>> im = Image.open("image.png") >>> builder = pyocr.tesseract.CharBoxBuilder() >>> char_boxes = ocr.image_to_string(im, lang="jpn", builder=builder) >>> len(char_boxes) 12 >>> "|".join(box.content for box in char_boxes) 't|e|s|s|e|r|a|c|t|を|試|す' >>> for box in char_boxes: ... # box.position は左下を原点とした ((min-x, min-y), (max-x, max-y)) らしい。 ... # ここでは左上を原点とした x, y, width, height に変換してみる ... x = box.position[0][0] ... y = im.height - box.position[1][1] ... width = box.position[1][0] - x ... height = im.height - box.position[0][1] - y ... print("\t".join([ ... box.content, # 文字 ... str(x), str(y), str(width), str(height), ... str(box.confidence), # 確信度 ... ])) ... t 62 77 15 31 0 e 80 83 17 26 0 s 106 83 13 25 0 s 127 83 14 25 0 e 148 83 13 26 0 r 176 83 12 25 0 a 191 83 19 25 0 c 216 83 18 26 0 t 237 77 15 31 0 を 261 66 65 46 0 試 328 64 30 46 0 す 377 67 31 43 0 >>>
なお、単語単位であれば pyocr.builder.WordBoxBuilder など「特定の OCR エンジンに依存しない」オブジェクトが用意されているので、これらを使う方が良いだろう。文字単位での切り出しは pyocr.tesseract のみサポートされているらしく、それ用の実装クラスを上記の例では明示指定している。
座標系が変わっていたり、確信度が得られなかったり、といった点で少し注意は要るけれど、これで使えそうだ。