2014/07/15

Foursquare/Swarmのチェックインを提案 "beeWear" を公開しました (Android Wearにも対応)

先週、"beeWear"(びーうぇあ)というAndroidアプリケーションを公開しました。
位置情報を用いたSNS "Foursquare" および "Swarm" のクライアントです。

特徴は "チェックインの提案" です。

過去にチェックインしたことのあるベニューに近づくと...
「チェックインしますか?」と自動的に提案してくれます。
バッテリの消費についてご心配されるかもしれませんが、後述のとおり大丈夫です。初期設定ではGPS測位を使いません。
※省電力かつ高精度なWi-Fi測位を十分に活用するために、Android 4.3以降ではWi-Fi設定の"スキャンを常に実行する"を有効にする事を強く推奨します。ホットスポットなどに不用意に接続することなくスキャンのみを行えます。


beeWearによる提案が表示されたところ。
尚、これは大学の研究室の非公式マスコットキャラクターですが、
本アプリは大学での研究テーマと関係ありません。あしからず。

beeWearでは無駄のない提案を行うために工夫を取り入れています。

  • Fused Location による省電力かつ高精度な位置情報の取得
    Google Play Serviceによって、Wi-Fiや基地局、自律測位を組み合わせ。他のアプリが取得した位置情報を利用することもでき、効率的。
    I/O 2013の資料によると1%/毎時のバッテリ消費で済むとか。
  • Activity Recognition によるユーザの行動状況の認識
    Google Play Service によって、歩行中/移動中などを認識。
    例えば、電車に乗車している間は提案を抑制します。
  • 機械学習によるチェックイン傾向の学習
    時間帯を考慮し、どのベニューにどの順序でチェックインするか。
  • 位置情報ジャンプのキャンセル
    明らかにありえない距離のジャンプが発生した場合は提案を控えます。
    Wi-Fi測位などは精度値が全く信用できない場合があるからです。
  • チェックイン履歴を基にした位置情報の誤差補正
    過去のチェックインから位置情報の誤差を補正し、提案の質を向上。
    Foursquare側でも何らかの補正をしていますが、独自でも行います。
  • 他の端末やアプリによるチェックインの反映
    他の端末やアプリからチェックインした場合にプッシュを用いて認識。
    学習に反映するほか、必要に応じて提案を取り下げます。

などなど。まだ試験的な部分も少なくありませんが、今後も改良を重ねていきます。

提案が必要無いベニューは "提案しない" を選べば、次から提案しません。
(逆に、"提案しない"としたベニューを再び提案してほしい場合は、メイン画面からそのベニューを長押ししてください。)

尚、バックグラウンドでの周辺ベニュー検索は、数日ごとにベニュー履歴を取得してデータベースを端末上に構築しています。従って都度通信は発生しません。

次に "Android Wearへの対応"です。

今月上旬にAndroid Wear搭載スマートウォッチが発売されましたが、
beeWearは先々月から開発開始しており、当初から対応を考慮していました。

もちろん、beeWearはスマートフォン/タブレットだけでもご利用いただけます。
しかし更にAndroid Wear搭載スマートウォッチがあれば...
スマートフォンやタブレットはカバンの中にしまっていても構いません。
Android Wear搭載スマートウォッチから、サクッとチェックインできます。

Android Wear上でチェックインの提案が表示されたところ。

また、過去に訪問したベニューを自動的に提案するだけでなく、
Android Wear上で新たなべニューを検索することもできます。



大切にしているのは、チェックインをサクッと行えることです。

個人的にですが、Foursquareを楽しんできたユーザの一人として、初期から続いてきた楽しさは"チェックイン"という行為にあるのかもなぁ...と思っています。
好きなお店や初めてのお店で、ときには友人とチェックインするという行為です。
それを純粋に楽める軽快さを大切にしたいと考えています。

Twitterで見かけたから合流しようっ!なんていう使い方もありますよね。
ご安心ください。Foursquare/Swarm上でTwitterやFacebookと連携設定されている方は、beeWearでも連携投稿ができます。非公開チェックインも可能です。

共有範囲("公開"、"非公開"、"公開 (+Twitter)"...)はベニュー毎に記憶させることも可能です。
つまり...
  • 自宅最寄り駅では非公開チェックイン
  • 学校では公開チェックイン
  • お気に入りのお店では公開チェックイン + Twitter連携
