とか がいつもごっちゃになるのでメモ
Must Read
- OpenCV: Camera Calibration and 3D Reconstruction
- SSII2019TS: 実践カメラキャリブレーション ~カメラを用いた実世界計測の基礎と応用~ | PPT (slideshare.net)
このページにおける記法
ある点 X があり、
: 世界座標系における点 X の座標
: カメラ座標系における点 X の座標
のとき、 R と t が以下のような関係を持つとする。
cw は世界座標系をカメラ座標系に変換するためのパラメータであるということを意味する。
- なので世界座標系からカメラ座標系に変換するものである、と覚える
- 一般に座標系 A から B への変換行列を BA という添え字で表すことが多い () ので、これに沿っている
- 読み方は camera from world とか camera-world とか world to camera
具体例
- 一般に外部パラメータというと cw を指す
cv2.solvePnPが返してくるのは cw- ただし回転に関しては回転行列ではなく Rodrigues vector
- COLMAP で用いられているものも cw
- ただし回転に関しては wxyz の quaternion
- 一方、ORB-SLAM3(というより EuRoC データセットか?)の保存フォーマットは wc (
timestamp tx ty tz x y z wの順) - nbhr/pycalib で
plotCameraが受け取るのは wc- でも
plotCamerasの受け取るcamera_paramsは cw - なので、
plotCameras関数の中で これらを変換して からplotCameraに渡している
- でも
性質
R の相互変換
関係式を変形して
であることから
が成り立つ。
よって は 直行行列 である。
t の相互変換
上の変形より が成り立つ。
同様に も成り立つ。
それぞれのパラメータの意味
: 世界座標系におけるカメラの位置
- これは最初の関係式に を代入すると容易にわかる: この点 はカメラ座標系の原点、すなわちカメラのある場所だが、このとき である。
- 同じようにして、「世界座標系における何かの位置」は一般に wc ベクトルで表されている。
- よって,例えば下の 座標系に対する操作 で座標系を変換する時にこれを変換することも忘れないようにする
: 同様に、 カメラ座標系における世界座標原点の位置
- 言い換えると、カメラから見える世界座標系原点の位置
- よって世界全体を回転させたときにこのベクトルは変化しない
: これの縦ベクトル R[:, i] は、カメラ座標系の x,y,z 軸が世界座標系でどちらを向いているかを表す
- 証明:例えば、 はカメラ座標系の x 軸上にある点であるが、最初の式の定義によりこれに対応する は の一番左の縦ベクトルとなる(平行移動は回転に関係ないので は無視)。y, z も同様。
- これの横ベクトル
R[i]は、逆に、世界座標系の x,y,z 軸がカメラ座標系でどちらを向いているかを表す
についても、 より行列の縦と横を入れ替えて同じことが言える(横ベクトル R[i] がカメラ座標軸の世界座標系における向き、縦ベクトル R[:,i] が世界座標軸のカメラ座標系における向き)
便利な性質
に右から回転行列 をかけると、そのカメラを だけ回転させられる
- なお、計算上のハックとして、 に右から をかけるのは、 に左から をかけるのに等しい
に右から回転行列 をかけ、 に右から をかけるのは、世界全体を だけ回転させることに等しい
- ではない! 上に書いたように、 は世界全体を回転させたとき変化しないので操作を行う必要はない
つまり、世界座標系を回転させるには以下のような変換をする
R_cw, t_cw # 回転前のカメラパラメータ。これから `*_new` を求める
R_cw_new = R_cw @ R
t_wc = -R_cw.T @ t_cw # 最初の関係式より
t_wc_new = R.T @ t_wc # numpyの演算の都合上こう書いているが、t_wcはベクトルなのでこれは右からRをかけているのに等しい
t_cw_new = -R_cw_new @ t_wc_new # 最初の関係式より
# 色々変形したが、結局t_cw_newはt_cwに等しい(すなわち下が成立する)。
assert np.allclose(t_cw, t_cw_new)
# cwでtranslationを扱っている場合は,世界全体を回転させてもtを変更する必要はない。座標系に対する操作
座標系に対してある操作を行いたいときにどういう変形をすればいいかという観点でまとめ直すと以下のようになる:
世界座標系全体をスライドしたい・あるカメラ/物体をスライドしたい
スライドしたいベクトル の分だけ translation を動かす。
カメラの translation を cw で管理している場合は,以下の関係
に注目すると、 だけスライドすればいいとわかる。ただし,ここで用いる は動かしたいカメラのものを用いることに注意。
世界座標系全体を 倍に拡大したい
wc であれ cw であれ、 を 倍する。
世界座標系全体を回転したい
世界全体を回転し、そこに置かれているカメラや物体の座標を動かすが、それらの間の位置関係は変わらないようにしたい場合、以下のような変換を行う。
- に右から回転行列 をかける(すなわち, で管理しているなら左から回転行列 をかける)
- translation を で管理している場合は、これに右から をかける
- 「世界座標系における何かの座標」はすべて wc であるため,これらにも をかける
- で管理しているものには、何もしなくてよい
あるカメラを回転したい
- に左から回転行列 をかける
- translation を で管理している場合は、 を右からかける
- で管理している場合は、何もしなくて良い
関連資料
- 内部パラメータについて カメラ内部パラメータ
- 座標系の取り方について 三次元座標系の種類
- OpenCV でのキャリブレーションについて OpenCV calibrateCamera関数のプロになる - かみのメモ (hatenablog.com)
- 回転行列以外の回転表現について 回転ベクトル・回転行列・クォータニオン・オイラー角についてまとめてみた - かみのメモ (hatenablog.com)