つくるって楽しい

主にpythonとか。画像処理とか。

2つの画像の対応点からから3次元上の点を求める

理論

ある3次元上の点\boldsymbol{X}=(X,Y,Z,1)をカメラ内部パラメータ行列Aとカメラ外部パラメータ行列[R|t]を用いて画像上に投影した点を\boldsymbol{x}=(x,y,1)とすると、以下の関係が成り立ちます[1]。
{
s\boldsymbol{x}= A[R|t] \boldsymbol{X}
\tag{1}
}
または、
{
\displaystyle
s
\begin{pmatrix}
x_{1} \\
y_{1} \\
1 \\
\end{pmatrix}

=

\begin{pmatrix}
f_{x} && 0 && c_{x}  \\
0 && f_{y} && c_{y}  \\
0 && 0 && 1  \\
\end{pmatrix}

\begin{pmatrix}
r_{11} && r_{12 }&& r_{13} && t_{1}\\
r_{21} && r_{22 }&& r_{23} && t_{2}\\
r_{31} && r_{32 }&& r_{33} && t_{3}\\
\end{pmatrix}

\begin{pmatrix}
X \\
Y \\
Z \\
1 \\
\end{pmatrix}
\tag{2}
}
sはスケール調整の定数です。カメラ内部行列のf_{x},f_{y}はそれぞれピクセル単位の焦点距離c_{x},c_{y}は画像中心を表します。カメラの固有パラメータという感じです。カメラ外部行列はカメラ姿勢を表し、3次元物体の座標をカメラ座標に変換する役割を持ちます。

同じカメラで別の視点から\boldsymbol{X}を投影した画像が2枚(画像1、画像2)あり、それぞれのカメラ内部・外部行列を合わせたものをM_{1}=A[R|t]_{1} , M_{2}=A[R|t] _{2} 、画像上の投影点をx_{1}, x_{2}とすると、それぞれに対して(1)を適応して、

{
s\boldsymbol{x}_{1}= M_{1} \boldsymbol{X}
\tag{3}
}

{
s\boldsymbol{x}_{2}= M_{2} \boldsymbol{X}
\tag{4}
}

と表せます。
これを変形すると、

{
\begin{pmatrix}
M_{1} && -\boldsymbol{x}_{1}&& 0\\
M_{1} && 0 && -\boldsymbol{x}_{2}\\
\end{pmatrix}

\begin{pmatrix}
\boldsymbol{X} \\
s_{1} \\
s_{2} \\
\end{pmatrix}

=
\boldsymbol{0} 
\tag{5}
}

と書けます。これを解くことで\boldsymbol{X}が求まります。特異値分解で解くことが出来ます。

試してみた

3次元上の物体をカメラ行列M_{1}, M_{2}を使ってそれぞれ画像1,画像2に変換し、その画像を3次元上に復元する例を作成しました。
カメラ行列のパラメータはそれぞれ変えることが出来ます。

f:id:mikekochang:20190305134838j:plain
Fig1. 1段目左:元の3次元上の物体、右:復元した3次元物体
(2段目:元の物体のカメラ座標上の点。ここでは説明していない)
3段目左:画像1、右:画像2

元の3次元物体と復元結果が一致しています。

コード

pyCodes/recon3d at master · misakikobayashi1984/pyCodes · GitHub

一部計算は[2]のサンプルを使用しています。