2012年1月4日水曜日

勾配方向画像のHSV表示スクリプト

画像の勾配方向をHSVに変換するPythonスクリプトです.
OpenCV2.3.1で動作します.2.2系では動かないと思います. 

使い方は,
-i オプションで勾配方向画像を得たい画像ファイルを与え
-o オプションで変換後の画像ファイルを指定します.
-s オプションをつけると変換後に表示してくれます.

 使用例)
 python gradient_direction_hsv.py -i source.jpg -o result.jpg -s

 変換例)


ダウンロード

2012年1月3日火曜日

ロマネスコのピクルス漬けを作ってみた

昨日,茹でたロマネスコが少し余ってしまいました.
フラクタルな模様は子供たちには不評で,悪魔の野菜だとかいって逃げまわる始末です.
捨てるのはもったいないのでツイッターでピクルス漬けにしたという話を思い出して早速作ってみました.
一般的なピクルスの作り方を参考に,ありあわせの材料をジップロックに放り込んだだけなのですが,ニンニクの香りがするだけで美味しそうな気がしてきます.

材料)
穀物酢
100ml
水
50ml
砂糖
30g
ニンニク
ひとかけ
唐辛子
1本
塩コショウ
適量
ローズマリー
適量

今はジップロックに入れて保存しているところです.
肝心の味のほうですが,フツーにピクルスでした.
まあ,買ったものよりは,おいしいように思います.
ロマネスコのピクルス漬けなんて売ってないからそれだけでも作ってみる価値はあったんじゃないでしょうか.

NIPALSとかPLSとか

昨今の認識アルゴリズムは,マシンパワーにものを言わせて判別に使う情報量をどんどんと増やしていく傾向にあると思うのです. 例えばHOGとかがいい例ではないでしょうか.私の5年前のノートPCでは遅すぎて使いもになりません.

そもそも自分が学習機ならとても覚えられないような情報量を無理やり食わせて,性能をだすことができるんでしょうか. もっとシンプルにやる方法が必ずあるに違いないと心の奥底で私は信じているのですが,今は具体案を提案できている状態ではないので私の主張には説得力はありません.

実際に人間の脳みそは,体重比率で大きなウエイトを占めているわけで,生物の知能が発達すると共に脳みそは大きくなってきたのを鑑みると,高度な情報を処理するためには複雑な仕組みが必要なのだと,暗に示唆されているようにも思えます.高度な知性を実現するには脳みそのような複雑なハードが必要なのだという証だといわれれば反論するのが難しいです.

だけれどもほんの一部でもいいから,シンプルな手法によって人間の知性を計算機の上で実行できないものだろうかと思うのです. 映像から人がどこを歩いているのかだけでも人並みに判別できれば,悲惨な交通事故をもっと減らすことのできる役立つ機械を作ることが出来るはずです.
もしシンプルに計算量の少ないアルゴリズムでそれが実現できれば,安いハードウエアで製品を構成することができるようになり,普及が期待されます.

そこで手っ取り早い方法として性能は保証されているけれど膨大な情報を収集する必要のあるアルゴリズムを使いつつ,その中からあまり重要ではない情報をふるいにかけて情報量を減らして,計算量を減らすアプローチを考えます.このようなことをやる代表的な手法として主成分分析(PCA)があります.PCA-SIFTなどが応用例としていい例でしょう.

でも実際にPCAを分類器に入力するデータの次元圧縮手段として使ってみると,期待したほど性能は良くないんじゃないかという印象を持っています. もちろんそれはケースバイケースなんだと思いますが,画像認識に使うようなデータでは判別結果に使うパラメータの線形独立性を期待できないことがほとんではないでしょうか.

そのようないい加減なデータでもパワフルに働いてくれる次元圧縮方法がないものかと探していたら,先日PLSという手法(Partial Least Square)を見つけました.化学分析分野でよく用いられる方法のようで,例えば,サンプルの各波長における吸光度から,どのような物質がどのような割合で含まれているかなどを分析するために開発された手法のようです.

日本語で書かれたフリーで読める文献がありました.こちらです「PLS 回帰におけるモデル選択」.でも日本語で読んでもなんだかよく分かんなかったです.ちょっと苦しいけれど英語の文献の方が丁寧に書かれていて,理解しやすかったりすることも多いです.これもいいかも知れません「A Beginner’s Guide to Partial Least Squares Analysis」
実は自分が参考にした最もわかりやすかった文献のリンクが今探せないです.どこいっちゃったものだか.あとで見つけたら追記しておきます.

