2012 年 5 月 6 日, 12:29 PM
F○XC○NNの工場でアイポッド組立に従事するようになり早一ヶ月,私の古巣でまたもや01の文字列の印刷されたポスターが掲示されているという情報を得た.
世界的に有名な諜報組織モ○ドの協力でその写真を入手することに成功したので以下にそれを示す.


い,いったい7号館で何が起こっているんだ……!?
じゃなくて!
気を取り直してもう一度……

やっぱり和服なのね。風邪引いて気力が極限まで減退してるので文字おこしは今年は勘弁して下さいな.あともうちょっと拡大した写真も持っているので必要なら声をかけてください.Twitterの様子を見ると, #istposter のハッシュタグで在学生数名が既に解読に取り掛かっているようです.
2012 年 3 月 10 日, 8:32 PM
バーコードを読み取って本のリストを作るiPhoneアプリはあるらしいのだが,本というものは背表紙が見える状態で整理されていることが多いのだし,本棚の写真を撮るだけでリスト作れたら便利だなーと思いまして.で,画像処理全くわからないんだけど我流でOpenCVを使いながら試み中.一応そのものズバリなタイトルな英語論文(Building book inventories using smartphones)はあって,それを参考にキーワードを探りながら画像処理の知識を蓄えている.
本のタイトルのあたりは角が多いのでコーナー検出をすればそこにコーナーが集中する,ということと,直線の検出をすると平行な線がたくさん出る,ということを使えばいいんじゃないかと思っている(後者は論文でも使っている).
今の処理の流れは
- 元画像に対してコーナー検出を行なって角の座標を得る(コーナー検出アルゴリズムはEigenValueがよさそうという結果を得ている)
- 元画像に対してCannyエッジ検出を行った画像を得る
- エッジ検出を行った画像に対して,角の座標付近を黒で塗りつぶす処理を行う(文字が消えるのを期待する)
- HoughLinesで直線検出を行う(これで背表紙ごとに分割できるはず…うまくいけば)
比較的うまくいっている例が以下となる:

