2012/01/30

マーカー検出計画2 OpenGL上で自作マーカーを使う

昨日作ったマーカー検出用関数を、OpenGL側で利用してみました。
マーカー上10cmの所に、球体を描画しています。
マーカーごとにIDはデコードしているのですが、今回はひとまず全部に同じ球体を描画しました。IDごとでSwitchすれば、色々な物体を表示することができるようになると思います。

ただの線よりも、立体的な物体が出たほうが楽しいですね。

マーカーの仕様や、関数の使い方をもう少しまとめてから別館の方にUPする予定です。
ではまた。

2012/01/29

マーカー検出計画2 マーカー検出プログラムの改良

今日はマーカー検出部分を作成していました。1年半前に作ったマーカー検出プログラムはあまり再利用できる感じではなかったのでほぼ全部書すことに。

今回は単機能の関数を複数作り、それぞれの関数をつなげてパイプライン方式で処理する形にしました。関数ごとに機能を絞ったので、デバッグがしやすくなりました。作った主な関数は以下の通りです。

  • マーカーの四角形を検出する関数
  • マーカーの2次元コードをデコードし、マーカーの向きを調べる関数
  • マーカーの頂点座標を整列する関数
  • マーカーの頂点座標から、移動ベクトルと回転ベクトルを計算する関数


キャプチャした画像を上にある関数から順に処理していくと、

  • 画像内にあるマーカーの数
  • マーカーの識別番号(2次元コードをデコードしたもの)
  • マーカーの頂点座標(外側、内側)
  • マーカーの移動ベクトル、回転ベクトル

が得られる形になっています。

今回作った関数を使って、OpenCV内で軸を描画してみました。
マーカーの識別用エリアは8ビット分に設定し、ビットの大きさは1センチ四方、マーカーの全体の大きさは9センチ四方としました。
描画する軸の大きさは45mmで指定しています。

赤:X軸 緑:Y軸 青:Z軸


チェスボードに比べて、コーナーの数が少ないため軸がプルプル震えてしまいますが、対策はまた後で考えることにしてOpenGL側で複数の物体を表示させる実験を先に行おうと思います。

ではまた。

2012/01/28

マーカー検出部分の見直し

OpenCVとOpenGLを組み合わせて、ARオブジェクトを実寸で表示できるようになりました。(光源の設定などまだ課題がありますが)

今まではチェスボードを対象にしていましたが、やはりマーカーなどを使用して識別できるようにしたいところ。なので1年以上前に作ったマーカー検出プログラムを作り直しています。

マーカーの位置検出方法ですが、OpenCVのcvFindContoursとcvApproxPolyを使って、四角形っぽい輪郭を抽出しています。
FindContoursがどういう動きをするのか気になったので、頂点ごとに番号を自動的に振ってみました。


ざっとみた感じだと、外側の輪郭は反時計回り、内側の輪郭は時計回りで検出されているようです。外側と内側で検出される順番が同じだったらそのまま使えたのですが、検出される順番は信用せず、外側の頂点に一番近いところを探してやる必要がありそうです。

OpenGLに移動ベクトルと回転ベクトル、マーカーの識別番号のリストを渡せるように変更すれば、OpenGL側で別々のオブジェクトを表示できるようになると思います。

ではまた。

2012/01/25

マーカー検出計画2 3Dモデルをチェスボード上に表示

OpenGLで実寸表示できたので、今日は3次元モデルを表示する方法を探していました。
objファイル形式というものがいろいろなソフトでサポートしているようなので、objファイルを使うことにしました。
 OpenGLで遊ぼう6 -まとめ!- @毛の生えたようなものにobjファイルの取り込み方について書かれていたので、参考にして実装してみました。読み込ませる3次元モデルは、Blenderで作りました。Blenderはフリーの3次元モデリングソフトで、いろいろなプラットフォームで使えます。ダウンロードして使ってみましたが、機能が多すぎて使い方がよくわからず。その結果、なんだかよくわからない物体が出来上がりました。

Blenderで作った謎のモデル
glutのサンプルコード内に含まれている、glm.cというファイルにobjファイルを読み込んで描画する機能が実装されているので、モデルを渡して描画してもらいました。

glmを使ってobjファイルを描画
真っ黒になっていますが、謎モデルの形が画面上に出ています。
塗りつぶされているのは光源の設定がよくないからかもしれません。

glm.cとは別になりますが、OBJ2OPENGLというobjファイルをヘッダファイルに変換して、ソースコードに組み込めるようにするスクリプトもあるようです。こちらはOpenGL ES用もあるみたいです。