このPLSをお手軽にためすには,「R」のplsパッケージを使うのが良いみたいで,PLSの紹介論文などでは,Rに付属のgasolineという吸光度とオクタン価の関係を測定したデータが良く紹介さrています.Rはあんまり好きじゃないので,早速,ガソリンデータを使ってPLSアルゴを試すpythonコードを書いてみました.
def NIPALS_internal(X, Y, n, M, N, u, epsilon):
    u0 = u
    while True:
        w = X.T * u / (u.T * u)
        w = w / norm(w)
        t = X * w
        c_ = Y.T * t / (t.T * t)
        c = c_ / norm(c_)
        u = Y * c
        if norm(u0 - u) < epsilon: break
        u0 = u
    p = X.T * t / (t.T * t)
    q = Y.T * u / (u.T * u)
    Xnew = X - t * p.T
    Ynew = Y - t * c_.T
    return Xnew, Ynew, t, u, p, q, w

def NIPALS(X, Y, k = 1, epsilon = 1e-12):
    n, N = X.shape
    M = Y.shape[1]
    X_mean = X.mean(axis=0)
    X_std = X.std(axis=0)
    Y_mean = Y.mean(axis=0)
    Y_std = Y.std(axis=0)
    X_ = (X - X_mean) / X_std
    Y_ = (Y - Y_mean) / Y_std
    X__, Y__ = X_, Y_
    W = matrix(zeros( (N, k), float32))
    T = matrix(zeros( (n, k), float32))
    U = matrix(zeros( (n, k), float32))
    P = matrix(zeros( (N, k), float32))
    Q = matrix(zeros( (M, k), float32))
    for i in range(k):
        u = Y_[:,0]
        Xnew, Ynew, t, u, p, q, w = NIPALS_internal(X__, Y__, n, M, N, u, epsilon)
        X__, Y__ = Xnew, Ynew
        W[:,i], T[:,i], U[:,i], P[:,i],Q[:,i] = w,t,u,p,q
    B = X_.T * U * (T.T * X_ * X_.T * U).I * T.T * Y_
    return (B, X_mean, X_std, Y_mean, Y_std)
Rのplsに付属のガソリンデータの読み込みと,既述のNIPALS(), NIPALS_predict()の利用シーンは次のような感じです.
def load_gasoline():
    f = open("gasoline.txt")
    reader = csv.reader(f, delimiter=' ', quoting=csv.QUOTE_NONE)
    octane, NIR = [], []
    for i, row in enumerate(reader):
        if i > 0:
            octane.append(int(row[0].strip('\"')))
            NIR.append([float(j) for j in row[1:]])
    return matrix(octane).T, matrix(NIR)

if __name__ = '__main__':
    Y, X = load_gasoline()
    tt = []
    t_y0, t_y1 = [],[]
    for h in range(2,26):
        s = 0
        for i in range(60):
            p = NIPALS(X, Y, h)
            Y_ = NIPALS_predict(p, X[i,:])
            t_y0.append(Y[i,0])
            t_y1.append(Y_[0,0])
            s += abs(Y[i, 0] - Y_[0,0])
        tt.append(s/60)

    gp = Gnuplot.Gnuplot(debug = 1)
    gp.xlabel('X')
    gp.ylabel('Y')
    gp('set grid')
    s = Gnuplot.Data(range(len(tt)), tt, title='error',with_='points 3 3')
    s1 = Gnuplot.Data(range(len(t_y0)), t_y0, title='raw',with_='line')
    s2 = Gnuplot.Data(range(len(t_y1)), t_y1, title='predict',with_='line')
    gp.plot(s, s1, s2)
    raw_input()
これを足がかりにして認識アルゴリズムに応用して性能を試すようなことを正月休みにやってみたいと思っていたけど,子供たちの喧騒の中でブログに書くのが精一杯でした.

休みも残すところ今日の半日と明日1日になってしまいました. そろそろ家出ゴロゴロしているのがだるくなってきたので,これからどこかへ出かけてみたいと思っていますが,人ごみは嫌いであり,はて どこへ行こうか,子供たちは雪遊びできるところへ行けば喜ぶに違いありませんが,心の底から雪遊びを楽しむ心を忘れてしまった私は,寒いばかりなので他にいいところは無いものかと考えるのですが,人ごみも苦手だし,あてもなく困ったものです.

勾配方向画像のHSV表示

HOG特徴とかEOH特徴を使ったスライド資料を作る時など,エッジの勾配方向をかっこ良く色分けした画像を載せると見栄えが良くなりわかりやすい.
その画像だけを作る労力もバカにならないと思うのです.例えばこんな画像のこと

左側は原画で,右側はソベルフィルター処理後に勾配の方向を求め角度によって色分け表示してます.HOGの著者Dalalさんたちの論文に掲載されている画像をイメージして作りました
盛岡の月が丘のあたりで研究用に撮影した画像のなのだけれどストックを手に散歩したおじさんが写っていた.乾いた路面の上なのだがきっとストックがあると足への負担が軽減されるのだろうか

こういう画像のような色分けをするときHSV色空間を使うのだけど使うたびに計算式を調べたりしている.ちゃんと自分のライブラリとして管理するべきなんだけど毎日使うわけじゃないのでつくったコードの存在自体を忘れる始末.毎回ググってる状態なのでいっその事ウェブに掲載してしまえば未来の自分が再利用する確率が高いのかも知れない

