docker
Zinnia

手書き文字認識エンジン「Zinnia」をDockerコンテナ上で動かす

More than 1 year has passed since last update.

手書き文字認識エンジン「Zinnia」とは?

ZinniaはTaku Kudoさんが作成された手書き文字認識エンジンです。

説明には"機械学習アルゴリズム SVM を用いたポータブルで汎用的な オンライン手書き文字認識エンジン"と書かれています。   

オンライン認識とオフライン認識の違いについてはこちらをご覧ください。

Zinniaを動かしたい理由

  • 最近スマホ・タブレットでよく使われている手書き文字認識を使って遊びたい
  • けどAPIは有料ばっかりで使いたくない...
  • あ、Zinniaはタダで使える、これにしょう!!!

Zinniaについて参考にしたサイトなど

Docker上で動かす理由

  • よくわからないエラーが起きたらいやだなぁ

Dockerのイメージを作る

今回はubuntu 14.04のイメージをもとに環境構築します。

# Dockerfile
FROM ubuntu:14.04

# コンパイルに必要なもの(build-essential)とwgetのインストール
RUN apt-get update && apt-get install -y build-essential wget

# homeディレクトリで作業します
WORKDIR /home

# zinnia本体と認識モデルの取得
RUN wget 'http://jaist.dl.sourceforge.net/project/zinnia/zinnia/0.06/zinnia-0.06.tar.gz'
RUN wget 'http://jaist.dl.sourceforge.net/project/zinnia/zinnia-tomoe/0.6.0-20080911/zinnia-tomoe-0.6.0-20080911.tar.bz2'

# 解凍
RUN tar xf zinnia-0.06.tar.gz
RUN tar xf zinnia-tomoe-0.6.0-20080911.tar.bz2

# /usr/local/libにパスを通す
ENV LD_LIBRARY_PATH=/lib:/usr/lib:/usr/local/lib

# インストール
RUN cd zinnia-0.06 && ./configure && make && make install
RUN cd zinnia-tomoe-0.6.0-20080911 && ./configure && make && make install

# コンテナが停止しない呪文
CMD ["/bin/bash"]

Dockerfileというファイル名で以上をコピペしたら保存して、

ファイルがあるディレクトリでイメージを作成。

$ docker build -t zinnia-tomoe .

Dockerコンテナの起動

とりあえず先ほど作ったイメージで、コンテナを起動します。

$ docker run -ti -p 5000:5000 --name zinnia zinnia-tomoe

オプションは、読み書きできる形で、コンテナを中(port: 5000)と外(port: 5000)でつないで、

コンテナの名前をzinniaにして、先ほど作ったイメージ(zinnia-tomoe)で起動するというものです。

Bottleを使ってWebサービスとして使えるようにしよう!! (準備編)

BottleはPythonの軽量Webフレームワークです。

これを使って最終的には、Ajaxを使った手書き文字認識みたいなのを作ります。

なので、ZinniaのPython APIを今後は使っていきます。

それでは、コンテナ内で以下のコマンドを打って、環境構築をしましょう。

# Python環境の構築(たぶん使うの一部だけど...)
apt-get install -y python-dev python-setuptools python-numpy python-scipy

# pipをインストール
$ easy_install pip

# Flaskをインストール
$ pip install bottle

次に、ZinniaのPython APIをインストールします。

$ cd /home/zinnia-0.06/python/
$ python setup.py install

Bottleを使ってWebサービスとして使えるようにしよう!! (サーバー側の色々編)

homeディレクトリにBottleAppという名前でディレクトリを作って、そこで作業します。

$ mkdir /home/BottleApp
$ cd /home/BottleApp

では、/home/BottleApp/BottleApp.pyにプログラムを書いていきます。

#!/usr/bin/python
# -*- coding:utf-8 -*-

# Bottle, zinnia, jsonのライブラリをインポート 
from bottle import route, run, post, request, hook, response
import zinnia
import json
from pprint import pprint

# 
# レスポンスヘッダの付与
@hook('after_request')
def enable_cors():
    response.headers['Access-Control-Allow-Origin'] = '*'

# 
# POSTでリクエストを受ける
@route('/zin', method='POST')  # or @post('/post')
def zinpost2():
    canvasWidth = request.forms.get("canvasWidth")
    canvasHeight = request.forms.get("canvasHeight")

    print canvasWidth
    print canvasHeight

    try:
        # 認識したい文字の情報を入れるオブジェクト
        s = zinnia.Character()
        # 文字認識のための分類器のオブジェクトと認識モデルの読み込み
        r = zinnia.Recognizer()
        r.open("/usr/local/lib/zinnia/model/tomoe/handwriting-ja.model")
        # 初期化と描画サイズの設定
        s.clear()
        s.set_width(int(canvasWidth))
        s.set_height(int(canvasHeight))
        for stroke in json.loads(request.forms.get("history")):
            print stroke["numofStroke"]
            print stroke["selectedcolor"]
            print stroke["_lineWidth"]
            for point in stroke["points"]:
                s.add(int(stroke["numofStroke"]),int(point[0]),int(point[1]))
                print point[0]," : ",point[1]

        # 上位10件の認識結果を取得する
        result = r.classify(s, 10)
        size = result.size()
        resultValue = []
        resultScore = []

        # 認識した文字はvalueに、確率はscoreに入っている
        for i in range(0, (size - 1)):
            print "%s\t%f" % (result.value(i), result.score(i))
            resultValue.append(result.value(i))
            resultScore.append(result.score(i))

        json_data = {
            "resultValue": resultValue,
            "resultScore": resultScore
        }

        print resultValue
        print resultScore

        return json_data

    except RuntimeError, e:
        print "RuntimeError: ", e,
        return "RuntimeError"

run(host='0.0.0.0', port=5000, debug=True)

あとは、

python BottleApp.py

で実行すれば、サーバーが5000番ポートで起動します。

dockerコンテナの起動時に"-p 5000:5000"をしていたので,

ホストマシンの5000番ポートにリクエストを投げると、認識結果が帰ってきます。

html canvasを使って文字を手書きし、リクエストを投げる

準備中...