2024年7月24日水曜日

ステレオカメラとか、キャリブレーションボードとか

 amazonで1万円くらいで売ってるステレオカメラをちょっと改造



 t1.6mmのガラエポなので、力をかけたら歪んだりするから、3Dプリンタでレンズマウントを作ったり、裏面に強い光が当たると透過して迷光が入るので、それの対策と三脚の取付穴を作ったり。元々は表側だけ作ったのでレンズマウントも兼ねているけど、ある程度の強度を追加して迷光対策+固定穴だけでいいなら裏面だけ作ればいい。

 FDMってベッドから剥がして冷却する間に歪むもんだと思ってたけど、冷え切って以降もある程度時間が経ってから少しずつ歪みが増えていってる気がする。溜まったストレスで塑性変形していってる感じなのかな。キャリブレーションが必要な光学系に使うにはちょっと困るかも。ある程度長期間経過してからキャリブレーションすれば安定するんだろうけど。


 ちょっと前からこの手のステレオカメラがamazonで売られるようになってきて、最近はいくつか種類が増えてきているっぽい。今回買ったものはその中でも比較的安い方の製品だからか、画質があまり良くない(USB 2.0の普通のUSBカメラの帯域幅でFHD2画面分を転送するので、圧縮率が高い)。とはいえちょっと遊ぶ程度には十分(画像処理に悪影響あるかもしれないけど)。

 今回買った製品は左右が同期しているタイプ。物によってはステレオカメラだけど左右非同期(2x USBカメラ + USBハブ)の製品も売ってるから、買うときは注意。見分け方としては、左右同期のカメラは中央に信号処理用のQFP系が乗っていて、左右非同期のカメラは中央にUSBハブのSOPが乗っている、みたいな判断もできるけど、これに限らない製品もあるだろうから、結局は祈りながら買うしかない。USBデバイスはPnP(plug and play)だけど、この手のデバイスはpray and pay(祈りながら買え)的なPnPになる。


 左右で同期しているので、扇風機を撮れば左右で同じように撮影できる。かなり強力な光をあてても止まるほどにはならない。多少は羽が伸びずに写るけど、とはいえローリングシャッターだからいかにも「ローリングシャッターです」的な画像にしかならないし。

 多少動きのあるものを撮っても左右で極端にずれたりはしないけど、とはいえ動いているものを見るのを目的に使えるほどではない。


 適当なキャリブレーションボードを撮ってOpenCVで処理すると、左右のカメラ行列と歪み係数は妥当性のある結果が得られる(まあ、ただのUSBカメラなので、当然)。

 StereoCalibrateでカメラ間の距離や姿勢を推定すると、距離は-59.07, 0.53, 0.257、くらいになって、実測60mmとほぼ一致する。姿勢の行列は[0,0],[1,1],[2,2]が0.9989,0.9996,0.9986くらいで、ほぼ平行(計算で無視できるほど並行でもないけど)。


 ステレオで撮影した画像に対してAKAZEで特徴点を検出してBFMatcherでマッチング、画像座標系点ペアを任意の座標系ベクトル(例えば左側のカメラ座標系)へ変換して、2本のベクトルの最近傍点を求める処理。

 ベクトルの最近傍点の座標をカメラ座標系(3次元)の点として、Z値に応じた色を表示している(外れ値でダイナミックレンジが悪化する対策で、両端0.5%のマーカーをサチらせた上で100mmでFloor/Ceilingを取ってスケーリングしている)。

 特徴点を探しているから、文字とか図形とか、特徴的な部分にマーカーが大量に出る。手前から奥に向かって妥当性のある結果になっている気がする。

 小さいリングは橙がマッチングできなかった特徴点を、緑がマッチングしたがベクトルの最近傍点の計算で誤差が大きかったものを示している。


 カメラの俯角を適当に想定して座標変換し、ほぼ水平面の点群をプロット

 外れ値も多いけど、わりと綺麗な結果が得られている感。ちゃんと壁に見える。

