OpenCVを使用してカメラの内因性および外因性パラメーターを計算しました。ここで、画面座標(u、v)から世界座標(x、y、z)を計算します。
どうすればいいですか?
注意:kinectを使用しているので、z座標はすでにわかっています。
どんな助けでも大歓迎です。ありがとう!
OpenCVを使用してカメラの内因性および外因性パラメーターを計算しました。ここで、画面座標(u、v)から世界座標(x、y、z)を計算します。
どうすればいいですか?
注意:kinectを使用しているので、z座標はすでにわかっています。
どんな助けでも大歓迎です。ありがとう!
最初にそれを計算する方法を理解するために、ピンホールカメラモデルと単純な透視投影についていくつかのことを読むと役に立ちます。簡単に確認するには、これを確認してください。もっと更新してみます。
それでは、カメラがどのように機能するかを説明する反対のことから始めましょう。ワールド座標系の3Dポイントを画像の2Dポイントに投影します。カメラモデルによると:
P_screen = I * P_world
または(同次座標を使用)
| x_screen | = I * | x_world |
| y_screen | | y_world |
| 1 | | z_world |
| 1 |
どこ
I = | f_x 0 c_x 0 |
| 0 f_y c_y 0 |
| 0 0 1 0 |
は3x4組み込み行列で、fは焦点、cは射影の中心です。
上記のシステムを解くと、次のようになります。
x_screen = (x_world/z_world)*f_x + c_x
y_screen = (y_world/z_world)*f_y + c_y
しかし、あなたは逆のことをしたいので、あなたの答えは次のとおりです。
x_world = (x_screen - c_x) * z_world / f_x
y_world = (y_screen - c_y) * z_world / f_y
z_worldは、Kinectが返す深さであり、組み込み関数のキャリブレーションからfとcがわかっているため、すべてのピクセルについて、上記を適用して実際の世界座標を取得します。
編集1(上記が世界座標に対応する理由と、キャリブレーション中に取得する外因性は何ですか):
まず、これをチェックしてください、それは様々な座標系を非常によく説明しています。
3D座標系は次のとおりです。オブジェクト--->ワールド--->カメラ。オブジェクトの座標系から世界へとあなたを連れて行く変換と、世界からカメラへとあなたを連れて行く別の変換があります(あなたが参照する外因性)。通常、次のように想定します。
1.Kinectでオブジェクトをキャプチャしている間
Kinectを使用してオブジェクトをキャプチャすると、センサーから返されるのはカメラからの距離です。これは、z座標がすでにカメラ座標にあることを意味します。上記の式を使用してxとyを変換することにより、カメラ座標でポイントを取得します。
これで、世界座標系があなたによって定義されます。一般的なアプローチの1つは、カメラがワールド座標系の(0,0,0)にあると想定することです。したがって、その場合、外因性行列は実際には単位行列に対応し、見つけたカメラ座標は世界座標に対応します。
補足: Kinectはカメラ座標でzを返すため、オブジェクト座標系からワールド座標系への変換も必要ありません。たとえば、顔をキャプチャする別のカメラがあり、各ポイントについて、鼻からの距離(オブジェクトの座標系の中心と見なした)を返したとします。その場合、返される値はオブジェクトの座標系にあるため、それらをカメラの座標系に移動するには、実際に回転と平行移動の行列が必要になります。
2.カメラのキャリブレーション中
さまざまなポーズのキャリブレーションボードを使用して、OpenCVを使用してカメラをキャリブレーションしていると思います。通常の方法は、ボードが実際に安定していて、カメラが反対ではなく動いていると想定することです(変換はどちらの場合も同じです)。これは、ワールド座標系がオブジェクト座標系に対応することを意味します。このようにして、すべてのフレームについて、チェッカーボードのコーナーを見つけて3D座標を割り当て、次のようにします。
std::vector<cv::Point3f> objectCorners;
for (int i=0; i<noOfCornersInHeight; i++)
{
for (int j=0; j<noOfCornersInWidth; j++)
{
objectCorners.push_back(cv::Point3f(float(i*squareSize),float(j*squareSize), 0.0f));
}
}
ここでnoOfCornersInWidth
、noOfCornersInHeight
およびsquareSize
キャリブレーションボードによって異なります。たとえば、noOfCornersInWidth = 4、noOfCornersInHeight = 3、squareSize = 100の場合、3Dポイントを取得します。
(0 ,0,0) (0 ,100,0) (0 ,200,0) (0 ,300,0)
(100,0,0) (100,100,0) (100,200,0) (100,300,0)
(200,0,0) (200,100,0) (200,200,0) (200,300,0)
したがって、ここでの座標は実際にはオブジェクト座標系にあります。(ボードの左上隅は(0,0,0)であり、残りの隅の座標はそれに応じていると任意に仮定しました)。したがって、ここでは、オブジェクト(ワールド)からカメラシステムに移動するための回転および変換行列が実際に必要です。これらは、OpenCVがフレームごとに返す外因性です。
Kinectの場合を要約すると、次のようになります。
編集2(使用する座標系について):
これは慣例であり、使用するドライバーと返されるデータの種類にも依存すると思います。たとえば、あれ、あれ、あれを確認してください。
補足:点群を視覚化して少し遊んだら、とても役に立ちます。ポイントを3Dオブジェクト形式(たとえば、plyまたはobj )で保存してから、 Meshlabなどのプログラム(非常に使いやすい)にインポートすることができます。
編集2(使用する座標系について):
これは慣例であり、使用するドライバーと返されるデータの種類にも依存すると思います。たとえば、あれ、あれ、あれを確認してください。
たとえば、microsoft sdkを使用する場合、Zはカメラまでの距離ではなく、カメラまでの「平面」距離です。これにより、適切な式が変更される可能性があります。