garaemon.net: 脳汁でコードを書く!

CommonLispでsleep sort
Posted at 20 May 2011

sleep sort

巷でsleep sortというのが話題になっていたので, CommonLispでかいてみた.

(require :bordeaux-threads)

(defun sleep-proc (n)
  (sleep n)
  (format t " ~A~%" n )
  n)

(defun sleep-sort (list)
  (let ((all-threads
         (mapcar #'(lambda (n)
                     (BORDEAUX-THREADS:MAKE-THREAD
                      #'(lambda () (sleep-proc n))))
                 list)))
    (dolist (thread all-threads)
      (bordeaux-threads:join-thread thread))))

(defun demo-sleep-sort ()
  (let ((sample-data '(5 3 6 3 6 3 1 4 7)))
    (sleep-sort sample-data)
    ))
(demo-sleep-sort)
 1
 3
 3
 3
 4
 5
 6
 6
 7

bordeaux-threadsかわいいよ.

jekyll
Posted at 18 Jan 2011

今まで, blogをorg-blogで書いていたのですが, やっぱ自分で書いたプログラムはメンテが面倒なので, jekyllに移行しました.

jekyllはgithubのサイト構築にも利用できるので, 一元化しようという狙いもあります.

OpenNI + Kinectで複数人追跡
Posted at 10 Dec 2010

複数人追跡

なんか少しTLで話題になってたので, 複数人追跡の動画もあげてみました. プログラムの走らせ方は前回 と同じです.

走らせてるのは割と普通のLaptopです(Core2Duo).

特別出演は僕の妹です.

OpenNI + Kinectの動かし方
Posted at 09 Dec 2010

OpenNI

なんかすごいことになりました. PrimeSense(Kinectの開発元です)がソフトウェアのバイナリ を公開しました. その人認識がとても素晴らしいので, 簡単に紹介します.

OpenNI はオープンなミドルウェアフレームワークです. 肝心の人認識とかはソースが見れないので 注意されたし. 基本的にここに書いてある情報は, このwikiに書いてあります. 最新情報はここ を参考にしたほうが良いです.

ROSでOpenNIのインストール

ターゲットはubuntu 10.04です. windowsとか知らないのであしからず. このインストールは, あえて ROS でやりましょう. ROS普及のためにも.

まず, 以下のコマンドを実行してrosinstallを入れましょう.

$ sudo aptitude install build-essential python-yaml cmake wget python-setuptools subversion mercurial git-core
$ sudo easy_install -U rosinstall

で, いろいろインストールします. 僕はソースコードから入れるのが好きなので, 以下のコマンドを打ってしばらく待ちましょう

$ rosinstall --rosdep-yes ~/ros http://garaemon.net/rosinstall/kinect_openni_small.rosinstall

ROSをすでに使ってる人は適時rosinstallファイルを修正してね! kinect_openni_small.rosinstallはkinect関係と, cturtle_base をあわせただけのものです.

次に, コンパイルします. 現状64bit linuxにしか対応してませんが, 32bitもすぐ対応するでしょう. (少し変更したら32bitでも通ることは確認済みです)

$ source ~/ros/setup.sh # ~/.bashrcに追加したほうがいいよ!
$ rosmake ni --rosdep-install --rosdep-yes

OpenCVとかmakeするので結構時間がかかるかもです.

OpenNIを走らせる

では実行する前に少しおまじないをします.

$ sudo cp `rospack find ps_engine`/install/55-primesense-usb.rules /etc/udev/rules.d/

そしたらkinectをPCにつなぎます. (もしくはreboot)

追記

以下が必要かも

$ roslaunch openni_camera openni_kinect.launch

そんでもって, 以下を実行

$ export XN_SENSOR_VENDOR_ID=0x045E 
$ export XN_SENSOR_PRODUCT_ID=0x02AE
$ export XN_HOST_PROTOCOL_ALGORITHM_REGISTRATION=0x40
$ rosrun openni Sample-NiUserTracker

人認識良い感じですね. キャリブレーションの為にはY字になる必要があります(90度を意識する). 動画 もあげてるのでこっちもみると雰囲気がわかるかも.

興味を持った人は PCLも要チェックです.

しつもんがあれば @garaemonまで.

CL数学処理ライブラリ nurarihyon 02
Posted at 23 Nov 2010

nurarihyonのAPI

前回 のつづき. nurarihyon が提供する関数のAPIのほとんどは, 2種類提供されます.

  • 安全にコンパイルされた関数. 例: v+, v., ...
  • 高速なコンパイルされた関数. 例: $v+, $v., ...

速度を重視した関数は, "安全な関数"の先頭に$をつけた名前で提供されます.

これらは, define-nhfunというマクロで定義され, 安全な関数は(optimize (safety 3) (debug 3))でコンパイルされます.

また, 高速な関数は(optimize (speed 3) (safety 0))でコンパイルされます.

高速な関数のコンパイル時には, *nurarihyon-optimization*がtとなり, nurarihyonで定義されているコンパイラマクロの展開が変化します.

このように, 2種類のAPIを提供している理由は, CLでは, 高速側にコンパイラを振ると, 非常に不安定になってしまうためです.

たとえば, 以下のようなadd関数をSBCLで定義してみます.

(defun add (a b) 
   (declare (optimize (speed 3) (safety 0)) 
            (type double-float a b)) 
    (+ a b))

これを, single-floatでよびだすと...

(add 1.0 2.0)
=> Unhandled memory fault at #x322C800.
     [Condition of type SB-SYS:MEMORY-FAULT-ERROR]

となり, 非常にデバッグが難しくなります.

と, 前口上はこの辺にして, 今回はベクトル演算について少し見ていきます.

ベクトルの作成

nurarihyonはいくつかのベクトル作成関数を提供します. 以下のようなものです.

(nh:make-vector 5) ; => #(0.0d0 0.0d0 0.0d0 0.0d0 0.0d0)
(nh:make-vector3) ; => #(0.0d0 0.0d0 0.0d0)
(nh:make-vector4) ; => #(0.0d0 0.0d0 0.0d0 0.0d0)
(nh:double-vector 1 2 3 4 5) ; => #(1.0d0 2.0d0 3.0d0 4.0d0 5.0d0)

ベクトルの加減

v+, v-という名前で提供されます.

(nh:enable-nurarihyon-reader-syntax)
(nh:v+ #d(1 2 3) #d(4 5 6)) ; => #(5.0d0 7.0d0 9.0d0)
(nh:v- #d(1 2 3) #d(4 5 6)) ; => #(-3.0d0 -3.0d0 -3.0d0)

これら, というかベクトルや行列を返す関数のほとんどは最後にoptional引数をとります. ここで, 演算結果を格納する配列を予めわたしておいてやることができます. CLでoptimizationをするなら, いかにヒープアロケーションを少なくするかがキモだと思うので.

(let ((buf (nh:make-vector 3)))
  (let ((ret (nh:v+ #d(1 2 3) #d(4 5 6) buf))) ; => #(5.0d0 7.0d0 9.0d0)
     (eq ret buf))) ; => T

さらに, はじめで述べたように, 高速版の関数も提供されます.

(nh:$v+ #d(1 2 3) #d(4 5 6)) ; => #(5.0d0 7.0d0 9.0d0)
(nh:$v- #d(1 2 3) #d(4 5 6)) ; => #(-3.0d0 -3.0d0 -3.0d0)

$vや$v-はベクトルの長さの確認を行わないことに注意!.

(nh:v+ #d(1 2 3) #d(4 5)) ; => vector dimension mismatch: #(4.0d0 5.0d0) is required to be 3 dimension エラーになる
(nh:$v+ #d(1 2 3) #d(4 5)) ; => #(5.0d0 7.0d0 3.0d0) 何も気にせず結果がreturn!

ベクトルの内積

内積はv.という名前です

(nh:v. #d(1 4 6) #d(-1 2 3)) ; => 25.0d0

ベクトルの外積

外積はv*です. 長さ3のベクトルのみを対象とします.

(nh:v* #d(1 0 0) #d(0 1 0)) ; => #(0.0d0 0.0d0 1.0d0)