/* 古い本ばっかりだな。最近本全然買ってないからなぁ。。。ゲームグラフィックス好きだったのに最近売ってないのが残念 */


 ArUcoの姿勢推定とステレオカメラで深度推定

 ステレオでは所々に外れ値があるけど、ある程度一貫して推定できている。

 ArUcoの姿勢推定にはSolvePnPを使用している(SolvePnPRansacだとそれなりの割合で推定に失敗する)。

 ステレオのZ値とArUcoのZ値では5-10mmくらいずれるかな。どっちが正しいかは判断に悩むところだけど。


 ArUcoの外枠からステレオで深度推定

 1行目がId、2行目がArUcoマーカーからSolvePnPで求めたZ値、3行目がArUcoマーカー位置の視差から求めたZ値。

 左側左上のId0はマーカーが微妙に見切れているので、ArUcoの姿勢推定は実際よりも遠くにあると誤認している。右のカメラでは正しい大きさで認識しているので、正しそうな結果が得られている。ステレオベースでは位置が合わない(誤差が大きい)ので計算できていない。


 4x4pixel(枠含めて6x6pixel)のArUcoを7.5x7.5mmの大きさで、10mmピッチで配置

 ピントがずれると読み取れなくなる。ギリギリ読める場所でも、明らかに形が変わっていたりとか。

 視差(横軸)とSolvePnP(縦軸)。SolvePnPは青が左側、橙が右側の画像。

 傾向としては安定しているけど、オフセットやゲインのエラーが結構多い。キャリブレーションし直せばある程度は回復できるのかもしれないけど。視差はカメラの機械的強度で特性が大きく劣化しそうなのが使いづらそう。SolvePnPは焦点距離やフォーカスを固定している限り、カメラ行列や歪み係数は中長期的にある程度安定した結果が得られるはず。


***


 OpenCVにはChArUcoボードやダイヤモンド(Diamond)マーカーというのがあって、前者は任意の大きさのチェスボードの白い場所にArUcoマーカーを配置したもの、後者は3x3のチェスボードの白い場所4箇所にArUcoマーカーを配置したもの、だそう。

 ChArUcoボードを使うとチェスボードの交点を一意に決定できるので、一部しか写っていないチェスボードの曖昧さを解消できる利点があるんだそう。ただしOpenCvSharpはChArUcoは非対応っぽい。

 ダイヤモンドマーカーはOpenCvSharpでも検出に対応している(生成はたぶん自分で頑張る必要がある)。ダイヤモンドマーカーはArUcoを4個使っているが、複数のマーカーで同じArUcoを共有したり、一部を別のものに置き換えたり、みたいなことが自由にできるらしい。なので同じマーカーを複製して配置したり、あるいは小さなArUco辞書で多くのダイヤモンドマーカーを作成したりといったことができる。

 ただしダイヤモンドマーカーはあくまでも位置や姿勢を推定するためのマーカーとして使うものであって、ChArUcoボードみたいにカメラキャリブレーションに使えるようなものではなさそう。ChArUcoとダイヤモンドはあくまでも別の用途に使うものであって、どちらかがあれば十分、みたいなものではなさそうな気がする。


 チェスボードってキャリブレーションに使う場合はボケの影響が大きいみたいな話があったはず。で、ボケても基準点が変化しないドットパターンが追加された、みたいな流れのはず。ならChArUcoみたいな感じでドットパターンを使ったボード(ChArUcoがチェスボードArUcoなら、CrArUcoとか?)があっても良さそうな気がするけど、軽くググってもArUcoとドットパターンを組み合わせたような形は見当たらなかった。


 試しにAsymmetricCirclesGridの隙間にArUcoを埋め込むようなキャリブレーションボードを作ってみた。

 こんな感じのパターンで

 みたいに途中しか写っていない画像でも正しく認識できる。今回は手抜き実装なので、パターン(ドットの座標とArUcoIDの組み合わせ)は既知としている。

 で、実際に何枚か撮影してキャリブレーションに食わせてみたんだけど、あんまり綺麗に推定できていない感じ。通常のAssymetricCirclesGrid(13x17とか)は比較的少ない画像(10枚程度)でもかなりきれいに歪みを除去できるが、今回作ったキャリブレーションパターンで推定したobjectPoints/imagePointsの組み合わせからパラメータを推定すると、20枚くらい使っても周囲に歪みが残る。

 ということで、そこそこ苦労して実装した割には使い物にならねぇ、という結果。まあ、「画像認識」っぽい遊びができたので暇つぶしとしては面白い方ではある。

 元々はステレオカメラみたいに撮影領域の一部が重なったカメラに対して、キャリブレーションボードの一部が途切れていても使えるようなボード、というような目的だったわけだが、結局のところ、カメラ単体のキャリブレーションなら画角全体を使ってキャリブレーションするべきだし、カメラ間のキャリブレーションでも重なった領域を最大限使ってキャリブレーションするべきだし、基本に則って作業するなら通常のAsymmetricCirclesGridでも十分だよね、という話になる。


 OpenCVで円形の物体を認識しようとするとハフ変換を使う例が多く出てくるけど、今回はうまく使えなかった。ArUcoに挟まれた領域を小さい画像に切り出してから画像認識に渡すので、パラメータを追い込まないと狙い通りに動かないっぽい。

 今回は輪郭を検出してからfitEllipseで認識させるようにしてみた。ただ、今度は画像によっては輪郭を認識できないことがあったので、輪郭を抽出する前にOtsuで二値化してから輪郭抽出、楕円検出、みたいな手順を踏んでいる。結構複雑。

 それ以外はこれと言って変な処理も必要なく。ドットとArUcoの組み合わせが既知だから、先にArUcoを検出しておいて、foreachで舐め回す程度で検出できる。