トランジスタ技術みたいな太い本はうまくいくのだが,細い本や暗い本,角が丸みを帯びた本はダメ.スマートフォンだとどうしても解像度が低いし,ズームができない(つまり斜め方向から撮影する本が多くなって角が判別しにくくなる)のでより条件が悪くなる.遠くから解像度の高いカメラで撮影しないと使い物にならなさそう.
背表紙ごとの分割をクリアした所で,OCRと名寄せの困難が待ち受けてるので,ハードルはかなり高そう.
2012 年 3 月 7 日, 7:27 AM
インターネットの人に公開する用の電話番号が欲しくなったので050 plusとかいうサーヴィスのためにiPod touchを買った.
良い点
- 解像度の高いディスプレイと良質なフォントがとてもQoLに影響することが分かった.
- 家計簿アプリのレシート撮影して解析する機能が楽しい.
良くない点
- バイブレーション機能が無いので音をなるべく出さずに着信に気づく方法がない.やむを得ず常時イヤホンをつけている.
- 050 plusの留守電機能がちと鬱陶しい(録音終了時に#を押してもう一回1#押さないといけない)
イヤホンのひもが本体とくっついてるのが嫌なので,片耳につけるタイプのBluetoothヘッドセット試そうかと思ってる.
追記:050plus公式に「Bluetoothには対応しておりません」書かれてた…どうしたものか
2012 年 2 月 22 日, 10:06 AM
今回書いた全ソースコードはgithubのリポジトリのtut3ディレクトリにあります.
前回はローカルの手書きHTMLからサービスに向ってPOSTリクエストを投げましたが,今回はリクエストを投げるHTMLをWebアプリで出すようにします.その前の準備として前回のままだと不都合があるので,main_serviceを 1. サービスを受け持つ部分 2. ページを出力する部分 の2つに分割します.
let main_service =
Eliom_services.service
~path:["index"]
~get_params:unit
()
let comment_service =
Eliom_services.post_service
~fallback:main_service
~post_params:(string "name" ** string "comment" ** string "submit")
()
let main_page =
register
~service:main_service
(fun () () -> (* HTML出力部.あとでフォームを出力するように置き換える *) Lwt.return
(html (head (title (pcdata "")) [])
(body [p [pcdata "hogehoge"]])))
つまり,register_serviceというのはserviceとregisterを一挙にやってくれていたわけです.
次にHTML出力部をフォームを出力するように置き換えます.
let f =
(Eliom_output.Html5.post_form comment_service
(fun (name, (comment, submit)) ->
[p [pcdata "name: ";
string_input ~input_type:`Text ~name:name ();
pcdata "comment: ";
string_input ~input_type:`Text ~name:comment ();
string_input ~input_type:`Submit ~name:submit ~value:"Post" ()]]) ()) in
return (html (head (title (pcdata "")) [])
(body [f]))
Eliom_output.Html5.post_formの最初の引数でどのサービスに向ってリクエストを投げるかを指定し,次の引数でPOSTリクエストのパラメータからどのようなフォームを作るかを指定します.ここでcomment_serviceを参照する必要があったので,serviceとregisterを分割しました.いやlet rec使えば分割しないでも行けたんですけど,ややこしくなるので.
string_inputはEliom_output.Html5.string_inputのことです.まあそんなに難しくないと思います.
こうすることにより,/indexにアクセスするとフォームが表示されるようになります.

2012 年 2 月 19 日, 5:37 PM
今回書いた全ソースコードはgithubのリポジトリのtut2ディレクトリにあります.
POSTを処理するサービスを記述するには,POST単体だけではダメで,そのサービスのURIがGETリクエストされた時の処理も書かないといけません.
EliomではEliom_services.post_service関数の~fallbackにGETを処理するサービスを指定します.~post_paramsにはGETのときと同様にパラメータを記述します.
let comment_service =
Eliom_services.post_service
~fallback:main_service
~post_params:(string "name" ** string "comment" ** string "submit")
()
サービスでどんなページを表示するかはGETのときと似たような感じです(今回は関数が2つに分割されてるけど).ページの内容を返す関数の第二引数の記述に注意.どうやら(param1, (param2, (param3, …)))と書かないといけないようで.
let comment_page = Eliom_output.Html5.register
~service:comment_service
(fun () (name, (comment, _)) ->
let message = name ^ "さんのコメント: " ^ comment
in
Lwt.return
(html (head (title (pcdata "")) [])
(body [p [pcdata message]])));
テスト用のHTMLが以下.
<html>
<head><title>post</title></head>
<body>
<form action="http://localhost:8080/index" method="post">
name: <input type="text" name="name"><br>
comment: <input type="text" name="comment"><br>
<input type="submit" name="submit" value="Submit">
</form>
<body>
</html>
これに適当に入力してsubmitすると以下のようになるはず.

なお,この場合,Eliom_services.post_serviceの~post_paramsにはちゃんとstring “submit”を入れておかないと「パラメータが合わねえよ」と怒られます.パラメータの過不足は許容されないっぽい?
追記: Eliom_parameters.optを使って,opt (string “submit”)と書けばオプショナルなパラメータを作れるようなので不足する分にはよさそうです.
2012 年 2 月 15 日, 1:48 AM
まえがき:ここのサンプルはgithubのplus7/ocsigen_tutのtut1/に置いてありますので適宜cloneしてください.
Webアプリはとにもかくにも何かを表示しないといけないことになっているらしいので.とりあえずHello worldしましょう.
ocsigenserverを動かすには設定ファイルが必要なのは前のエントリで環境構築していればわかると思いますが,いったい何が書いてあるんでしょうか.下記のXMLが私が簡略化してみたものです.
<!-- -*- Mode: Xml -*- -->
<ocsigen>
<server>
<port>8080</port>
<logdir>./log</logdir>
<datadir>./data</datadir>
<user>ahya</user><!--www-data-->
<group>ahya</group><!--www-data-->
<commandpipe>/tmp/ocsigen_command</commandpipe>
<charset>utf-8</charset>
<findlib path="/usr/local/lib/ocaml/3.12.1"/>
<extension findlib-package="ocsigenserver.ext.staticmod"/>
<extension findlib-package="ocsigenserver.ext.ocsipersist-sqlite">
<database file="./db/file"/>
</extension>
<extension findlib-package="eliom.server"/>
<!-- Inclusion of all external configuration files matching *.conf
from the directory 'dir' (in alphabetical order): -->
<extconf dir="/usr/local/etc/ocsigenserver/conf.d" />
<host charset="utf-8" hostfilter="*">
<site path="">
<eliom module="./byoki.cmo" />
</site>
</host>
</server>
</ocsigen>
<user>と<group>には自分のユーザー名入れてください.本格運用するときにはApacheのようにwww-dataとか.<logdir><datadir>はその名の通りのものです.mkdirしておいてください.
<commandpipe>はocsigenserverを制御するときに使う名前付きパイプのpathみたいです.再起動無しにモジュールをアップデートしたい時等に使うとか(Updating sites without shutting down the serverのところを参照).
<findlib>にはOCamlのライブラリへのPathが書かれています.普通にインストールしていれば変更の必要はないでしょう.
<extension>の列はocsigenserver内で有効にする拡張機能の一覧です.eliom.serverは古い資料だとocsigen.ext.eliomになってたりするので気をつけましょう.あとeliomはocsipersist-sqliteに依存してるっぽいです.これ書かないとエラーでて死にます.dbディレクトリもmkdirしておいてください.
<extconf>は私もよくわかってないのでそのままにしました.
<host>以下の<site>が核心部分です.<eliom>のmodule属性でどのモジュールに基づいてWebアプリを動かすかを指定します.<site>のpath属性ではどこのディレクトリ以下にこのWebアプリを配置するかを記述します.ここでは何も書いていないのでhttp://localhost:8080/直下でアクセスできます.例えば”exampleapp”と書けばhttp://localhost:8080/exampleapp/となります.
次にWebアプリ本体です.
open Lwt
open Eliom_pervasives
open HTML5.M
open Eliom_services
open Eliom_parameters
open Eliom_output.Html5
let main_service =
register_service ~path:["index"] ~get_params:unit
(fun () () -> return (html (head (title (pcdata "")) [])
(body [h1 [pcdata "Hello work!"]])))
register_serviceはEliom_output.Html5.register_serviceのことです.~pathにはこのサービスがどのpathを受け持つかを書きます.この例だとhttp:/localhost:8080/indexにアクセスするとこのサービスが表示されることになります.~get_paramsにはどのようなGETリクエストのパラメータを取るかを書きます.今回は何も取らないのでEliom_parameters.unitが指定されています.なにかパラメータを取りたい時には~get_params:(Eliom_parameters.int “i”)と書きます.こいつらにチルダがついてるのはOCamlのラベルを使っているからですね.使ってるの初めて見た….最後の関数はどんな内容を返すかの関数です.第一引数にGETのパラメータ,第二引数にPOSTのパラメータが渡されるらしい.今回は何もとらないので()になっています.htmlとかheadとかはHTML5.Mの型で,文字通りhtmlの要素を表しています.
このソースをocamlfind ocamlc -thread -package eliom.server -c byoki.mlでコンパイルした後,ocsigenserver -c kowai.confでサーバを起動すれば,http://localhost:8080/indexにアクセスすると味気のな~いページが表示されるはずです.

2012 年 2 月 14 日, 8:18 AM
日本語情報は3, 4年前くらいには出てるみたいなんですけど最近なさげなので検証も兼ねて作業記録つけますよ.作業環境はDebian sid.
今回は環境構築ということであんまり詳しくは書きませんので適宜リンク先を読んでください.
Ocsigen bundleのインストール
Ocsigen bundleを説明に従ってインストールする.ただしここの記述,抜けがあって,libgdbm-devが追加で必要だったので,必要なパッケージをapt-getするときには気をつけよう.
なお,Ocsigen bundleにはすでにEliomも付属しているので追加で何かする必要はない.
ocsigenserverの動作チェック
root で ocsigenserver または /etc/init.d/ocsigenserver start すれば80番ポートでデフォルトのHTTPサーバが起動するのでブラウザから確認する.It works! と出ているはず(ocsigen server単体のマニュアルより)
次はもうちょっと詳しめのチュートリアルのソースコードと設定ファイルをコピペして,My first pageだけでも動かして満足してみよう.とりあえずここまで動けば遊べる態勢になっているはずだ.
次回に続く,かも?
2012 年 2 月 6 日, 4:23 AM
最近どうやってhome以下のディレクトリ切ってるかのメモ.
- usr makeする系の小物ソフトやライブラリ
- opt unzipしたほうが早い系のでかいソフト
- proj 他人と作業する前提のファイル類
- repo 公的なソフトウェアのリポジトリから引っ張ってきたのがここ
- work 雑多な作業用のディレクトリ
- tmp 一時作業
- vm 仮想マシンの類
いろいろなカオスを経てこんな感じにすることが増えてきたと思う.
2011 年 12 月 31 日, 8:54 PM
参考: https://twitter.com/todesking/status/51560179707293696

ポイント支払いの上,額がみみっちいので初任給もらったら追加する予定.
卒業前に旅行に行こうかしらん.