AndroidでTesseractを使ってみた

http://code.google.com/p/tesseract-android-tools/ を使うとAndroidからでも簡単にOCRれるみたいなので、夏休み中で時間もあることだし試してみようかと。

ビルドの仕方はREADMEに書いてある通りに以下のようにすればOK

cd <project-directory>
wget http://tesseract-ocr.googlecode.com/files/tesseract-3.01.tar.gz
wget http://leptonica.googlecode.com/files/leptonica-1.68.tar.gz
tar -zxvf tesseract-3.01.tar.gz
tar -zxvf leptonica-1.68.tar.gz
rm -f tesseract-3.01.tar.gz
rm -f leptonica-1.68.tar.gz
mv tesseract-3.01 jni/com_googlecode_tesseract_android/src
mv leptonica-1.68 jni/com_googlecode_leptonica_android/src
ndk-build
android update project --path .
ant release

でハマりやすいのが、学習データ的なものがないので http://code.google.com/p/tesseract-ocr/ の /tessdata から適切なディレクトリに配置しておく必要がある点。これを忘れるとSEGVしまくります。


一応、ギャラリー、カメラから読み込むサンプルを作ってgithubにあげておいた。
https://github.com/komamitsu/Android-OCRSample

肝心の精度は、ちょっとこのまま使うにはナイーブだな〜という感じ。

OCatraをいろいろ直したり、ベンチマークとってみたり

komamitsu/OCatra · GitHub のkeepaliveまわりのバグとかを直したり、モジュール名を変更したりしました。

Eventモジュールを使ってすっきり書いた方が良さげだなぁとか思っているのですが、現状そんなにややこしい制御をしていないので、まぁいいかと。

あとついでに、thin上でSinatraを動かしたやつと、abでrpsを比べてみました (-c 200 -n 4000)。

1st 2nd 3rd 4th Ave. σ
OCatra (byte) 3089 3197 1761 3415 2865 748
OCatra (opt) 4288 1809 6120 3920 4036 1768
Sinatra + thin 1561 1613 1595 1557 1581 27

bytecode版とnative版でともにSinatra + thinよりも速いのですが、測定値にばらつきがありました。99%のリクエストは一瞬なんですが、1%未満でレスポンスが遅くなるみたい。ちょっと気になるな〜

OCatraを短くかけるように修正

SinatraっぽいOCatraを書いてみた - komamitsu.log で作ったOCatraですが、もうちょっとすっきり書けるように修正。

open Ocatra
open HttpCommon
open HttpCommon.HttpContent

let _ =
  get "/" (fun r -> say (TextPlain "Hello, World (GET)") ());

  post "/" (fun r -> say (TextPlain "Hello, World (POST)") ());

  get "/givemeyournameandage" (fun r ->
    say (
      TextHtml (
        "<html><head><title>hello " ^ r ++> "name" ^ "</title></head>" ^
        "<body><h3>you are " ^ r ++> "age" ^ " years old.</h3></body></html>")
    ) ()
  );

  run ()

SinatraっぽいOCatraを書いてみた

先日、やっつけのWebサーバーを書く際にRubySinatraで書いてみたのですが、「簡単に書けて良いな〜」と思ったので、OCamlでもそれっぽいものを適当に作ってみました。

komamitsu/OCatra · GitHub

現状はこんな感じでかけます:

open Ocatra
open HttpCommon
open HttpRequest
open HttpResponse

let _ =
  get "/" (fun req ->
    create_response (Some (HttpContent.TextPlain "Hello, World (GET)")) ()
  );

  post "/" (fun req ->
    create_response (Some (HttpContent.TextPlain "Hello, World (POST)")) ()
  );

  get "/givemeyournameandage" (fun req ->
    let name = HttpParam.find req.param "name" in
    let age = HttpParam.find req.param "age" in
    create_response (Some (
      HttpContent.TextHtml (
        "<html><head><title>hello " ^ name ^ "</title></head>" ^
        "<body><h3>you are " ^ age ^ " years old.</h3></body></html>")
    )) ()
  );

  run ()

「それっぽい感じで書けそうかな?」というのを確認した段階なので、肝心の「短くかけるか?」というのはあまり追求してない... 後で暇になったら頑張ろうかなと。

あと、ソースコードの配置とかMakefileとかSignature切ってないとかが、やっつけ感溢れるというか適当なので、これも暇になったら頑張りたい。