***


 全然話変わるけど、車の衝突試験の画像解析とかに使う四角いマーカーって、正式な名前はなんていうんだろう?

 四角いマーカーって車でしか使ってないんだろうか? 例えば飛行開発実験団のF-2の写真(2011年)だとCenter of Gravityのマーカーみたいに円形のものが使われている。飛行機はCGみたいな形のマーカーを使いたがるのかな? 戦闘機でも民間用の自動車でも、画像解析ソリューションとしては大して変わらないだろうから、飛行機だからCGみたいなマーカー、車だからひし形のマーカー、みたいな使い分けはないはずなんだけど。

 とはいえ、飛実団のF-2のマーカーは綺麗にフレームに沿って貼ってあるような見た目。マーカーの位置を図面と照らし合わせやすいように、図面で位置が示されているフレームの継ぎ目とかに位置を合わせて貼ってあるんだろうけど、これが車になると、表面のボディは位置の基準となるものがないから、車の絶対座標に対してはあまり厳密に貼っていないような気がする。せいぜい実験前にキャリブレーション用の撮影を行って、衝突時に相対的にどれくらい動いたかを解析する、みたいな感じな気がする。とすると、飛行機用の解析ソフトと車用の解析ソフトは別物なんだろうか? どっちにしろ途中の処理がちょっと違う程度で画像処理としては大して変わらないはずだから一つのソフトでどっちも対応していそうな気もするけど。

 F-35のピットテストの写真とか見てみると黒い四角の中に白い円があってその中心に黒い円、さらにその内側に白いドット、みたいなマーカーが大量に貼り付けてある。画像処理アルゴリズムで見やすい(&精度の出る)形なら何でもいいんだろうな。大量にペタペタ貼ってあるし、フレームのラインとかに合わせてあるわけでもなさそうだし、相対的な変化を見る程度の目的っぽい感じ。


0 件のコメント:

コメントを投稿