Triclops ライブラリを用いた3次元画像処理 技術解説ページ

Triclops ライブラリを用いた 3 次元画像処理 技術解説
・ Step1
レクティファイ (歪曲収差補正) とライブラリの初期化
レンズを通して画像を取得すると、光学的な問題で周辺部分の画像が歪んでしまうことがあります。これが
歪曲収差です。広角レンズの場合は周辺が膨らむ「糸巻き型」になりやすく、望遠レンズの場合は「樽型」
になりやすいのが特徴です。
樽型
糸巻き型
レンズごとにこの収差の度合いに個体差があります。そのため、ステレオ処理を行う前にこれを補正し歪み
をとる必要があります。
Triclops ライブラリでは「キャリブレーションファイル」を用いて補正します。
「キャリブレーションファイ
ル」は拡張子が cal のファイルで、レンズごとに固体データが記述されたものです。Digiclops や BumbleBEE
ではこの情報はカメラ内のメモリに記録されていますが、MiniBEE ではファイルとして提供されています。
そのため、MiniBEE では Triclops ライブラリを初期化する時にこのファイルを指定して固体情報を読み込
んで下さい。
ライブラリを利用するためにはまず、コンテキストと呼ばれるワークスペースを作成します。実行時のパス
の通ったフォルダへ上記のキャリブレーションファイルをコピーしておく必要があることに注意して下さい。
//コンテキスト(ワークスペース)変数の宣言
TriclopsContext StereoContext;
//キャリブレーションファイルを指定して初期化
triclopsGetDefaultContextFromFile( &StereoContext ,
キャリブレーションファイル名
);
MiniBEE の場合は AD カメラセット及び BC カメラセットの二つがありますのでそれぞれを初期化する必要
があります。また、取得した距離の計測値は各カメラセットの右側レンズの中心点付近を原点とした座標系
となります。すなわち AD セットと BC セットの座標系が異なってしまうため、片方の座標系をもう片方に
あわせて同一座標系上のデータとする必要があります。
//MiniBEEキャリブレーションファイルの読込み
TriclopsContext StereoContext[ 2 ];
triclopsGetDefaultContextFromFile( &StereoContext[ 0 ] , “minibee_xxxxxxxx_AD.cal” );
(1)
ViewPLUS Inc.
triclopsGetDefaultContextFromFile( &StereoContext[ 1 ] , “minibee_xxxxxxxx_BC.cal” );
//ADセットのカメラで取得した距離データをBCセットのカメラ座標系に合わせる
TriclopsTransform trans;
//AD->BCカメラ座標系への変換情報
triclopsGetTransformFromFile("minibee_xxxxxxxx_ADtoBC" , &trans );
//ADからBCへの変換行列をロードする
triclopsSetTriclopsToWorldTransform( StereoContext[ 0 ] , trans );
(2)
ViewPLUS Inc.
Step2
ステレオパラメータの設定
ステレオ処理のためのパラメータを設定します。このパラメータのとり方によってステレオデータの精度が
大きく異なります。また、CPU への負荷のかかり方にも直結しますのでパラメータ設定は大変大事な部分で
あることを認識するべきです。
以下、Triclops ライブラリの主なパラメータの設定方法を順に挙げてゆきます。パラメータ設定以降の全て
処理では常に Step1 で作成したコンテキストを利用します。
■ ステレオ処理方法(利用するカメラ台数)の選択
PGR 社製 Digiclops は右方向と上方向のカメラを含めた 3 眼にてステレオ処理を行うことができます。対し
て BumbleBee や弊社製 MiniBEE は横方向の 2 眼で行います。ここでは利用するステレオ処理のタイプに
あわせて処理方法を設定します。
Digiclops で は TriCfg_L 、 TriCfg_2CAM_HORIZONTAL 、 TriCfg_2CAM_VERTICAL が 、 MiniBEE で は
TriCfg_2CAM_HORIZONTAL のみが利用できます。
//MiniBEE では水平方向 2 眼方式を設定します
triclopsSetCameraConfiguration( StereoContext[ i ] , TriCfg_2CAM_HORIZONTAL );
■ ステレオ処理解像度の設定
演算処理を行う時の画像解像度を設定します。入力画像はこの解像度より大きくても構いません。ただし、
出力画像はここで設定した解像度と同じになります。解像度をあまり大きくすると CPU に負担をかけること
になります。また、計測対象によってはステレオ処理時の比較テクスチャをとりやすい解像度が存在します。
ここでは入力時の画像が 640x480 の大きさであると仮定し、処理画像の解像度を 320x240 と設定して先へ進
みます。
//MiniBEE では基本的に 320x240 でステレオ処理を行うのを推奨します
triclopsSetResolution( StereoContext[ i ] , 240 , 320 );
■ ディスパリティ計算範囲の設定
ステレオ処理とは、右カメラ画像に写ったターゲット(図中緑の三角形)が、左カメラ画像ではどの位置に
写っているかを計測する処理と言えます。
具体的には、右カメラ画像内にサーチウィドウを設定し、それと対応する左カメラ内の同じ座標位置にウィ
(3)
ViewPLUS Inc.
ンドウを生成します(ウィンドウ A)。右カメラと左カメラに写ったターゲットには視差の発生によって、ウ
ィンドウ A 内にはターゲットは存在しません。水平方向 2 眼カメラではターゲットはより右側に写っている
はずです。そのため、サーチウインドウをウィンドウ A の位置からウィンドウ B の位置まで少しづつずらし
ながらウィンドウ内の相関値を計算し、最も相関値の高い位置を求める作業となります。
図中ではウィンドウの右方向シフト量が dx の時にターゲットが見つかり、相関値が最も高くなりました。も
しもターゲットが近くにあるならば dx は大きい値となり、ターゲットが遠くにあればあるほど dx は小さく
なります。逆に言えば、より近くのターゲットを検出するためにはウィンドウ B の位置をより右までずらす
必要があるということです。しかし、検索範囲を広げると計算量が大きく増加してしまいます。
「ディスパリティ計算範囲」とは距離の計測範囲です。すなわち図中のターゲットサーチ範囲となるウィン
ドウの右シフト量の範囲、dMin と dMax です。dMin の位置から dMin+1,dMin+2…と相関値を計算してゆ
き、dMax までの相関値を計算するよう設定します。あらかじめ計測対象の距離が分かっている場合、ある
いは計測を望まない範囲の距離がある場合、範囲を適切に設定することで計算コストを減らし、余計な対象
を検知しないで済ませることができます。
例えば MiniBEE ではカメラから 50cm の距離にある物体の視差 dx は AD カメラセットで約 35 ピクセル、
BC カメラセットで約 11 ピクセルとなります。そのため、カメラより 50cm 以上∼無限遠まで離れた物体を
計測するには下記の例のようになります。
//MiniBEE で 50cm から無限遠までを計測する場合
triclopsSetDisparity( StereoContext[ 0 ] , 1 , 35 );
triclopsSetDisparity( StereoContext[ 1 ] , 1 , 11 );
■ ステレオマスクサイズの設定
相関サーチウィンドウの大きさ(Fig2 での size)がステレオマスクサイズです。このサイズを大きくすると
誤計測が減り計測値が安定しますが、ピクセル間の距離計測値が緩やかになります。1 から 15 までの間で設
定できますが、多くの場合は 13 あるいは 15 に設定しておくと安定した値を得ることが出来ます。
//ステレオ相関ウィンドウの大きさを 13x13 に設定
SetStereoMask( StereoContext[ i ] , 13 );
■ エッジ検出フィルタの設定
ステレオ相関演算の精度を上げるためにエッジフィルタを適用するかどうかを設定します。フィルタを On
にすると、カメラ画像から下のようなエッジ画像を生成しエッジ画像上でステレオ相関演算を行います。
(4)
ViewPLUS Inc.
エッジ抽出フィルタを使わずに画像輝度値で相関演算を行った場合、両カメラ間で対象の明るさが異なった
場合に正しく相関を計算することが出来ません。ほとんどの場合はエッジ抽出フィルタを利用する設定にし、
エッジ抽出マスクのサイズを 11-13 程度にすることで計測値が安定します。
//エッジ抽出フィルタを利用する場合は 1 を、しない場合は 0 を設定します
triclopsSetEdgeCorrelation( StereoContext[ i ] , 1 );
triclopsSetEdgeMask( StereoContext[ i ] , 13 );
この時、カメラ自体に設定されたゲインやシャッタースピードを調節してエッジ抽出画像がきれいに取得で
きるようにして下さい。3 次元計測の前に必ずゲインやホワイトバランスを調整するようにします。
■ サブピクセル演算
ステレオ相関演算をサブピクセルを用いて演算することで取得距離の精度を上げることができます。ただし、
サブピクセル演算を設定しない場合は演算結果となる距離値は 8bit となりますが、設定した場合は距離値が
16bit で出力されますのでご注意下さい。
また、サブピクセル演算時は triclopsSetStrictSubpixelValidation()を利用するとより精度の良い結果が得られので
これもあわせて設定することを推奨しています。
//サブピクセル演算を利用する場合は 1 を、しない場合は 0 を設定します
triclopsSetSubpixelInterpolation( StereoContext[ i ] , 1 );
triclopsSetStrictSubpixelValidation( StereoContext[ i ] , 1 );
(5)
ViewPLUS Inc.
Step3
計測ノイズ低減フィルタの設定
ステレオ相関値より算出された距離値には大抵の場合ノイズが含まれてしまいます。下図左側の入力画像に
対して距離の計測値となる出力距離画像を右側に示します。右側の距離画像では各点のカメラに対する距離
が白から黒までの画像の濃淡地で表されます。
(画像の点の色が白いほどカメラから近いとして表されていま
す)
下の画像は、ディスパリティ計測範囲の計測可能最大距離を短くしてわざとノイズが多く含まれるよう設定
した距離の計測結果です。ターゲット以遠の背景部分が認識できず、色が激しく変化していて強いノイズが
含まれていることが分かります。このノイズを低減する方法を解説します。
■ サーフェイス バリデイション フィルタの設定
ある点の距離値がその近傍の点の距離値と大きく異なるものを除去します。すなわち、計測された距離を一
連のサーフェイス(物体表面)として認識し、認識できなかった点を除去します。
設定にはサーフェイスサイズとサーフェイス限界差分値の二つを用いて行います。サイズは、サーフェイス
として認識する面積の最小値です。サイズを小さくすればするほど認識できる距離点が増え、より多くの距
離点を有効にすることができますがノイズが増えます。限界差分値は、同一サーフェイスとして認識する距
離値の範囲です。これを小さくするとサーフェイスの判定がより厳密に行われノイズを多く除去できる代わ
りに計測できた面積が少なくなってしまいます。
大体の場合は、サーフェイスサイズを 100 から 300 の間、サーフェイス限界差分値を 0.5 から 1.5 の間あた
りで設定すると有効です。下はサーフェイスサイズを 250、限界差分値を 1.0 に設定した例です。
//サーフェイス バリデイション フィルタを利用する場合は 1 を、しない場合は 0 を設定します
triclopsSetSurfaceValidation( StereoContext[ i ] , 1 );
triclopsSetSurfaceValidationSize( StereoContext[ i ] , 250 );
triclopsSetSurfaceValidationDifference( StereoContext[ i ] , 1.0 );
(6)
ViewPLUS Inc.
■ ユニークネス バリデイション フィルタの設定
ステレオウィンドウをシフトしながら相関値を演算している時に、ウィンドウ内の相関値の山が適切に出て
いないものを除去します。これは、例えばカメラに近すぎて右カメラ画像には写っているが左画像には写っ
ていない面があり、そのために発生してしまうような誤計測を防ぐことができます。
フィルタの設定可能パラメータは、除去する強さの閾値です。この値を小さくするとより多くの距離点を除
去できますが、検出面積は小さくなってしまいます。
//ユニークネス バリデイション フィルタを利用する場合は 1 を、しない場合は 0 を設定します
triclopsSetUniquenessValidation( StereoContext[ i ] , 1);
triclopsSetUniquenessValidationThreshold( StereoContext[ i ] , 1.0 );
■ ローパスフィルタの設定
ローパスフィルタを設定すると、レクティファイ処理の前にローパスフィルタをかけることができます。
これを行うとレクティファイ結果画像にアンチエイリアシングをかけたのと同様の効果を得ることが出来、
ステレオ処理の精度が高くなります。
//ローパスフィルタを利用する場合は 1 を、しない場合は 0 を設定します
triclopsSetLowpass( StereoContext[ i ] , 1 );
■ テクスチャ バリデイション フィルタの設定
ノイズ低減フィルタとしてはさらにテクスチャ バリデイション フィルタがあります。このフィルタは計測
された距離点の中から、テクスチャの薄い部分を除去して精度を高めます。
(7)
ViewPLUS Inc.
ステレオ演算前の入力画像について、輝度値が平坦でテクスチャのない部分は画像センサの微小ノイズの影
響が大きくなってしまい、相関値の計算結果が計測不能点とならずに誤った距離値を出してしまうことがあ
ります。テクスチャ バリデイション フィルタはこのような状況を除去することが出来るのです。
triclopsSetTextureValidation()を用いてこのフィルタを設定することができます。
(8)
ViewPLUS Inc.
Step4
距離計測(ステレオ演算)処理
■ レクティファイ前画像作成
まず、取得したカメラ画像からレクティファイ(歪曲収差補正)処理を行うための画像を作成します。カメ
ラから取得した画像は GRBG 形式のベイヤーパターン画像であるため、これをモノクロの 8bit 輝度画像へ
変換します。
下記は MiniBEE の例です。Raw8bitImage[ x ][ x ] にレクティファイ処理前画像を作成しています。
HVPCAM_T hCamera;
BYTE * BufferHeap;
BYTE * RawImage[ 2 ][ 2 ];
BYTE * Raw8bitImage[ 2 ][ 2 ];
//画像を MiniBEE より取得します。hCamera は既に初期化され、BufferHeap にも適切な量のメモリが確保されているとし
ます
vpcamGrabImage(hCamera , BufferHeap , NULL );
//取得した 4 枚の画像をデモザイク処理し、ベイヤー画像から RGB8bit カラー画像へ変換します
// ImageSize には API より取得した画像サイズ量が格納されていて、RawImage[ x ][ x ]には幅×高さ×3 バイトのメモ
リが確保されているとします。
vpcamBayerToColor( hCamera, RawImage[ 0 ][ 0 ] , BufferHeap );
vpcamBayerToColor( hCamera, RawImage[ 1 ][ 0 ] , BufferHeap + ImageSize );
vpcamBayerToColor( hCamera, RawImage[ 1 ][ 1 ] , BufferHeap + ImageSize * 2 );
vpcamBayerToColor( hCamera, RawImage[ 0 ][ 1 ] , BufferHeap + ImageSize * 3 );
//取得した 4 枚の画像について、それぞれをモノクロ 8bit の輝度画像へ変換します
//Raw8bitImage[ x ][ x ]には幅×高さバイトのメモリが確保されているとします
BYTE * src, * dest;
int i , j , p;
for( i = 0 ; i < CAMERA_SET_COUNT ; i ++ )
{
for( j = 0 ; j < CAMERA_COUNT ; j ++ )
{
src = RawImage[ i ][ j ];
dest = Raw8bitImage[ i ][ j ];
for( p = 0 ; p < CAMERA_WIDTH * CAMERA_HEIGHT ; p ++ )
{
src++;
*(dest++) = *(src++);
//緑成分のみを取得して輝度とする
src++;
}
(9)
ViewPLUS Inc.
}
}
作成された左カメラモノクロ画像 と 右カメラモノクロ画像
■ レクティファイ画像の作成とステレオ処理
輝度画像をレンズ補正データを用いてレクティファイします。ここでは 8bit のモノクロ画像を用いて行って
いますが、後述する方法を用いることで 8bitRGB のカラー画像を用いてレクティファイすることができます。
この場合はカラーのレンズ補正画像が得られますが、モノクロ画像の処理に比べて大きなコストがかかりま
すのでご注意下さい。ステレオ演算により作成された距離データ点に対しての色情報が欲しい場合のみカラ
ー画像のレクティファイを行うほうが処理速度が速くなります。
レクティファイは TriclopsInput 構造体に処理に必要な変数を格納して triclopsPreprocess()渡すことで指定さ
れ、triclopsStereo()を呼ぶことでステレオ演算処理時に実行されます。
下記は MiniBEE での例です。640x480 サイズの 8bit モノクロ画像で、右カメラの画像と左カメラの画像間
のステレオ演算を実行するよう指示しています。
TriclopsInput
input;
for( i = 0 ; i < 2 ; i ++ )
{
input.inputType = TriInp_RGB;
input.ncols = 640;
//入力画像の幅
input.nrows = 480;
//入力画像の高さ
input.rowinc = 640;
//入力画像 1 行あたりに確保されているメモリ量
input.u.rgb.red
= Raw8bitImage[ i ][ 0 ];
//右カメラ モノクロ画像を指定
input.u.rgb.green = Raw8bitImage[ i ][ 1 ]];
//左カメラ モノクロ画像を指定
input.u.rgb.blue = NULL;
//2 カメラ水平モードで演算する場合は NULL を指定
triclopsPreprocess( StereoContext[ i ] , &input );
triclopsStereo( StereoContext[ i ] );
//レクティファイ&ステレオ演算 実行
( 10 )
ViewPLUS Inc.
}
■ 距離画像の取得
triclopsStereo()が成功すると、レクティファイ後画像や距離画像が取得できます。triclopsGetImage()を実行する
と、指定した TriclopsImage 構造体に各種の値が設定されて返されます。また、ここで作成される画像の大
きさはコンテキストの初期化時に triclopsSetResolution()で設定された大きさとなります。
TriclopsImage image , edge;
TriclopsImage16 disparity;
//レクティファイ後画像を取得する場合
triclopsGetImage( StereoContext[ i ] , TriImg_RECTIFIED , TriCam_RIGHT , &image );
//エッジ抽出フィルタ適用後画像を取得する場合
triclopsGetImage( StereoContext[ i ] , TriImg_EDGE , TriCam_RIGHT , &edge );
//距離画像を取得する場合
triclopsGetImage( StereoContext[ i ] , TriImg_DISPARITY , TriCam_RIGHT , &disparity );
上記の例では disparity 構造体の nrows, ncols, rowinc メンバに画像サイズが格納され、data メンバに距離
画像のビットデータが格納されます。
作成された レクティファイ画像(左) と 距離画像(右)
( 11 )
ViewPLUS Inc.
Step5
距離計測点の絶対座標を求める
■ 距離画像より計測点の絶対座標を取得する
前段で作成された距離画像より各点の距離値を取得し、これから絶対座標を求めます。
TriclopsImage16 disparity;
//片方のカメラセットの距離画像を取得する
triclopsGetImage( StereoContext[ i ] , TriImg_DISPARITY , TriCam_RIGHT , &disparity );
//距離計測点から絶対座標を取得する
int x , y;
float px , py , pz;
WORD * depth;
for( y = 0; y < disparity.nrows ; y++ )
{
depth = disparity.data + y * disparity.rowinc / sizeof(WORD);
// rowinc はバイト単位なのでワード単位へ
for ( x = 0 ; x < disparity.ncols ; x++ , depth++ )
{
if ( (0xFF00 & *depth ) != 0xFF00 )
triclopsRCD16ToWorldXYZ( StereoContext[ i ] , y , x , * depth, &px , &py , &pz );
//px , py , pz に距離値 *depth から単位[m]の座標値へ変換される
}
}
上記 px , py , pz に取得される距離値
の座標系は左の通りとなります。
(単位
はメートルとなります)
座標系の原点は原則として右側カメラ
のレンズ中心上となります。そのため、
カメラ画像の中心点では px=0,py=0 と
なり、pz にカメラからの距離が格納さ
れることになります。
■ カラー3 次元モデルを作成する
前段までのステップでモノクロ距離画像上の点の絶対位置を求めることが出来ました。しかし、作成された
距離画像は収差補正処理がかかっているため、カメラ画像上の点とは対応しません。(triclopsGetImage()関
( 12 )
ViewPLUS Inc.
数を用いてレクティファイ後のモノクロ画像を取得すれば、この画像から対応する点のモノクロの色情報を
取得することは出来ます。)
計測された点のカメラ画像カラー値を取得するには、カメラからの入力カラー画像をレクティファイして距
離画像の点と対応できるようにします。
int x , y;
BYTE * src , *dest;
TriclopsInput color_input;
TriclopsColorImage color_image;
//デモザイキング後のカメラ入力カラー画像を RGB 形式から 32bit の B,G,R,U 形式に変換する
src = RawImage[ i ][ 0 ];
dest = CameraBGRUWork;
// CameraBGRUWork には幅×高さ×4 バイトのメモリを確保しておく
for( x = 0 ; x < 640 * 320 ; x ++ )
{
*(dest++) = *(src++);
*(dest++) = *(src++);
*(dest++) = *(src++);
*(dest++) = 0;
}
// TriclopsInput 構造体に値をセットする
color_input.inputType = TriInp_RGB_32BIT_PACKED;
color_input.ncols = 640;
color_input.nrows = 480;
color_input.rowinc = 640 * 4;
color_input.u.rgb32BitPacked.data = ( void * )CameraBGRUWork;
//カラー画像のレクティファイを実行する。出力画像の大きさは triclopsSetResolution()で設定された大きさである。
triclopsRectifyColorImage( StereoContext[ i ] , TriCam_REFERENCE , &color_input , &color_image );
上記実行後、color_image.blue、green、red に距離画像に対応する青、赤、黄色の色データビット列が格納
されます。対応するカラー値を抜き出して OpenGL を用いて 3 次元空間上にカラーの点を描画することで 3 次
元モデルを描画することが出来ます。
( 13 )
ViewPLUS Inc.
- Document Version 1.0.0 -
( 14 )
ViewPLUS Inc.