ClojureでKinectをさわってみる

ClojureというとWeb系のお話が多い感じがしますが、[ClojureからKinectやAR.Droneを使っている人][clj-drone]もいるようですので、今回はClojureからKinectをさわってみたいと思います。


# 使用ライブラリ

Clojureのライブラリとしては、[Quil][quil]と[Bifocals][bifocals]を使います。Bifocalsは[OpenNI][openni]を利用しているので、OpenNIのインストールも必要です。

## Quil

[Quil][quil]は[Processing][processing]のClojureラッパーです。

簡潔なコードで図形を描くことができるなど、グラフィカルな出力を得られます。今回はBifocalsで取得したKinectのデータを描画するのに使用します。

最新バージョンは **1.6.0** です。

```clj:project.clj
[quil "1.6.0"]
```

## Bifocals

[Bifocals][bifocals]はClojureからKinectを扱うためのライブラリです。

Processingには[simple-openni][simple-openni]という有名なOpenNIのラッパーライブラリがあります。Bifocalsはsimple-openniのラッパーみたいな感じです。

最新バージョンは **0.1.0** です。

```clj:project.clj
[bifocals "0.1.0"]
```

## OpenNI

[OpenNI][openni]は3Dセンサ向けのオープンソースのSDKです。Kinectだけでなく様々な3Dセンサに利用できます。

OpenNIは現在バージョン2系になっていますが、今回の記事では **v1.5.2.23** を用いています。BifocalsからOpenNI2が利用できるかは確認していません。

OpenNIのインストール方法はググれば色々と出てくるのでそちらを参照ください。ちなみに、Mac + Homebrew環境であれば、私の作成した[homebrew-openni][homebrew-openni]を使うと簡単です！（ステマ）


# Kinectにアクセス

`ns`にQuilとBifocalsを追加します。

```clj
(ns cljac16.core
  (:require [quil.core :refer :all]
            [bifocals.core :as bifocals]))
```

`setup`関数とsketchの定義は以下のようにしておきます。

```clj
(defn setup []
  (smooth)
  (frame-rate 30))

(defsketch kinect
  :title "Can Haz Kinect!"
  :setup setup
  :draw draw
  :size [640 480])
```

## Depth

距離画像を取得・表示するには、`draw`関数に以下のように書きます。

```clj
(defn draw []
  (background 0)
  (bifocals/tick)
  (image (bifocals/depth-image) 0 0))
```

`draw`関数内で必ず`bifocals.core/tick`を呼ぶ必要があります。`tick`関数によってKinectのデータが更新されるので、毎フレーム呼び出しています。

`bifocals.core/depth-image`は距離画像をProcessingのPImageインスタンスとして返します。`quil.core/image`によって距離画像を表示しています。

![bifocals-1.jpg](https://qiita-image-store.s3.amazonaws.com/0/24168/ccbf6f0d-b20b-8d54-17d4-9c6f95afd156.jpeg)

## スケルトントラッキング

```clj
(defn- draw-line
  [p1 p2]
  (line (:x p1) (:y p1) (:x p2) (:y p2)))

(defn- draw-skeleton
  [skeleton]
  (let [{:keys [head neck left-shoulder right-shoulder left-elbow right-elbow
                left-hand right-hand torso left-hip right-hip left-knee
                right-knee left-foot right-foot]}
        (bifocals/project-skeleton skeleton)]
    (stroke 30 120 180)
    (stroke-weight 3)
    (draw-line head neck)
    (draw-line neck left-shoulder), (draw-line neck right-shoulder)
    (draw-line left-shoulder left-elbow), (draw-line right-shoulder right-elbow)
    (draw-line left-elbow left-hand), (draw-line right-elbow right-hand)
    (draw-line left-shoulder torso), (draw-line right-shoulder torso)
    (draw-line torso left-hip), (draw-line torso right-hip)
    (draw-line left-hip left-knee), (draw-line right-hip right-knee)
    (draw-line left-knee left-foot), (draw-line right-knee right-foot)))

(defn draw []
  (background 0)
  (bifocals/tick)
  (image (bifocals/depth-image) 0 0)
  (doseq [skeleton (vals @bifocals/skeletons)]
    (draw-skeleton skeleton)))
```

`bifocals.core/skeletons`というatomに画面内に入っている人物のスケルトンデータが入っているので、それを取り出して描画しています。

また、`bifocals.core/project-skeleton`関数によって、3次元のスケルトン座標を2次元のカメラ座標系に変換しています。

![bifocals-0.jpg](https://qiita-image-store.s3.amazonaws.com/0/24168/113d3ec9-765a-267a-e275-0fea4bd29f7d.jpeg)

# 所感

かなり簡単にKinectにアクセスすることができました。今回の記事では距離画像とスケルトン情報の取得だけを紹介しましたが、Bifocalsの[example][bifocals-example]では人の数を検出するやり方なども含まれています。

少し気になる点としては、QuilやBifocalsは最近は更新されていなくて、Processingやsimple-openniに追従できていない気がします。ですがClojureはJavaに簡単にアクセスできるので、Bifocalsを使わなくても、直接OpenNIのJavaバインドを呼び出してもいいかなと思います。

KinectやAR.Drone、Arduinoなどを扱うフィジカル・コンピューティングの世界にもClojureがさらに進出してくれたら良いなと思います。

[clj-drone]: http://nakkaya.com/2013/02/20/controlling-an-ar-drone-with-the-kinect-and-clojure/
[quil]: https://github.com/quil/quil
[bifocals]: https://github.com/aperiodic/bifocals
[openni]: http://www.openni.org/
[processing]: http://www.processing.org/
[simple-openni]: https://code.google.com/p/simple-openni/
[homebrew-openni]: https://github.com/totakke/homebrew-openni
[bifocals-example]: https://github.com/aperiodic/bifocals/blob/master/examples/bifocals/examples/2D.clj