ということができます。
(※ Android Wearでのチェックインの際には共有範囲が選べませんので、デフォルトの設定か、ベニュー毎に記憶した共有範囲が使用されます。)

スマートフォン/タブレット向けのメイン画面からチェックインすると"共有範囲"を選択できます。
ここで選んだ共有範囲は、ベニューごとに記憶されます。

もし宜しければ、beeWear (びーうぇあ) を一度お試し下さい。もちろん無料です。
フィードバックもお待ちしております!

Get it on Google Play
Android 2.3以降のスマートフォン/タブレットでご利用いただけます。
(但し、Android Wearスマートウォッチとの連携される場合は、Android 4.3以降が必要です。)

[2014/07/07 追記]
v1.2.0 にはAndroid Wear上での通知に関する重大な不具合がありました。
昨日公開した v1.2.1で修正済みです。


p.s.
余談ですが、"beeWear"の"Wear"はわかるけど、"bee"って?と聞かれます。
当初から、Swarm対応のアプリとして開発を行っていたのですが、アプリ名についてSwarmの運営者に確認したところ、"Swarm"という言葉を使うのは商標的に宜しくないということでした。Swarm(ハチの群れ)から連想して...ミツバチのような賢さという意味も込めて"bee"にしました(笑)

さて本アプリを公開するにあたり友人にはテスターとしてご協力いただきました。
未完成のアプリであったにもかかわらず、実際の生活で毎日テストしてくださり フィードバックをいただきました。あらためて感謝申し上げます。ありがとうございました。

また、本アプリにはApache Licenseが適用されたオープンソースライブラリを使用、改変しております。本アプリではライセンスに従って条項文章を同梱しています。ライブラリ開発者の皆さまに感謝申し上げます。

2014/05/24

PidoraでCLIからBluetooth SPP接続しようとしたらbluez-simple-agentがない件

Raspberry PiのPidoraでコマンドラインからBluetooth SPPで接続しようとしたところ、bluezパッケージ(bluez4)をインストールしてあるにもかかわらず、
bluez-simple-agentなどのコマンドがないということで引っかかってしまいました。
私のRPiのPidoraはFedora18ベースのバージョンなのですが、どうもリポジトリにある bluez4 のパッケージに、これらのコマンドが含まれていないようです。(たぶん。)

Bluezのソースコードからビルドすれば良いのですが、
今ビルドするだけのために必要なパッケージをRaspberry PiのSDカードにインストールするのもあれですし、単なるPythonスクリプトですので、他から持ってくることにしました。

私のRPiのPidoraにあるbluezは Bluez-4.101-5 です。
従って、bluez-4.101 のソースコードから持ってくれば良いということになります。
http://www.bluez.org/download/ から bluez-4.101.tar.xz をダウンロードし、
アーカイブを解凍したところ、"test"ディレクトリ以下に"simple-agent"、"test-device"などのファイルがありました。
# ls test/
agent.c     l2test.c            service-spp.xml   test-nap
attest.c    list-devices        simple-agent      test-network
avtest.c    lmptest.c           simple-endpoint   test-oob
bdaddr.8    monitor-bluetooth   simple-player     test-proximity
bdaddr.c    mpris-player.c      simple-service    test-sap-server
btiotest.c  rctest.1            test-adapter      test-serial
dbusdef.py  rctest.c            test-attrib       test-serial-proxy
gaptest.c   sap-client          test-audio        test-service
hciemu.1    scotest.c           test-device       test-telephony
hciemu.c    sdptest.c           test-discovery    test-textfile.c
hsmicro     service-did.xml     test-health       test-thermometer
hsplay      service-ftp.xml     test-health-sink  uuidtest.c
hstest.c    service-opp.xml     test-input
ipctest.c   service-record.dtd  test-manager
この中からを必要なスクリプト(simple-agent, test-device)をリネームして/usr/local/bin あたりにコピーすればOKです。
# cp test/simple-agent /usr/local/bin/bluez-simple-agent
# cp test/test-device /usr/local/bin/bluez-test-device

あとは接続を試してみます...。
# hciconfig hci0 up
# hcitool scan
Scanning ...
    XX:XX:XX:XX:XX:XX    xxxxx

# bluez-simple-agent hci0 XX:XX:XX:XX:XX:XX
# RequestPinCode (/org/bluez/xxx/hci0/dev_xx_xx_xx_xx_xx_xx)
Enter PIN Code: XXXX

