openFrameworksをやっていて詰まったのでとりあえずOpenCVをやってみることにした。

openFrameworksはOpenCV・OpenGL・シリアルポート関連・音声関連のC++ライブラリをまとめたWin/Mac/Ubuntuで動作するクロスプラットフォームラッパーで、processingの影響を受けているらしいのだが、その中のOpenCVとOpenGL自体がまず巨大なライブラリなのでこいつらを扱う作法を知っていないとopenFrameworksが使いこなせない。


今回はOpenCVを単体で扱ってみてどんなもんか探ってみた。


■OpenCVのセットアップ、サンプル実行、コンパイル環境と対応カメラの確認

マシンに3つOSが入っているので実行環境も3つ揃えてみた。
MacとUbuntuはgccで、WinはVS2008でコンパイル。Ubuntuは色々ためしたけどiSightを認識しなかったが古い外付けUSBカメラを認識して使えた。
この内Macだけが駄目。描画が異常に重い。ググったらhighguiとCarbonの組み合わせが悪さしている?ような情報もあったがよくわからなかった。でもちゃんと動いていると報告してる人がたくさんいる。悔しい。

最近は全部パッケージ管理システムから入るんですね


本当はMacかUbuntuで動かしたかったけど、WindowsでVS2008でやる事にした。
俺が電車で移動中プログラムを書く事が多いので、Windowsからは内蔵i-Sightを使えて一番都合が良い。

cvWaitKey(msec)の待ち時間を短くしすぎなければ(30ぐらいなら大丈夫)どの環境でも動く事が確認できたので、後述するプログラムはどの環境でも動くと思う。少なくともWindowsとUbuntuでは動いている。



■画像処理の勉強

この本でやった。プログラムの途中重要な定数宣言部分が省略されまくったりしていて困ったけど、理論的な所は詳しく解説してくれているのでこの本と翻訳版ドキュメントサンプル集を見ればなんとかなった。


OpenCV プログラミングブック
奈良先端科学技術大学院大学 OpenCVプログラミングブック制作チーム
毎日コミュニケーションズ
売り上げランキング: 58513
おすすめ度の平均: 3.0
3 とっかかりとしてはよい本
4 OpenCVを日本語でまとまって解説した初めての本
2 肩すかし


OpenCVというとまっさきに「顔認識」を思い浮かべるけど、機械学習を用いた分類器については巻末のリファレンスに少し書かれている程度で、この本では基本的なOpenCVの組み込み関数を使った2値化やノイズ除去や表色系の変換、輪郭、エッジ抽出、テンプレートマッチング、物体追跡、背景差分法などが書かれている。書かれている内容はbuilt with processingディジタル画像処理の基礎と応用なんかに書かれている内容と被っている部分が多いけど、OpenCVの関数を使っているから滅茶苦茶処理が速い。やばい。もっと早くOpenCVに移れば良かった。





サンプルを自分なりに改変しながら写経していった。
肌色領域検出


肌色領域検出でわかったのは、OpenCVでの画像処理で一番特徴的な「お作法」は画像データ(IplImageオブジェクト)同士を集合の様に扱って、論理積や差などを取るためのcvAndやcvSubなどの関数を使うこと。今までProcessing等でピクセルを1つずつ走査していって数値として計算していたが、そうではなく集合同士をガッと合わせて処理させてしまえばほとんどメモリの中でのビット演算で済むので、めちゃくちゃ速い。
OpenCVのIplImageを扱う関数は全ピクセルに同じ条件でまとめて処理を行う関数ばかりなので、ちょっと考え方を改めるのに頭が疲れた。


ここから、サンプルで「2値画像をいじる処理」が良く出てくるようになったので、自分で赤色領域を検出するプログラムを作ってその2値画像に対するアルゴリズムだけ適応していってみた。

赤色領域を検出(1)
RGB要素をそれぞれ調べて、赤いところを抜く。これはRGBそれぞれcvThresholdで2値化して、論理和を求める。
ついでにcvSetMouseCallback()マウスイベントを取り、マウス位置のピクセルのRGB要素の値を調べてコンソール出力もした。これでdebugしやすい。
detect red


赤色領域を検出(2)
(1)のアルゴリズムだと暗い場所では色が変わって認識できないので、青・緑の要素より相対的に赤がある比率以上の場所を抜き出すようにした。cvDivで赤と青、赤と緑の比率を計算しそれぞれcvThresholdで一定以上の比率の場所を抜き出し、論理和を取る。
detect red


赤色検出
同じプログラムをVMWare+Ubuntuでも動かしてみた。あっさり動いた。
detect red


収縮・膨張で砂嵐ノイズフィルタ
砂嵐ノイズを消す方法。速い。
背景差分背景差分+ノイズカット


赤色領域を検出(3) 重心も計算
2値画像から一発で重心を求められるcvMomentsで計算した。
赤色検出+重心計算


赤色領域を検出(4) 輪郭を囲む
2値画像から一発で輪郭を探索してくれるcvFindContourを使って、青い線で囲む。何個あるかもわかってしまう。
detect contour of red



C++だけど、OpenCVで実装したプログラム自体は高度なプログラミングテクニックが使われているわけではない。
webでいろいろな人が公開しているサンプルを見ても、上から処理が降りてきて画像処理用のメモリ領域を確保し、while(1)で毎フレームカメラを処理して、cvWaitKey()でキーボード割り込みで終了できるようにしつつ、ループの中で画面表示を更新し続けるだけという単純なものだった。まるでマイコンそっくりの構成。

逆に言えばOpenCV単体ではカメラ入力をいじった結果をフルスクリーンで表示する位しかできないので、それ以上の事をやるにはopenFrameworksを使うとかした方がいいんだろうと思う。
一応highguiというGUI部品も同梱されているが、基本的なボタンやスライダーがあるだけ。


で、本を一応最後まで読んだので、あとはopencv.jp – OpenCV サンプルコード –を見たりして応用的なアルゴリズムや関数を見たり、機械学習ライブラリの使い方を(使う予定が無いけど)見ておくぐらいか。
いよいよ実戦投入のために自分のプロジェクトのコードを書かなければ。