これまでのまとめ
  • OpenCVでカメラのキャリブレーションを行い、カメラの内部定数を求めた
  • OpenGLのProjectionMatrix にカメラの内部定数から計算した値を入れ、OpenGL上の座標をミリ単位で指定できるようになった( 参考:POSIT tutorial@OpenCVWiki
  • Blenderで作成した謎モデルをobjファイルにエクスポートして、GLUTに入っているglm.cを使ってOpenGLで描画した

参考資料
詳解OpenCV カメラキャリブレーションの章
コンピュータビジョン ピンホールカメラの章。高いけど詳しい本です。

OpenGLのProjection Matrix関係
POSIT tutorial@OpenCVWiki Projection Matrixを生成して、glLoadMatrixで読み込む方法。なぜこの数式になったのかの検証はまだしていません。
From Homography to OpenGL Modelview Matrix glFrustrumを使う方法。まだ試していません

今後の課題

  • カメラの内部定数からOpenGLのProjection Matrixを求めるところについてもう少し調べる
  • ソースコードが継ぎはぎ状態なので関数にまとめる
  • Blenderでパイプ椅子ぐらいは作れるようにする
  • OpenGLの光源について調べる


別館に、現時点でのソースコードをアップしておきました。ソースコード、今回使用しているチェスボードのPDF、謎の3Dモデル、カメラの内部定数ファイルを含めています。
ビルド環境はUbuntu 11.10 64bit と, Mac OS X 10.5.8です。OpenCVのバージョンは2.2を使用しています。

CGは難しいなぁ。

ではまた。



マーカー検出計画2 OpenGLの座標軸をミリ単位にする

先週はOpenGLの画面バッファにIplImageを表示するところまで作成しました。
OpenGLでマーカー上に現実上のサイズを指定して物体を書く場合は、OpenGLの座標単位をマーカーの座標単位にする必要があります。
Posit@OpenCV wikiに、カメラの内部定数などを使用して、座標系を合わせる方法が書かれていたのでコードを借りてみました。

そしたらこんな感じで表示できるようになりました。



マーカーのサイズは20mmで印刷しており、OpenGL上ではglutWireCube(100) と描画命令を出しています。
画面上でマーカーのサイズ5つ分=100mmとなっているので、ほかのオブジェクトもサイズをミリ単位で指定できると思います。

次は3Dモデルの読み込みを調べたいと思います。
椅子とかを部屋の中に置いてレイアウトのシミュレーションできる感じのものを作れればいいな〜。

ではまた。

2012/01/22

OpenCVのIplImageをOpenGLで使用する

OpenCVで取得したカメラ画像に、3Dオブジェクトをオーバーレイするためには、
OpenCVの画像をOpenGL側の背景に設定する必要があります。

色々なサイトをみたところ、glDrawPixels関数を使えばIplImage形式の画像を描画することができるようです。

というわけで実装してみました。

OpenCVで取得した画像を背景に、OpenGLで急須を描画

処理の流れ:
  • OpenCVでWebカメラから画像を取得する
  • 取得した画像(IplImage)のデータ部分を、glDrawPixel関数を使って描画
  • そのあとOpenGLのオブジェクト(今回はglutWireTeapot)を描画
  • 毎フレーム繰り返す

ひとまずOpenGLのウィンドウにIplImageを表示することができました。

次はOpenCVのcvFindExtrinsicCameraParams2で求めた回転ベクトルと移動ベクトルをOpenGL側のオブジェクトに反映させる方法について調べようと思います。

サンプルコードは別館の「マーカー検出」に置いてあります。

ではまた。

2012/01/18

チェスボードパターン上に3軸を表示する

今日はカメラのキャリブレーションで使う、チェスボードパターン上に3軸を表示するプログラムを作成していました。

コードはまだ汚い状態なので、ひとまず流れだけ書いておきます。

最初に、カメラの内部定数を求めてファイルに保存しておきます。
そのあと、ファイルから内部定数を読み込み、各画像の特徴点(今回はチェスボードの頂点)をcvFindChessboardCornersを使って計算します。
次に、特徴点をさらに高精度化するために、cvFindCornerSubPixに渡します。

画像上の特徴点座標、カメラ内部定数(intrinsic,distortion)、物体上の特徴点座標がわかったので、次は移動ベクトルと回転ベクトルを計算しす。cvFindExtrinsicCameraParams2にまとめて放り込むと計算してくれます。

移動ベクトル(3x1)と回転ベクトル(3x1)が求まれば、あとは好きな座標(今回は物体上に表示したい軸)をcvProjectPoints2を使って変換すると、画像上のどこにくるかがわかります。








今回はcvProjectPoints2に任せてしまいましたが、行列の勉強のため、cvProjectPoints2を使わない方法でもやってみたいと思います。

ではまた。

2012/01/17

マーカー検出計画 再び

Arduinoタンク計画に若干飽きてきたので、OpenCVでマーカー検出をして遊ぼうかなと思っています。

今回は検出したマーカーの上に、”きちんと”3Dオブジェクトを表示させたいと思います。
まずは、カメラのキャリブレーション用のチェスボードに、X、Y、Z軸を表示するのと、Ogre3Dなどのライブラリを使ってOpenGLでのオブジェクト表示にチャレンジしてみたいと思います。

とりあえず今日は詳解OpenCVのカメラキャリブレーションの章を読み直ししてます。


マーカー検出した後の処理に役立ちそうなリンクは以下の通り。
2次元マトリックスコードを利用した拡張現実感の構成手法
(1996年の論文だそうです。OpenCVがなかった頃に2次元マーカー検出を実現しているのが凄い!)
座標変換
グラフィックス@ゲームプログラミングwiki
書籍:詳解OpenCV(O'reilly)
書籍:実例で学ぶゲーム3D数学(O'reilly) <-行列と線形変換の章がサンプルで読めます

ではまた。

2012/01/13

ママチャリGP用GPSシステムの反省

1月8日に富士スピードウェイでママチャリGPがありました。
ライダーとしても参加しましたが、今回の主な目的はGPSシステムのフィールド
テストです。
今回持っていったGPSシステムの構成は以下の通りです。

送信機側:
XBee ProとGPSモジュール(GT-723F)、OpenLogを合わせたもの
Eneloop8本直列したものをDC-DCコンバーターを使って3.3Vに調節した電源を使用
送信機側を全部タッパーにつめて、自転車の前かごにガムテープで固定。

受信機側:
XBee ProとArduino、e-Dispの組み合わせ。送信機から送られてきた生のGPSデー
タを、Arduinoで解析してe-Dispに表示するようにプログラムを作成。バッテ
リーはQE-PL201を使用。省電力モードを積む時間はなかったので全部つけっ放
し。受信機側のXBee Proは、2Mぐらいの高さに設置した。

送信機側コスト:
XBee Pro ZBワイヤアンテナ型 2,500
GPSモジュール GT-723F 3,500
OpenLog 2,500eneloop(単三) x 8本 2,400
DC-DCコンバータ(CE-1004-TP) 500

受信機側コスト:
Arduino Uno 3,000
小型LCD e-Disp3 4,500
USB電源 Panasonic PL201 4,000
ユニバーサル基盤、レギュレータ 500ぐらい

・・・全部新品で買うと2万ぐらいかかりますね。秋月電子かスイッチサイエン
スで部品はそろいます。e-Dispは桜パーツで買いました。


実験結果

送信機側の電池:8時間程度動作した後の電圧は10.4V。まだまだ電池は元気そう
なので20時間具合は問題なく動くかも。
GPS+OpenLogについて:GPSの精度は問題なし。1秒間隔で出力されるデータを7時
間程度OpenLogで保存すると6MBになるが、OpenLogに挿してあるSDカードの容量
は2GBあるのでかなり余裕あり。

受信機側の電池:5時間ほど稼動させたところでランプがオレンジになった(≒残容
量70%を切った)ので、10時間程度は持ちそう。e-DispのバックライトをOn/Offす
ればもっと稼働時間は延びるはず。

XBeeの通信距離について:思った以上に通信距離が伸びなかった。通信できた最
大距離はピットロードの直線での200m程度。建物があるとほとんど通信できず。

という訳で、今年のGPSシステムはいまいちな結果になりましたが、GPSの生ログ
が取れたのと、消費電力量のデータもとれたので、来年のGPSシステムの基礎
データとして活用できそうです。


来年に向けての計画:
  •  客席側のほうが見通しがよいので、客席最終コーナー寄りにルータ設定のXBeeを設置して通信可能エリアを拡大し、マルチホップでデータがピットに届くようにする。障害物はほぼ無いので最終コーナーを曲がってきたところぐらいから通信できるようになるはず。
  •  自転車の位置情報を最終コーナー付近からピット付近に絞って、より見やすい画面(or 基盤)にしておく。e-Dispは表示しやすくてよかったが、みんなで見るには画面が小さすぎた。LEDを20個ぐらい基盤につけて、点滅させたほうが現地ではわかりやすいかもしれない。

その他基礎実験系:
  •  見晴らしが良く、小さい丘があるところなどで、実際のところ何メーターぐらいXBee Pro同士で通信できるかを確認する。 
  • 2.4GHzの電波(というか電波自体)について勉強しておく。
  •  XBeeによるメッシュネットワークの構築をできるようにしておく。
  •  もう少し上位にいけるように筋トレ。