という訳でRGBからHSVに変換するコードを載せちゃいます.
プレゼン資料を作るための画像処理は,私の場合はPythonでお手軽にすませるこが多いです.
def hsv2rgb(h, s, v):
    h = float(h)
    s = float(s)
    v = float(v)
    h60 = h / 60.0
    h60f = math.floor(h60)
    hi = int(h60f) % 6
    f = h60 - h60f
    p = v * (1 - s)
    q = v * (1 - f * s)
    t = v * (1 - (1 - f) * s)
    r, g, b = 0, 0, 0
    if hi == 0: r, g, b = v, t, p
    elif hi == 1: r, g, b = q, v, p
    elif hi == 2: r, g, b = p, v, t
    elif hi == 3: r, g, b = p, q, v
    elif hi == 4: r, g, b = t, p, v
    elif hi == 5: r, g, b = v, p, q
    r, g, b = int(r * 255), int(g * 255), int(b * 255)
    return (b, g, r)#cv2.cv.CV_RGB(r, g, b)
よくブログなどに備忘録として掲載しますなどと書いてあることがあって正直なところ意味不明だと思ってたんだけどやっとその思考が理解できたようなつもりになったのでした

追記)
入力画像のエッジ勾配方向をHSV表示するスクリプトを公開しておきました.こちらです

2012年1月2日月曜日

ロマネスコ伐採完了

フタクタルな葉っぱの部分は茹でてマヨネーズにて食べるつもり
茎の部分が大きかったので薄くスライスしてニンニクと軽く炒めてみるのだ.

ただいま.茎の部分を炒めたのを食べてるところ.モグモグ...

キャベツとジャガイモを足して2で割ったような食感と味であります.
次は,フラクタルな葉っぱが楽しみです.





ロマネスコ発見

近所のスーパーで初めて見つけた。ジュリア集合みたいな野菜。食べ方知らないけど買ってみるかな

Android ADK+秋月電子USBホストマイコンボードのその後

Xperia X10を買ってから約1年半.
何か面白い事をやってやろうと思っているうちに時間はドンドンながれて,新しい機種が次々と発表されて,持っている機種への満足度は,指数関数的に減退していくのでございます.
中でもAndroid2.3.4から導入されたAccsessory Development Kitは,ぜひとも使ってみたい機能であったのだけど,私の古ぼけたX10では,使うことができなくて諦めていた.
そこへADKをサポートしたと思われるXperia X10用のカスタムファームを見つけてしまった.これが去年の7月ころのこと.
そのカスタムファームを導入すれば,あとはUSBホスト機能のあるマイコンを使って,Androidの周辺機器を作って楽しめるのではないかと睨んだ私は,まず安く手に入るUSBホスト機能のあるマイコンボードを探してみた.
目に止まったのは「秋月電子 H8 3069/USBホストボードキット」 価格は3000円也.
USBホストドライバーは,SL811が乗っかってる.使ったことはない.
このボードは2004年に発売開始された歴史のあるもののようなので,きっと誰かが使いこなす雛形ソースなどを公開していると期待して調べてみたが,予想は裏切られ見つけることが出来なかった.
サンプルソースコードがついていると秋月のサイトに書いてあったので,それを期待して購入したのだが,残念ながらサンプルとしてしか成立しないレベルの程度のものしかついていなかった.
仕方ないのでADKのArudino用サンプルソースを参考にしながら,H8 3069/USBホストボードで動作するADKデバイス開発を目指し,空き時間に作り込んでみることにしたのだが,今にいたってもADKデバイスを動かすところまでできていない.
なぜかというと,私がX10に導入したカスタムファームは,AndroidのJAVA階層レベルでは,ADKのAPIをサポートしているもののLinuxカーネルがADKに必要な機能を持っていないようなのだ.具体的に言うとカーネルバージョン2.6.29ベースではNGで,2.6.34といったバージョンが必要らしい.
やっとファームの方に,ADKの認識プロトコルを実装し,ADKの門前をくぐることができると期待していた私は,門前払いを受けたことに大いにショック状態となった.
しょぼいファームだけど,それなりにめんどくさい作業をしたので,文字通りガックリ状態.
Xperia X10用の2.6.34系カーネルが公開されるか,あと半年まって新機種に乗り換えるかするまで塩漬けするしかない.

折角つくったファームなので,こっそり公開させて頂きます.AKI-ADKソースコード
HOS-V4を使わせて頂いております.素晴らしいRTOSを公開いただきありがとうございます.
メモリー配置は,GDBでデバッグする状態になっているのでROMに焼いて動作するようにするには,リンカスクリプトをちょっといじらねばなりません.

このファームは,リセット後,ひたすらにUSBスレーブデバイスを探し続け,見つけると接続したデバイスを列挙し,もしAndroidケータイがつながっているなら,ADK接続モードになるはず.
きっと本家Androidならアクセサリとして認識されるんじゃないかと期待しております.
お金があればGoogleから,開発デバイスを買うんだけれどなあ.