あと、OCamlのライブラリ依存を何とかするのが面倒で苦手なので、品質よりも簡単に使えること(できるだけ標準で用意されている環境で使いたい)優先で、HTTPサーバー的なところは自前で実装しています。この辺も結構適当にやってるので暇になったら頑張りたい。

テトリスっぽいやつに自動保存機能つけた

テトリスっぽいゲーム作った - komamitsu.log で書いた Not Found なんですが、アプリを終了させると(というか画面を閉じるだけで)、次はまた最初からになってしまうのが嫌だったので自動的に保存する機能を付けました。で、アプリスタート時に続行可能に。

テトリスっぽいゲーム作った

https://play.google.com/store/apps/details?id=com.komamitsu.ketris

以前、ちょっと時間が空いていた頃、SurfaceViewの練習がてら適当にブロックを書いて動かしてたらテトリスになったので、ちょこちょこと手を加えてそれっぽくしてリリースしました。

途中で幾つか革新的なあいであが浮かんで来たのですが、実装してみてチューニングしてみて結局使い勝手が良くないなぁということで没になり、最終的にごく普通のテトリスになってます。というかそもそもテトリス良く知らないので間違ってるかも...

基本的に、いざというときの自分の暇つぶしに使えるようにしたいなぁと。で、そういう状況は大体がAndroidの電波が届かない地下鉄に乗っているときで、自分的にはそういうとき片手で操作できると嬉しいので、その辺の操作感まわりはちょっと気にしました。

あと、好奇心半分お小遣い目当て半分で、広告を入れてみています。でもゲーム画面が小さくなってちょっと嫌だなぁとか、それだけのためにuse-permission増やす(INTERNETとか)のも嫌だなぁという感じがしているのでどうにかしたいですねぇ。

error: gnutls_handshake() failed: A TLS packet with unexpected length was received

とあるgit repositoryからgit cloneしようとしたら以下のエラーが出てしまいました。

error: gnutls_handshake() failed: A TLS packet with unexpected length was received

で、どうしようか、というメモ。


まず、どうやらgnutlsがエラーを出しているみたいなので、念のため確認と絞り込み。やはりエラーとなる。

$ gnutls-cli -p 443 hogehoge.com
Resolving 'hogehoge.com'...
Connecting to '123.231.213.123:443'...
*** Fatal error: A TLS packet with unexpected length was received.
*** Handshake has failed
GnuTLS error: A TLS packet with unexpected length was received.


じゃあサーバー側の致命的な問題なのか?ということでopensslを使ってみる。こちらはエラーにならない。

$ openssl s_client -port 443 -host hogehoge.com
    :
(エラーじゃないっぽい内容)


git cloneしたときにどういった経路でgnutlsが使われているのか知りたいので、GIT_TRACE=1で。

$ GIT_TRACE=1 /usr/bin/git clone https://hogehoge.com/git/foobar.git
trace: built-in: git 'clone' 'https://hogehoge.com/git/foobar.git'
Cloning into foobar...
trace: run_command: 'git-remote-https' 'origin' 'https://hogehoge.com/git/foobar.git'
       :

あと、ltraceを使ってみたときに、/usr/lib/git-coreを触っていたのを見てたので、/usr/lib/git-core/git-remote-httpsを使っているのでは?と何となく思うので、確認

$ ldd /usr/lib/git-core/git-remote-https 
     :
libcurl-gnutls.so.4 => /usr/lib/x86_64-linux-gnu/libcurl-gnutls.so.4 (0x00007f32ee49c000)
     :
libgnutls.so.26 => /usr/lib/x86_64-linux-gnu/libgnutls.so.26 (0x00007f32ecee4000)
     :

ということで、git cloneからgnutlsのエラーまでが繋がった。


で、gitの最新版のソースコードhttps://github.com/git/git.git から落としてきて、configure -hすると、--with-openssl と --with-curl があったので付けてみた。その時、libcurl-devっぽのが無さそうで怒られたので、libcurl-openssl-devを入れた。

$ git clone https://github.com/git/git.git
$ cd git
$ autoconf
$ sudo aptitude install libcurl4-openssl-dev
$ ./configure --with-openssl --with-curl
$ make
$ sudo make install

で、こっちを使ったらうまく行った。