zinniaでお手軽手書き文字認識

@haoyayoi さんから引き続き iOS Advent Calendar 14日目の記事です。

アプリ自体はまだ2本しか出していないわたなべです。
iOS Advent Calendar はそうそうたるメンバーがとても参考になる記事を書かれているのでいろいろ勉強させてもらってます(><)!
こんな私ですが、@k_katsumiさんに背中を押されたので、最近試している手書き文字認識エンジン zinniaについて書いてみます

zinnia ってなに?

zinnia は Taku Kudoさんが作成された「手書き文字認識エンジン」です。このエンジンに文字のストローク座標の連続データを渡すことで、高速に文字を認識することができます。確からしさ順にN個の結果を取得することができるので、変換候補を表示したりも出来ます。

iPhone上で動かすには...

@FLCLjp さんが作成されたサンプルが Githubで公開されているのでそれを見るのが一番だと思います。
実際に動かしてみると以下のようにしっかり認識できるはずです。


f:id:kaz_29:20111214124235p:image:w360

で、これだけだと全く中身がない話になってしまうので(^^; もう少し書きますよ〜。

認識率は...

zinniaのサイト上で配布されれいる 認識用モデルファイル(Zinnia-Tomoe) を使って試用した感じではかなり認識率は高いと思います。ただ画数の少ない文字はどうしても正しく認識してくれないケースが多かったです。まぁ、仕方が無いですね。

ですが、特定の文字種に限って(たとえば数字だけとか...)認識できればいいのであれば、自前で認識用モデルファイルを作ってしまえばかなり認識率を高めることはできそうです。

実際、私を含め身近な数人に数字のストロークを入力してもらい作成した認識用モデルファイルを使うと、ほぼ100%に近い確率で認識できました!

認識用モデルファイル

認識用モデルファイルはS式で記述された学習データを元に、zinnia付属のコマンドで作成します。公式ページにも記述がありますが実際の形式は以下のような形式です。

S式フォーマット

(character
 (value 認識したい文字)
 (width キャンバス幅)
 (height キャンバス高さ)
 (strokes
   ((0画目x 0画目y) ... (0画目x 0画目y))
   ((1画目x 0画目y) ... (1画目x 1画目y))
   ((2画目x 2画目y) ... (2画目x 2画目y))
   ...))


フォーマット自体はとてもシンプルなのですが、このデータを作るには実際に認識させるデバイス上で文字のストローク情報を集める必要があります。おそらくzinniaを使っている方はみんな何らかの文字収集ツールを書いてるんじゃないかなぁと思います。


ということで、自分用にiPhoneで動作するアプリを書いたので解説します。

手書きストローク収集ツール(TegakiStroke)

iPhone-Zinnia-TegakiStroke@GitHub


もともと自分用に収集アプリを書いていたのですが、不特定多数の人のストロークを集めたかったので、データをサーバーに上げる方式で作っていました。これだとお手軽に試してもらうわけにはいかないので、すべてのデータをローカルなsqlitedbに保存する形で作り直しました。テーブル構成は以下のようなとても簡単な作りになっているので、、付属のtemplate.dbを覗いてもらえればわかるかと思います。

モデル情報(models) => モデルに含まれる文字情報(characters) => 実際のストローク情報(strokes)


以下がschema構築用のsqlファイルです。

CREATE TABLE models (
id INTEGER PRIMARY KEY,
name TEXT,
created
);

CREATE TABLE characters (
id INTEGER PRIMARY KEY,
model_id INTEGER,
character TEXT,
created
);

CREATE TABLE strokes (
id INTEGER PRIMARY KEY,
character_id INTEGER,
strokes TEXT,
created
);

INSERT INTO models (name,created) values ('number', '2011/12/13');

INSERT INTO characters(model_id,character, created) values(1,'0','2011/12/13');
INSERT INTO characters(model_id,character, created) values(1,'1','2011/12/13');
... 以下略

実際の動作は...

まず入力するモデルを選んで...

f:id:kaz_29:20111214141228p:image:w360

「文字入力」ボタンを押して....

f:id:kaz_29:20111214141229p:image:w360


実際に文字を入力します....

f:id:kaz_29:20111214141230p:image:w360


登録されている文字の入力が終わると、文字一覧に戻ってくるので「S式書出し」ボタンを押せば完了です。

f:id:kaz_29:20111214141229p:image:w360


書きだしたデータは、Documentsフォルダに保存されていますのでiTunes ファイル共有か何かで取り出してください。


f:id:kaz_29:20111214141231p:image:w360


吐き出された、*.sファイルをzinnia付属の zinnia_learn にかければ実際に使えるモデルファイルが出来上がります。
またアプリ内部で使用している sqliteのファイルもDocumentsフォルダに保存してあるので、適宜モデルや文字を追加するなり、自前でstrokeデータを抜き出して加工するなり、いろいろできるのではないかと思います。

まとめ

zinniaを使うと非常に簡単に手書き文字認識を実装できます。実際のアプリで使うには色々と工夫が必要かと思いますが...。

ソースはGitHubに上げてありますので、試してみてください!
若干やっつけ感が漂っているところもありますが(^^; 、時間ができたら機能を追加していこうと思ってます。

明日は @hIDDEN_xv さんです!

PHP Matsuriに参加しよう!

色々ばったばったしているわたなべです。
このエントリーは、10/15-16に大阪で開催されるPHP Matsuriリレーブログエントリーです!

http://2011.phpmatsuri.net/:image=http://img.f.hatena.ne.jp/images/fotolife/k/kaz_29/20111002/20111002173256.gif

まだ若干の余裕はありますが、急がないと埋まってしまう可能性もあるので後悔したくない人は今すぐ申し込んでしまいましょう!

私は昨年のPHP Matsuriにも参加したのですが、私が感じたこうしたら楽しめた(はず)!という内容を書きたいと思います。

作るものをある程度考えておく

f:id:kaz_29:20101002093601j:image

当日は興味深いセッションやワークショップが盛りだくさんなので、以外にハックの時間がとれないかもしれません。当日作るもの/やる事をある程度考えて事前準備をしておくと良いと思います。開発環境も準備出来る方は事前に準備しておくのも良いと思いますが、期間中に使用可能なインスタンススポンサーさんが貸してくれるとの話もある様なので、環境構築も周りのみんなの構築方法とかを聞きながら色々試すのも面白いと思います。

食事タイムにも交流

f:id:kaz_29:20111003190735j:image
photo by @ichikaway

期間中は、参加者/ゲスト全員で食事をする機会が4回あります。この食事時間も絶好の交流のチャンスです。気になるゲストのそばに陣取るのもいいですね。また、気になる参加者やスタッフをポジションペーパーでチェックして一緒に食事をとるのも楽しいと思いますよ!

疲れたら休憩にして動き回る

f:id:kaz_29:20111003191052j:image
photo by @ichikaway

講演/ワークショップ/ハックに疲れたら、少し休憩にしてうろうろしてみると面白いと思います。昨年は深夜にいきなりゲーム大会が始まったり、ビール片手に海外ゲストと談笑する人、喫煙スペースで延々開発談義をしている方とかもいました。

遅い時間になるとあちこちで「プシュ!」とビールの空く音が....!お酒が飲める人も飲めない人もあちこちで会話に花が咲いていると思います。興味のありそうな話が聞こえたらがんがん捕まえて交流する事をお勧めします。

英語は怖くない!?

f:id:kaz_29:20101002205231j:image

英語は思っているほど怖くありません。中学生レベルの英語で十分コミュニケーションはとれます。別にとって食われる事はないので、海外ゲストにもガンガン話しかけてみましょう。世界が広がるはずです。

と、英語をしゃべれる人にいつも言われているので、私も今回はがんばろうと思います(^^;。

やった事を発表する

f:id:kaz_29:20111003194009j:image
photo by @ichikaway

2日目の午後は参加者それぞれの成果をLT形式で発表する時間になります。「自分が作ったものなんてたいした事無いし...」とか「まだ未完成だから...」とか色々あって躊躇する人も多いとおもいますがそんな人は、@shin1x1さんの勉強会を楽しむなら発表しよう!を読んでみましょう!ここに書かれている、

「君の当たり前に僕らは感嘆させられるんだ」

は本当にその通りだと思います。発表する事で広がるものが絶対にあります!すてきな商品もある様なので、是非!

まとめ

という事でつらつらと書いてきましたが、PHP Matsuriは楽しいので是非参加してみんなでハックして交流しましょう!という事です。さあ、皆さん申し込みましょう!

明日は、上でも紹介した@shin1x1さんです、よろしくお願いしますー!

candycaneをPostgreSQLにも対応させたい!

昨日の夜に社内用 redmine をアップデートしていたのですが、まだCakePHPもgitも覚えたての頃に、CakePHP開発合宿に参加して開発したのを思いだしたのか、急に candycane が気になったので、ちょっといじってみる事にしました。

まずは手始めに、手持ちのMacのPHP+MySQL環境にインストールしてみたのですが、まぁこれが超絶簡単。@yandoさんも書いていますが、本当に3分程度でインストールが完了してしまいました。


f:id:kaz_29:20110817232500p:image


いよいよPostgreSQLに対応する作業ですが、実際にやった作業は以下のような感じ。

  • MySQLの初期状態を元にCakePHPのschemaファイルを作成
  • 上のschemaファイルを使ってPostgreSQL上にテーブルを作成
  • MySQLのダンプファイルを元に初期データをインサート
  • pg_dumpでダンプしたものを整形して初期化用sqlを作成
  • インストーラのDB設定画面にDB選択フィールドを追加
  • インストーラにPostgreSQLの接続確認処理 database.phpに選択されたdriverを書き込む処理を追加
  • 選択されたドライバ毎に初期データ作成用sqlを切り替える処理を追加

とこんな感じです。途中、schema生成時にエラーが出てはまったのですがこれはcandycane開発当初にはまだリリースされていなかったPostgreSQL9.xに依存する問題だったので、CakePHP1.3.10CakePHP1.3.5で対応されたもの組み込んで対応しました。

以下が実際のインストーラのスクリーンショットです。

f:id:kaz_29:20110817235238p:image

インストール完了後に Administration -> informationをみるとこんな感じ。

f:id:kaz_29:20110817235239p:image

ひとまず、無事PostgreSQLで動作させる事ができました。

実際にはいくつかの機能で正常に動作しない部分や、テストが通らない所があるので今後ちょっとづつ手を入れていこうと思ってます。

ソースはgithubにあげてあります

電力使用量を表示するアプリを作りました

先週金曜日(4/8)、計画停電の「原則不実施」の発表日という絶妙のタイミング(^^; でしたが東京電力管内の電力使用量を表示する「電力グラフ」というアプリをリリースしました。

電力使用量を取得するAPIが続々リリースされ始めた3/24頃に、こんな事をつぶやいていたら@basukeにケツ叩かれたので作ってみました(^^;

グラフの描画は s7graphview を使わせてもらっています。また、通信関係の処理は three20 を使っています。
この2つのライブラリのおかげで比較的サクッと作れました。

f:id:kaz_29:20110411102352p:image

主な機能はこんな感じです。

  • 過去7日分の電力使用状況の表示
  • 計画停電の実施状況の閲覧(当日から3日間)
  • 電力/節電に関連する情報の表示
  • 電力/節電に関連するリンク集

使用している情報は下記のAPIを使用しています。

計画停電のスケジュールは東京電力の発表しているデータを元に独自で作成したデータを使っています。この情報はAmazon S3上においてあったりします。

原則的に計画停電は実施されない事になった様ですが、これから夏にかけて電力が不足する事は変わらないと思うので、節電のお供に使って頂ければと思います。

ダウンロードはこちら

*「電力グラフ」で使用している情報は、東京電力の発表に基づき情報を更新しておりますが、反映には時間差が生じます。 最新の情報は東京電力のサイト等でご確認ください。

iPhone用のスタティックライブラリを統合

頻繁にやる作業ではないからかいつも忘れてしまうのでメモ。

iPhoneで外部ライブラリを使う場合、シミュレータ用とデバイス用と2種類用意しないといけないのですが、lipoコマンドを使って両方に対応したライブラリを用意します。

下記が使用方法です。

lipo -create \
    foo/Build/Debug-iphonesimulator/libBar.a \
    foo/Build/Release-iphoneos/libBar.a \
    -output \
    foo/lib/libBar.a

Titanium Developer で シミュレータが起動しない場合の対処方法

昨年秋に はてな技術勉強会 #2を見ながら試して以来触っていなかったのですが、先日の #stidev@masuidriveさんのお話を聞いて俄然興味が出てきたので、今更ながらTitanium Mobileを試してます。

で、いきなりハマった事があるので纏めておきます。

久々にTitanium Developerを立ち上げたら、「新しいSDKがあるよ」的なメッセージが出たので当然インストールした(つもり)。

で、その後新規でプロジェクトを作ったところ、Launchボタンを押してもシミュレータが起動しません...。

何だろうと思いつつ、Titanium SDKのバージョンを下げても似た様な状況...。

buildディレクトリをあさっていると "build/iphone/build/build.log" なんて怪しいファイルを見つけたので見てみると "libTiCore.a" が見つかりませんとのエラーが...。

調べてみると 確かに '/Library/Application Support/Titanium/mobilesdk/osx/1.5.1/iphone/libTiCore.a' が存在しません。1.4.2のディレクトリと比べてもなんだかファイル数も少なかったです。

リビルドとか出来ないのかなぁとかいろいろ調べてみましたが見つかりません。数日放置してたのですが、どうしても色々試したい!

仕方が無いので、'/Library/Application Support/Titanium/mobilesdk/osx/1.5.1' をまるっと移動して Titanium Developerを起動し直したところ「新しいSDKがあるよ」表示が!!!

という事で、あっさり使える様になりました(^^;。
原因は良くわかりませんが、インストールが正常に完了していなかった様です。

Datasourceを使い倒す

CakePHP Advent Calendar2010 も折り返し点を過ぎました。CakePHP Advent Calendar2010は、ネタの調整などはしていないのですが(してないよね(^^;?)、参考になる話ばかりだし、まだネタがかぶったという話は聞かないので正に「君の当たり前に僕らは感嘆させられるんだ」ですね(^^;。

では、13日目の担当と言う事で...。

*この記事の内容はCakePHP1.3での話になります。


CakePHP1.2までは、Datasourceは app/models/datasources/ 以下に配置しないと動作させることが出来ませんでしたが、CakePHP1.3からはプラグイン配下のDatasouceを使用することが可能になりました。
これは個人的にとても嬉しい修正だったのですが、このあたりの情報をWeb上にあまり見かけないのでまとめてみました。

CakePHP Datasources

CakePHPのCoreに含まれていないデータソースは、PHP Matsuriにも来ていただいた Graham Weldonさんが以下でまとめられています。

ここには、以下の様なデーターソースがまとめられています。

  • Amazon Associates Datasource
  • Array Datasource
  • CSV Datasource
  • SORP Datasource
  • XML-RPC Datasource
  • ADODB Datasource
  • DB2 Datasource
  • Firebird Datasource
  • MySQL Log Datasource
  • ODBC Datasource
  • SQLite3 Datasource
  • SQLServer Datasource
  • Sybase Datasource

他には、CakePHP Advent Carendar2010の一日目を担当されたid:cakephperさん作の MondoDB Datasource なんかも最近はホットなのではないでしょうか?
# 弊社でも使わせていただいております!

Datasourceの使い方(準備編)

使用する為に機能拡張等のインストールが全く必要ない、CSV Datasourceを例に実際にDatasourceを使う方法を解説してみたいと思います。

まずは、pluginsディレクトリに CakePHP Datasources を配置します。

 cd APP/plugins/
 git clone https://github.com/cakephp/datasources.git


実際のプロジェクトで利用する場合は、 6日目に@tfmagicianさんが紹介されているように git submoduleを使って管理すると良いと思います。


次に、cvsファイルを配置します。今回は APP/tmp/databases/ に下記のファイルを配置します。

  • APP/tmp/databases/advent_calendars.csv
id,target_date,name,url
1,"2010/12/01","cakephper","http://d.hatena.ne.jp/cakephper/20101201/1291166566"
2,"2010/12/02","k1LoW","http://d.hatena.ne.jp/k1LoW/20101202/1291262612"
3,"2010/12/03","shin1x1","http://www.1x1.jp/blog/2010/12/thinking_abount_cakephp_mode.html"
4,"2010/12/04","remore","http://rimuru.lunanet.gr.jp/notes/post/2838/"
5,"2010/12/05","uechoco","http://labs.uechoco.com/blog/2010/12/cakephp-model-lovers.html"
6,"2010/12/06","tfmagician","http://1-byte.jp/2010/12/06/cakephp_with_git/"
7,"2010/12/07","MASA-P","http://blog.ecworks.jp/archives/1323"
8,"2010/12/08","kanonji","http://d.hatena.ne.jp/kanonji/20101208/1291819950"
9,"2010/12/09","lxcy","http://d.hatena.ne.jp/ixcy/20101209/p1"
10,"2010/12/10","mon-sat","http://text.tklabo.net/blog/26/cakephp-environment-tips"
11,"2010/12/11","msng","http://www.msng.info/archives/2010/12/cakephp-error-only-when-debug-level-is-0.php"
12,"2010/12/12","ogaaaan","http://torhamzedd.blogspot.com/2010/12/cakephp-advent-calendar-12st.html"
13,"2010/12/13","kaz29","http://d.hatena.ne.jp/kaz_29/20101213/1292209088"
14,"2010/12/14","camelmasa","-"
15,"2010/12/15","hiromi","-"
16,"2010/12/16","aerith","-"
17,"2010/12/17","nojimage","-"
18,"2010/12/18","halt","-"
19,"2010/12/19","kunit","-"
20,"2010/12/20","connvoi_tyou","-"
21,"2010/12/21","yashio","-"
22,"2010/12/22","knj77","-"
23,"2010/12/23","osakanapower","-"
24,"2010/12/24","akiyan","-"


最後に、database.phpの設定です。今回datasourceはplugins以下に配置しているので下記の様に定義します。

<?php
define('CSV_PATH', TMP.'databases'.DS);

class DATABASE_CONFIG {
    var $csv = array(
        'driver' => 'Datasources.CsvSource',
        'path' => CSV_PATH,
        'readonly' => true,
        'extension' => 'csv',
        'recursive' => false,
    );

	...
}


これで、準備は完了です。

Datasourceの使い方(使用編)

実際に使用するには、通常のdatasourseを使用する場合とあまり変りないのですが以下のようになります。

  • モデル APP/models/advent_calendar.php
<?php
class AdventCalendar extends AppModel {
    public $useDbConfig='csv';
}
  • コントローラ APP/controllers/advent_calendar_controller.php
<?php
class AdventCalendarController extends AppController {
	public $name = 'AdventCalendar';
  public $helpers = array('Html','Paginator') ;
	public function index() {
	  $results = $this->paginate();
    $this->set(compact('results'));
  }
}
  • ビュー APP/views/advent_calendar/index.ctp
<div class="advent calendar index">
<h2><?php __('Advent Calendar');?></h2>

<p>
<?php
echo $this->Paginator->counter(array(
'format' => __('Page %page% of %pages%, showing %current% records out of %count% total, starting on record %start%, ending on %end%', true)
));
?>	</p>

<div class="paging">
	<?php echo $this->Paginator->prev('<< ' . __('previous', true), array(), null, array('class'=>'disabled'));?>
 | 	<?php echo $this->Paginator->numbers();?>
|
	<?php echo $this->Paginator->next(__('next', true) . ' >>', array(), null, array('class' => 'disabled'));?>
</div>

<table cellpadding="0" cellspacing="0">
<tr>
			<th><?php echo $result['AdventCalendar']['id'];?></th>
			<th><?php echo $result['AdventCalendar']['target_date'];?></th>
			<th><?php echo $result['AdventCalendar']['name'];?></th>
</tr>

<?php
$i = 0;
foreach ($results as $result):
	$class = null;
	if ($i++ % 2 == 0) {
		$class = ' class="altrow"';
	}
?>
	<tr<?php echo $class;?>>
		<td>
			<?php echo $result['AdventCalendar']['id']; ?>
		</td>
		<td>
			<?php echo $result['AdventCalendar']['target_date']; ?>
		</td>
		<td>
			<?php 
				if (!empty($result['AdventCalendar']['url']) && $result['AdventCalendar']['url'] !== '-' ):
					echo $this->Html->link($result['AdventCalendar']['name'], $result['AdventCalendar']['url']);
				else:
					echo $result['AdventCalendar']['name'];
				endif;
			?>
		</td>
	</tr>
<?php endforeach; ?>
</table>


Datasourceの実装によっては通常のRDB用 Datasourceと同じように使えない場合もありますが、基本的な機能は普段CakePHPを使っているのと同じように利用することができます。

参考のために、CSV Datasource以外のDatasourceを使う場合の database.phpの表記サンプルを下記に書いておきます。

<?php
define('TEST_SQLITE_FILE', TMP.'databases'.DS.'test.sqlite3');
...
    // SQLite3
    public $sqlite3 = array(
        'driver' => 'Datasources.DboSqlite3',
        'database' => TEST_SQLITE_FILE,
    );
...
    // mongoDB
    public $default_mongo = array(
        'driver' => 'mongodb.mongodbSource',
        'database' => 'mongotest',
        'host' => 'localhost',
        'port' => 27017,
        /* optional auth fields
        'login' => 'mongo', 
        'password' => 'awesomeness',    
        */
    );  	
...

まとめ

如何でしたでしょうか?今後はRDB以外のDatasourceを扱う機会も出てくると思いますので参考になれば嬉しいです。
また、Datasourceをアプリケーションと切り離すことができますので、Datasourceを作成する場合はpluginとして実装するのが良いと思います。そして、可能なのであればgithubなどで公開してみると面白いのではないかと思います。

明日は、@camelmasaさんです。よろしくお願いします〜。