# bluez-test-device trusted XX:XX:XX:XX:XX:XX
# rfcomm bind 0  XX:XX:XX:XX:XX:XX
# rfcomm
rfcomm0: XX:XX:XX:XX:XX:XX channel 1 closed

/dev/rfcomm*にバインドされましたので、minicom などのターミナルから接続できるはずです。
# minicom -D /dev/rfcomm0

2014/05/10

Android Wearプロジェクトを作ろうとして嵌ったので自分用初歩的メモ

来月あたりに Android Wear搭載スマートウォッチが発売されるそうなので
今更ですが、Android Wear Developer Previewに登録して始めてみました。
(3月あたりの発表直後に開発開始された方、流石です。私もそれくらいの早さで取りかからないとついていけないなぁ...。
...3月は学会発表やら何やらでそれどころじゃなかったんです!(ひど
い言い訳w))

今回の記事は申し訳ありませんが、Android Wear云々というより
Androidアプリケーション開発の初歩的なミスの話です。開発環境はEclipseです。
(そろそろAndroid Studioに乗り換えたほうが良さそう...。)
以前からアプリ開発で稀に似た問題があったので、この機会にメモしておきます。

開発の始め方については
http://developer.android.com/wear/preview/start.html
または 松岡氏による日本語訳 を参照してください。

AVDでAndroid Wearの仮想マシンを作ろうとしたら、対応するアーキテクチャが無いといわれる


Android SDK Managerを起動して、最新のSDK Toolsと、Android 4.4.2 の必要なコンポーネントが本当にインストールされているか確認しましょう。
特に、私みたいに以前からあまり開発環境をアップデートしていない人は、環境が古くなっており、ひと通りのアップデートを適用したあとにSDK Managerを再読み込みさせて...という作業を何度か繰り返さないといけないかもしれません。

java.lang.NoClassDefFoundError: android.preview.support.v4.app.NotificationManagerCompat

  1. プロジェクトのディレクトリのlibsディレクトリに"wearable-preview-support.jar"をコピー(Eclipseのパッケージエクスプローラ上でD&D)する。
  2. プロジェクトのプロパティで"Javaのビルドパス"設定を開いて...

    のようになっているかどうか確認する。

java.lang.NoClassDefFoundError: Android.support.v4.app.NotificationCompat$Builder

  1. Android SDK Managerで"Support Library"が最新(執筆時: v19.1)かどうか確認する。
    (※プロジェクトの"Androidツール"メニューなどから"サポートライブラリーの追加"をすると、何故か古いバージョンのv19.0に置き換わることがあったので注意。)
  2. Android SDKのインストールディレクトリ内の extras/android/extras/android/support/v4/android-support-v4.jar を
    プロジェクトのディレクトリのlibsディレクトリにコピーする (Eclipseのパッケージエクスプローラ上でD&D)
  3. プロジェクトのプロパティで"Javaのビルドパス"設定を開いて...あとは上と同じ。

その他


いずれも、android-support-v4.jarなどがビルドパスに追加されているからといっても、それが最新リビジョンとは限りませんし、複数表示されている場合は"除去"して一からやってみることをおすすめします。(こちらも参照)
また、appcombat_v7がproject.propertiesで定義されていて勝手に読み込まれていたりする場合もあるので、そういう場合はまず外してみましょう。

もしかしたら、追記するかもしれませんが...以上です(笑)
期待して記事にアクセスしてくださった方には申し訳ありませんが、
初歩的な話でした m(_ _)m

p.s. 試しにこんなものを作ってみました。
シンプルなサイコロのアプリです。(GitHub: weardice_android)
ちょっと Notification の使い方としてはあれですが...w (コンセプト的に合わないかも)
今現在はSDKでCue Cardが使えない(Notificationに対する応答として音声入力はできますが、ホームから何か新しいアクションが実行できない)ので、とりあえずサイコロを振った結果を表示する部分と、"もう一度振る"というActionを実装しました。
最終的には"Ok google, サイコロ振って"と言うとサイコロが振れる予定ですw
ちなみに画像素材は自作です。ついでにサイコロの3Dモデルも作りました(笑)

