Python
python2.7
OCR

Pythonで日本語OCRを行うときのメモ

More than 1 year has passed since last update.

フリーのtesseractというOCRを使って、pythonで日本語のOCRを行うまでに行った手順をまとめます。

環境

  • Ubuntu 14.04
  • Python 2.7

インストール

tesseractをインストールします。

インストール方針

インストールの方法には、
1. apt-getでインストール
2. ソースからビルド、インストール

の二つがあります。
1のapt-getでインストールできるバージョンは3.0.3です。
tesseractで日本語を扱うには、日本語で訓練されたデータ(jpn.traindata)が必要です。
これは自分でダウンロードしてくる必要があるのですが、ネット上で見つけられたものはver3.0.4のものだけです。3.03でこのデータを使おうとしても、うまくいかず、こんなエラーが出ます。

read_params_file: parameter not found: allow_blob_division

こちらのかたのように、traindataを編集して3.0.3で使うこともできますが、そのために必要なcombine_tessdataというコマンドはapt-getインストールでは使えません。そのため、現状で日本語でやりたかったら、ソースでインストールする他ないかと思われます。

基本的に、公式のコンパイルインストールのページを参考に、tesseract3.0.4をインストールします。

https://github.com/tesseract-ocr/tesseract/wiki/Compiling

依存関係インストール

$ sudo apt-get install autoconf automake libtool
$ sudo apt-get install libpng12-dev
$ sudo apt-get install libjpeg62-dev
$ sudo apt-get install libtiff4-dev
$ sudo apt-get install zlib1g-dev
$ sudo apt-get install libicu-dev      # (if you plan to make the training tools)
$ sudo apt-get install libpango1.0-dev # (if you plan to make the training tools)
$ sudo apt-get install libcairo2-dev   # (if you plan to make the training tools)

Laptonicaインストール

Laptonicaという画像ライブラリが必要のようです。
ソースをダウンロードページからダウンロード、解凍します。tesseract3.0.4のインストールには、最低でもLaptonica1.71が必要なので、最新の1.7.3をインストールします。

# 解凍
gzip -dc leptonica-1.73.tar.gz |tar xvf -
cd leptonica-1.73

# makeとか
$ ./configure
$ make
$ sudo make install

tesseractインストール

基本的にこれどおりやります。

3.0.4のソースをこちらから取得

# 解凍、移動
$ unzip 3.04.zip 
$ cd tesseract-3.04

# ライブラリパスを通しておく
$ export -p LD_LIBRARY=$LD_LIBRARY:/usr/local/lib

# インストール
$ ./autogen.sh
$ ./configure
$ sudo make          # ここだけsudoにした。laptonicaが見当たらなかったので。
$ sudo make install
$ sudo ldconfig

日本語ファイルの取得、設定

こちらの言語データセットから、jpn.traindataという日本語のものをダウンロードし、こちらに置きます。

/usr/local/share/tessdata/

そして、このフォルダのパスを設定しておきます。

export TESSDATA_PREFIX="/usr/local/share/tessdata/tessdata/

動作確認

インストールがうまくいっていれば、コマンドライン上でOCRの実行が可能になっているはずです。
試しにこんな画像を日本語OCRにかけてみます。
ocr_test.png

tesseract ocr_test.png out -l jpn

と実行すると、out.txtというファイルに結果が書き込まれます。

out.txt
笑顔が一番 ! れにちや ん

小さい「ゃ」が大きい「や」になってますが、概ね認識できています。
小文字の概念は他の英語とかにないので、そこは難しいのでしょうか。

pyocrの導入

pythonで使えるように、pyocrというラッパーライブラリを使います。

インストールは、

$ pip install pyocr

で終わりです。

しかしながら、ソースからインストールしたtesseractに対応しておらず、テスト用に以下のerror.pyを実行させると、うまくいきません。

error.py
import pyocr
tools = pyocr.get_available_tools()
Traceback (most recent call last):
  File "error.py", line 12, in <module>
    tools = pyocr.get_available_tools()
  File "/usr/local/lib/python2.7/site-packages/pyocr/pyocr.py", line 74, in get_available_tools
    if tool.is_available():
  File "/usr/local/lib/python2.7/site-packages/pyocr/libtesseract/__init__.py", line 152, in is_available
    version = get_version()
  File "/usr/local/lib/python2.7/site-packages/pyocr/libtesseract/__init__.py", line 179, in get_version
    upd = int(version[2])
ValueError: invalid literal for int() with base 10: '02dev'

エラーを読むと、"02dev"という文字列をintに変換しようとして怒られています。ソースからインストールしたバージョンが、tesseract 3.04.02devで、devパッケージを想定していないようです。
なので、このソースを変更してあげます。

変更するソースは、virtualenv使用の場合は、適当に置き換えてください。

/usr/local/lib/python2.7/site-packages/pyocr/libtesseract/__init__.py
    if len(version) >= 3:
        upd = int(version[2].replace('dev', ''))
        # upd = int(version[2])

これでうまくいくはずです。

OCRを試してみる

色々なOCRの仕組みがあるので、試してみます。
この画像で試してみます。

mlct-14-638.jpg

Text

もっともシンプルなOCRです。画像から文字を読み取り、文字列として返します。

import pyocr
import pyocr.builders
import argparse
from PIL import Image

parser = argparse.ArgumentParser(description='tesseract ocr test')
parser.add_argument('image', help='image path')
args = parser.parse_args()

tools = pyocr.get_available_tools()

if len(tools) == 0:
    print("No OCR tool found")
    sys.exit(1)
# The tools are returned in the recommended order of usage
tool = tools[0]

res = tool.image_to_string(Image.open(args.image),
                           lang="jpn",
                           builder=pyocr.builders.TextBuilder(tesseract_layout=6))

print res

結果

機鵬習の卿
テス 卜ヲータ
扉 叫隣 史習給果
縄
隻デーヮ ^~璽属~ 慣賭史習 バ『メーヮ

難しい単語のせいか、結果はひどいです。

WordBox

単語がどこにあるのか、boxを返してくれます。openCVで結果を可視化してみます。(openCVはこちらでインストール)

import pyocr
import pyocr.builders
import argparse
import cv2
from PIL import Image

parser = argparse.ArgumentParser(description='tesseract ocr test')
parser.add_argument('image', help='image path')
args = parser.parse_args()


tools = pyocr.get_available_tools()

if len(tools) == 0:
    print("No OCR tool found")
    sys.exit(1)
# The tools are returned in the recommended order of usage
tool = tools[0]


res = tool.image_to_string(Image.open(args.image),
                           lang="jpn",
                           builder=pyocr.builders.WordBoxBuilder(tesseract_layout=6))

# draw result 
out = cv2.imread(args.image)
for d in res:
    print d.content
    print d.position
    cv2.rectangle(out, d.position[0], d.position[1], (0, 0, 255), 2)

cv2.imshow('image',out)
cv2.waitKey(0)
cv2.destroyAllWindows()

Screenshot from 2016-07-20 15:12:12.png

機鵬習の卿
((226, 12), (412, 37))
テス
((255, 138), (278, 148))
卜ヲータ
((283, 137), (326, 148))
扉
((397, 149), (406, 159))
叫隣
((411, 149), (430, 159))
史習給果
((477, 148), (523, 159))
縄
((165, 170), (199, 181))
隻デーヮ
((115, 202), (156, 212))
^~璽属~
((210, 196), (247, 220))
慣賭史習
((297, 202), (343, 213))
バ『メーヮ
((390, 203), (438, 212))

領域はそこそことれていますが、認識した単語は相変わらずひどいです。

LineBox

WordBoxによるものは、単語ごとでしたが、LineBoxでは、同じ行にある単語をまとめてくれるようです。

先ほどのWordBoxのソースを一部だけ変えます
WordBoxBuilder→LineBoxBuilder にするだけです。

res = tool.image_to_string(Image.open(args.image),
                           lang="jpn",
                           builder=pyocr.builders.LineBoxBuilder(tesseract_layout=6))


結果
Screenshot from 2016-07-20 15:34:57.png

機鵬習の卿
((226, 12), (412, 37))
テス 卜ヲータ
((255, 137), (326, 148))
扉 叫隣 史習給果
((397, 148), (523, 159))
縄
((165, 170), (199, 181))
隻デーヮ ^~璽属~ 慣賭史習 バ『メーヮ
((115, 196), (438, 220))

この画像は同じ行にまとめてくれなくてもよいですが、複数行の文章のときに使えそうです。

tesseract_layoutについて

それぞれのbuilderで、tesseract_layout=6
と設定していました。この数字は、どのような方針で画像に対してOCRを行うか設定するものらしく、

こちらのかたがまとめてくださっています。
http://tanaken-log.blogspot.jp/2012/08/imagemagick-tesseract.html

pagesegmode values are:
0 = Orientation and script detection (OSD) only.
1 = Automatic page segmentation with OSD.
2 = Automatic page segmentation, but no OSD, or OCR
3 = Fully automatic page segmentation, but no OSD. (Default)
4 = Assume a single column of text of variable sizes.
5 = Assume a single uniform block of vertically aligned text.
6 = Assume a single uniform block of text.
7 = Treat the image as a single text line.
8 = Treat the image as a single word.
9 = Treat the image as a single word in a circle.
10 = Treat the image as a single character.

学習データについて

見ての通り、既存の日本語データを使うと、精度がよろしくないようです。
自分で学習データを作成すれば、もっとまともになるとのことです。

http://hadashi-gensan.hatenablog.com/entry/2014/01/15/135316

おまけ Google Cloud Vision

Google Cloud Vision API のTEXT_DETECTを利用すると、こんな感じになります。

Screenshot from 2016-07-21 11:28:43.png

機械
学習
の
流れ
テスト
データ
予
測
器
学習
結果
前
処理
教師
データ
生
データ
機械
学習
パラメータ
L
理
A

やっぱり精度いいですね。そんなにたくさんリクエストを投げず、手軽に処理したい場合は、Vision API使った方がいいですね。