ところで開発エミュレータ上でRoundのスキンを選んでいるのに、丸型にくり抜いて表示されないのですが、何故でしょうか...w 実用上、然程問題はありませんが
[2014/05/11 追記] 仮想マシンの設定で"ホストGPUを使用する"を有効にしていると、円形にくり抜いて表示されないようです。GPUによってオーバレイされるからでしょうか?


さて...気になる実機は LGの"G Watch"が第一弾として発売されるようですが、
私としては今までのスマートウォッチは四角いモノが殆どだったので、やはり丸型の"Moto 360"に興味があったり。((o(´∀`)o))ワクワク
正式版のSDKも楽しみです。

2014/04/29

Tesseract-OCRでMNISTのデータを用いて手書き数字認識をしようとしてみた

MNISTの手書き数字データベースのデータから
Tesseract-OCR用に学習データを生成し、手書き数字をオフライン認識してみます。

先に言い訳とお断りをさせていただきますと....
今回はとりあえずそのまま作るとどうなるかという実験のつもりでしたので
私の処理が「思いっきり手抜き」であり、数字しか認識できず認識率も低いですが、
とりあえず学習データができたというレベルの自分用メモとして記しておきます。
Tesseract-OCRもMNISTのデータベースも、正しく使えば、本来は相当な認識率となるはずです
 より正しい方法をご存知の方や、学習データの情報をご提供いただける方は是非教えていただければ幸いです
 ご指摘等をお待ちしております。 (記事のタイトルの歯切れが悪いのはそういうことです(汗;))


利用した環境は Linux (Arch Linux x64)であり、
Tesseract-OCR および engの学習データがインストール済みである事が前提です。
(Arch Linuxのpacmanでは tesseract, tesseract-data-eng でインストール可能。)

尚、Tesseract-OCRでの学習に関する手順は Tesseract-OCRの学習 - はだしの元さん を参照、引用させていただきました。感謝申し上げます。


1. MNISTのデータを取得

まずは 学習モデルの素となる MNISTのデータを取得...といきたいところですが、
今回はそのままでは使いづらい(もとい、使い方がよくわからない(^^;))ので
JPEG化されたデータを使わせていただくことにします。
http://www.cs.nyu.edu/~roweis/data.html

上記URLのページにある"MNIST Handwritten Digits"の
"training pictures"を0〜9までダウンロードします。
各々はJPEGファイル(mnist_train*.jpg)であり、その数字の手書き画像が大量に結合された巨大な画像ファイルとなっています。
training picturesの"0" (抜粋)
手書きされた数字の0が大量に結合されている。
さらに前処理として...これらのJPEGファイルを二値化してノイズを取り除き、PNGファイルとして保存しておきます。
この時、tesseractのboxファイルの命名規則に応じたファイル名にすると楽です:
(3文字の言語名).(フォント名(任意)).exp(インデックス番号)
という規則になっています (引用元)。  今回は数字だけですので...
  • 言語名: "eng"
  • フォント名:  "hand" (適当)
  • インデックス番号: PNGファイルの数字にあわせて0〜9
    (例: eng.hand.exp0.png 〜 eng.hand.exp9.png)
とします。
convertコマンドを使えば、二値化とPNGファイルとしての保存が一発ですね。
$ convert -threshold 30000 mnist_train*.jpg eng.hand.exp%d.png

2. boxファイルを生成

次にtesseract コマンドを用いて、PNGファイルからboxファイルを生成します。
$ tesseract eng.hand.exp0.png eng.hand.exp0 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp1.png eng.hand.exp1 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp2.png eng.hand.exp2 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp3.png eng.hand.exp3 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp4.png eng.hand.exp4 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp5.png eng.hand.exp5 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp6.png eng.hand.exp6 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp7.png eng.hand.exp7 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp8.png eng.hand.exp8 -l eng batch.nochop makebox &&\
tesseract eng.hand.exp9.png eng.hand.exp9 -l eng batch.nochop makebox
尚、処理には1時間程度かかりました。

3. boxファイルを修正

次にテキストエディタを用いて、boxファイルに対して修正を行います。
ここではまず、"0"の分のboxファイル(eng.hand.exp0.box)を見てみます:
o 2134 2132 2150 2152 0
o 2135 2104 2149 2124 0
o 2133 2075 2153 2095 0
a 2133 2048 2153 2066 0
a 2133 2021 2153 2037 0
o 2132 1992 2152 2012 0
o 2134 1964 2152 1984 0
o 2132 1936 2152 1956 0
o 2133 1907 2153 1927 0
o 2133 1880 2151 1900 0
o 2133 1853 2153 1869 0
o 2133 1825 2153 1842 0
o 2133 1797 2153 1815 0
n 2131 1770 2151 1784 0
o 2135 1739 2150 1759 0
....
先頭は認識された文字ですが、"0"ではなく"o"や"a"、"n"になってしまっています。
これをすべて"0"に置き換えます。(正規表現置換でs/^./0/すると良いですね。)
(※本当は行頭のあとの座標データも修正しなければならないようですが、今回は見逃しておきますw
本当はデータ数減らしてでもちゃんと修正すべきだと思います。)

この処理も0〜9のすべてのboxファイルに対して行います。

4. trファイルの生成

PNGファイルと修正したboxファイルから
tesseractコマンドを用いてtrファイルを生成します。
$ tesseract eng.hand.exp0.png eng.hand.exp0 nobatch box.train.stderr
これにより eng.hand.exp0.tr というファイルが生成されます。

この処理も0〜9のすべてのファイルに対して行います。

5. trファイルおよびboxファイルの結合

生成された 0〜9の分のtrファイル、boxファイルを各々結合します。
$ cat eng.hand.exp*.tr > eng.hand.exp.tr
$ cat eng.hand.exp*.box > eng.hand.exp.box
これ以降はほぼ参照させていただいたページのとおりですが、
丸投げもいけませんので、自分用メモとして掲載させていただきます m(_ _)m

6. 学習データの下準備

まず、boxファイルに対してunicharset_extractorコマンドを実行します。
$ unicharset_extractor eng.hand.exp.box
これにより、"unicharset"ファイルが生成されます。
※ この時、boxファイルの指定はこのように拡張子をつけます。

次に、テキストエディタで"font_properties"ファイルを作成します。
$ vim font_properties
hand 0 0 0 0 0
※ 先頭の文字列は最初に適当に決めたフォント名です。0 0 0 0 0はフォントの種類を表しますが、今回は特に何もないので0です。(詳しく参照ページをご覧ください。)

7. 学習データの生成

まず、先ほど作成したファイルをもとに、mftrainingコマンドを実行します。
$ mftraining -F font_properties -U unicharset eng.hand.exp.tr
これにより、"inttemp"、"shapetable"、"pffmtable"の3ファイルが生成されます。
※ この処理に約20時間要しました (Core i5 2520M @2.50Ghz, RAM8GB にて)。

さらに以下のコマンドを実行します。
$ mftraining -F font_properties -U unicharset -O eng.unicharset unicharset eng.hand.exp.tr
※ この処理にも約20時間要しました...(^^;)

続けて、cntrainingコマンドを実行します。
$ cntraining eng.hand.exp.tr
これにより、"normproto"ファイルが生成されます。
※ 以降の処理は数秒で行えます。

次に、本章で生成されたファイルのファイル名を変更し、
各々の先頭に言語名(今回は"eng")を付与します。
$ mv inttemp eng.inttemp
$ mv shapetable eng.shapetable
$ mv pffmtable eng.pffmtable
$ mv normproto eng.normproto

最後に、combine_tessdataコマンドを実行します。
$ combine_tessdata eng.
※ 最後のドットを忘れないようにしましょう。
これにより、"eng.traineddata"が生成されます。これが学習データです。

あとは...tesseractコマンドや、先日の記事のTesseract-OCRを用いたAndroidアプリケーションでこの学習データを利用できます。

8. 学習データを利用して認識してみる

生成した学習データを /usr/local/src/tesseract-ocr あたりにコピーしてもよいのですが、今回は環境変数で学習データのパスを指定してみることにします。
まず"tessdata"というディレクトリを作成し、学習データを入れておきます。
$ mkdir tessdata
$ mv eng.traineddata tessdata/
次に認識させたい画像をPNGファイルなどとして用意しておきます。(やはり2値化しておくと良いようです。)

あとは環境変数をつけて、tesseractコマンドを実行するだけです。
$ TESSDATA_PREFIX=. tesseract foo.png out.txt -l eng
これにより、out.txt に手書き数字の認識結果が得られます。

認識率は...私の手抜きの分、うーん(´・ω・`)...という感じです。
認識結果は参考までに...

  • 元画像(MNISTのデータをPNG化したもの)から適当な行を抜き出して認識させてみると、そこそこ満足できる認識率が得られました。
    (これで一応、学習データがそれらしく生成できていることは確認できました。)
  • 数字4桁を紙に手書きして、スマートフォンのカメラで撮影したものは...
    そのままでは全く認識できませんでしたが、
    数字部分を切り抜き、2値化と膨張を施すと、後ろ2文字は認識できました。さらに1文字目の数字の間隔を広げたところ、4文字すべて認識できました。

恐らくデータをもっと丁寧に前処理して、boxファイルの修正も丁寧に行えば、精度は向上すると思います...。
素晴らしいデータベースオープンソースソフトウェアであるにも関わらず、私の手抜きでこんな記事になってしまい大変失礼いたしました m(_ _;)m

もう一回、データ数を減らしてまじめに作りなおしてみようかな...とも思ったり...。


参考にさせていただいたWebページ (感謝♪) :

2014/03/16

Let's note CF-S10上のLinuxで正常にサスペンドするために (Arch Linux用カーネル再ビルドスクリプト)

Let's note CF-S10シリーズではLinux環境でサスペンドすると、内蔵キーボードやトラックパッドが認識されなくなる不具合があります。(知っている人は知っていると思いますが...。)
参照: Ubuntu 日本語フォーラム - サスペンドから復帰後キーボードが認識されません

Ubuntuに限らず、Arch Linuxなどの他ディストリビューションでもこの問題が発生します。 (i8042に関する問題ですが、他のi8042搭載マシンでは問題ないらしく、CF-S10シリーズのみ発生します。)
カーネルのドライバを書き換えてビルドしなおせば対策できますが、アップデートの度に自分で書き換えるのはあまりにも面倒です。
(ちなみに先日、東京で学会発表する機会があって CF-S10を持っていったのですが、何日か前にカーネルのアップデートをしてから再起動せずにサスペンドして使っていたところ、この問題の影響で一部デバイスが認識されなくなり焦りましたw)

...ということで...ちょっと今更ですが、
Arch Linux環境向けにカーネルを自動で書き換えてビルドしなおすスクリプトを書きました。
行っている内容としては...
  1. Arch Linuxの公式リポジトリからPKGBUILDやpatchを取得。
  2. makepkgを用いてPKGBUILDから最新カーネルのソースコードを取得。
  3. 上記参照ページと同様に drivers/input/serio/i8042.c を書き換え。
  4. makepkgでビルドを実行してパッケージ化し、システムに上書きインストール。
    (尚、ビルドは4コア使うように設定してありますが、数十分を要します。)
となっています。

わざわざこの機種のためにAURにカスタムカーネルとしてパッケージを登録するのもよろしくないのかな...と思いつつ、このような方法を取ってみました。
今後、Linuxカーネルがアップデートされたときにもこのスクリプトを実行すれば、不具合対策済みカーネルで上書きできます(...できるはずです)。

尚、このスクリプトは特に自己責任でご利用ください
また間違いやもっと良い方法がありましたら、ご指摘をお待ちしております m(_ _)m

それでは♪

2014/02/09

Arch Linuxでカーネルを更新したのにバージョンが古いままだった件 (環境の問題)

Arch Linuxのpacmanでアップデートを行ったところ、
linuxのアップデートがあったのですが...
再起動後、コンソールで表示が遅い、Xも起動しない、...という問題が。
(結論からいうと、環境の問題というか設定ミスでした m(_ _;)m)

lsmodすると...読み込まれているモジュールが明らかに少ない様子です。
$ lsmod
Module                  Size  Used by
ext4                  474251  3
crc16                   1367  1 ext4
mbcache                 6082  1 ext4
jbd2                   83504  1 ext4
dm_mod                 82469  9
sr_mod                 14898  0
cdrom                  34848  1 sr_mod
sd_mod                 30821  2
rtsx_pci_sdmmc         14332  0
ahci                   23056  1
libahci                21674  1 ahci
libata                170856  2 ahci,libahci
sdhci_pci              12146  0
sdhci                  29116  1 sdhci_pci
scsi_mod              130701  3 libata,sd_mod,sr_mod
mmc_core               95691  3 sdhci,rtsx_pci_sdmmc,sdhci_pci
rtsx_pci               32209  1 rtsx_pci_sdmmc
ehci_pci                4000  0
ehci_hcd               59220  1 ehci_pci
usbcore               180136  2 ehci_hcd,ehci_pci
usb_common              1656  1 usbcore
正常時は 116行なのに対して、22行しかありませんでした(笑)

mkinitcpioで確認してみようとしたところ...。
$ sudo mkinitcpio -M
 ==> ERROR: 'lib/modules/3.12.5-1.ARCH/' is not a valid kernel module directory.
カーネルモジュールのディレクトリが正しくないというエラーが。
しかも、バージョンが違うような?
(でも、アップデートでは何もエラーは表示されていませんでした。)

まずは、カーネルのバージョンを調べます。
$ uname -r
3.12.5-1-ARCH
アップデートされたはずのカーネルのバージョンがどうも古いままでした。

では、/lib/modulesは...というと...
$ ls /lib/modules/
合計 8
drwxr-xr-x 3 root root 4096  2月  9 13:25 3.12.9-2-ARCH
drwxr-xr-x 2 root root 4096  2月  9 13:25 extramodules-3.12-ARCH
こちらは新しいカーネルのバージョンでした。

さてここで原因が分かりました。
参照: [Solved] Uname doesn't changes after linux-3.9.5 upgrade

私のPCでは、/(ルート)や/homeはLVMボリュームであり
/boot は分割して通常のパーティションに割り当てています:
  • /(ルート) - LVMボリューム (/dev/sda8, /dev/VolGroup00/lvolroot)
  • /home - LVMボリューム (/dev/sda8, /dev/VolGroup00/lvolhome)
  • /boot - ext4 (/dev/sda10)

/bootパーティションがマウントされているか確認してみると...
$ mount -l | grep boot
空ということで、何も/bootにマウントされていないようです。

しかし、/bootには最新のイメージが書き込まれていました。
$ ls /boot -l
合計 xxxxx
-rw-r--r-- 1 root root 17758784  2月  9 13:25 initramfs-linux-fallback.img
-rw-r--r-- 1 root root  4344657  2月  9 13:25 initramfs-linux.img
-rw-r--r-- 1 root root  3867632  1月 31 18:24 vmlinuz-linux
※ でも、あるはずのgrubディレクトリが無いのです。

つまり...どういうことかと言いますと...
pacman -Syu でLinuxカーネルのアップデートがあった場合、
自動的にmkinitcpioが実行されますが、
この時、 /boot パーティションがマウントされていなかったため、
空の/bootディレクトリに最新のイメージファイルが書き込まれたようです。

GRUBから起動するときは /bootが/dev/sda10から起動されますが、
起動した後は、/bootがLVM上の/(ルート)下にあるものに置き換わっているため、
不整合となっていたようです。(そのため、必要なモジュールが読み込まれない。)

とりあえず、処置として...
コンソール上で /bootをマウントした上で
downgrade を使ってlinuxのカーネルを再インストールしました。
(pacman -Uでカーネルを再インストールしたり、mkinitcpioを手動実行してもいいはず。)

あとは再起動すれば正常に起動します。

さらに、fstabに/bootを追記しておきます。
$ sudo vi /etc/fstab
# /dev/sda10
/dev/sda10 /boot ext4 rw,relatime,data=ordered 0 2
これでOKです。たぶん(^^;)

とりあえず、一件落着です ε-(´∀`*)

2014/02/01

AndroidでTesseract-OCRを用いてカメラで光学文字認識をしてみた

AndroidでTesseract-OCRを使って、カメラで撮影した画像からOCR(光学文字認識)をしてみました。

"Tesseract-OCR"はOCRエンジンであり、元々HPによって開発され、OSS化されて今はGoogleがメインメンテナとなっています。
このTesseract-OCRをAndroidでNDKとして利用するためのライブラリが "tesseract-android-tools"です。

尚、本記事は Android SDK、GNU make、Awk、Gitがインストールされていることが前提です。また、OS環境としてLinux(Arch Linux x64)を使っています。

まずは、"Android NDK"をダウンロードします。
(すでにAndroid NDKをセットアップしていれば、この手順は不要です。)
今回は、Linux x64向けの最新版である "android-ndk-r9c-linux-x86_64.tar.bz2"を用いました。
さらにダウンロードしたアーカイブを展開し、これに含まれる"ndk-build"コマンドを利用できるようにPATHを通しておきます。
$ wget android-ndk-r9c-linux-x86_64.tar.bz2
$ tar jxf android-ndk-r9c-linux-x86_64.tar.bz2
$ sudo mv android-ndk-r9c/ /opt/
$ echo 'export PATH=$PATH:/opt/android-ndk-r9c' >> ~/.bashrc
$ echo 'export NDKROOT=$PATH:/opt/android-ndk-r9c' >> ~/.bashrc
$ source ~/.bashrc

次に、"tesseract-android-tools"を...
...のはずですが、執筆現在、Android NDK r9 でうまくビルドできませんでした。

代わりに、rmtheis 氏によってForkされたプロジェクトが公開されていますので、そちらを使わせていただくことにします。尚、このプロジェクトにはTesseract、Leptonica、その他の必要なファイルが同梱されています。
$ git clone  https://github.com/rmtheis/tess-two.git
$ cd tess-two/tess-two/

あとは READMEファイルのとおりにビルドを進めていきます。
但し、ここでAndroid SDKのAPI level 8がインストールされていないとエラーが発生しましたので、project.propertiesを書き換えることで対処しておきます。(自分のPCにインストールしておいたAPI levelに書き換えてください。)
--- project.properties
+++ project.properties
@@ -9,4 +9,4 @@
 android.library=true
 # Project target.
-target=android-8
+target=android-10
さらにコマンドを実行します。
$ ndk-build
$ android update project --path .
$ ant release

次に、Eclipseでプロジェクトをインポートします。
先ほどndk-build した "tess-two"プロジェクトを、Eclipse上で"Androidプロジェクト"としてインポートします。
インポートされたら、プロジェクトのプロパティで"ライブラリ"扱いになっているかを確認します。
Eclipse上でプロジェクト"tess-two"をインポートしたら、
プロジェクトのプロパティで"ライブラリー"にチェックが入っていることを確認する。

あとは、Androidアプリケーションを書きます。
今回は、最低限の簡単なサンプルアプリケーションを作ってみましたので、
一式をGitHubのリポジトリとして公開しておきました:
https://github.com/mugifly/android_tesseract-ocr_test
ご自由に git cloneして、動作を試したり改変したりしてご利用ください。

尚、このAndroidアプリケーションプロジェクトのほうでは、先ほどのライブラリプロジェクト"tess-two"をライブラリーとして追加しておきます。
Androidアプリケーションプロジェクトのプロパティで
使用するライブラリーとして先ほどの"tess-two"プロジェクトを追加する。
さらに、"tesseract-ocr"の学習データをダウンロードします。
日本語の学習データは http://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.02.jpn.tar.gz です。
これをダウンロードして展開すると"jpn.traineddata"というファイルがあります。

このファイルを、先ほどのAndroidアプリケーションプロジェクト内の"assets"ディレクトリ内にコピーしておきます。
Androidアプリケーションプロジェクトに"assets"フォルダを作り、
そこに"jpn.traineddata "をコピーしておく。
※ assets内の学習データを直接Tesseract-OCRで読み込めるようにするには、
tess-two (tesseract-android-tools)を改変する必要がありそうでしたので、
代わりに私が作成したサンプルアプリケーションでは、起動時にassets内の学習データをSDカード上にコピーする処理を実装しておきました。

尚、学習データがないと当然ながらOCR処理でエラーが発生します。ご注意下さい。

あとはAndroidアプリケーションプロジェクトをビルドするだけです。
NDKを用いたアプリケーションなので、ビルドに少し時間がかかります。

さて、写真を撮って文字認識をしてみます...。
尚、今回は面倒くさかったので、実機ではなくAndroidの開発用エミュレータを用いました。カメラは適当にあったWebカメラ QCam S7500 で、解像度はVGAに落として撮影しています。


OCRをかける前に二値化処理を行い、さらに数字だけに絞ってOCRをかけています。
適当に写真を撮った割には、まあまあの認識精度だと思いますが、
やはり、前処理(傾き、歪みとか、二値化とか...)について改良する余地がありそうです。

また、手書きした文字についてはうまく読み取りできませんでしたが、手書きの文字ばかりを集めて学習データを生成すれば、不可能ではないようです。
(参照: tesseract for handwriting recognition)

それでは (^ ^)♪

参考にさせていただいたページ (感謝♪):