プロクラステス分析
点群のレジストレーションや姿勢推定の論文で出てくるプロクラステス分析を知らなかったので調べて実装しました.
プロクラステス分析とは
プロクラステス分析(procrustes analysis,プロクラステス解析とも)は点同士の対応がとれた2つの点群に対して,並進・回転・一様なスケーリングの変換のもとで,点群間の二乗誤差が最小になるように重ねあわせする処理です.この記事では特に,回転行列が直交行列であるようなケースの直交プロクラステス分析(Orthogonal Procrustes analysis)について扱います.
方法
1. 2つの点群の重心を原点に位置合わせする
点群の重心が原点になるよう,からそれぞれの平均を引きます. \begin{equation} {\bf X}_{o} = {\bf X} - \overline{\bf X} \qquad {\bf Y}_{o} = {\bf Y} - \overline{\bf Y} \end{equation} 2. 2つの点群のスケールを正規化する
\begin{equation} {\bf X}_{norm} = \dfrac{{\bf X_o}}{||{\bf X}_o||_F} \qquad {\bf Y}_{norm} = \dfrac{{\bf Y_o}}{||{\bf Y}_o||_F} \end{equation} 3. 回転に二乗誤差が最小になるように回転する
重心を原点に位置合わせし,スケールを正規化した2つの点群を改めてとします.すると,を回転して誤差が最小になるようにに重ねあわせる時の回転行列は以下の式で求めることができます.
\begin{equation}
{\bf R} = argmin_{\bf \Omega}{|| {\bf \Omega A} - {\bf B} ||}_F \quad s.t. \quad {\bf \Omega}^{T} {\bf \Omega} = I
\end{equation}
この式は
\begin{equation}
||{\bf \Omega A} - {\bf B}||^2_F = ||{\bf A}||^2_F + ||{\bf B}||^2_F - 2 \langle {\bf \Omega A}, {\bf B}\rangle
\end{equation}
と変形でき、これを最小化するには右辺第三項を最大化します.次にこの項を以下のように変形します.
\begin{align*}
\langle{\bf \Omega A}, {\bf B}\rangle
&= tr({\bf A^T \Omega^T B}) = tr({\bf B^T \Omega A}) = tr({\bf \Omega A B^T}) \newline
&= tr({\bf \Omega USV^T})= tr({\bf SV^T\Omega U})
\end{align*}
となります.
(ただしと特異値分解した.)
と置くと,この右辺は直交行列の積であることからは直交行列になり,式は以下のように変形できます.
\begin{equation}
tr({\bf SV^T\Omega U}) = tr({\bf SX}) = \sum_i s_{ii}x_{ii}
\end{equation}
は特異値であるため非負になるので,この式を最大化する直交行列は明らかにの時です.
よってであるため の時,当初の式が最小化されるのでこれが求めたい回転行列になります.
実装
実装は↓にあるけど,ためしに自分でも実装してみました. stackoverflow.com
自分の実装
import numpy as np def procrustes(x, y): """ Orthogonal procrustes analysis Inputs: ------------ X, Y matrices of target and input coordinates. Outputs ------------ Z the matrix of transformed X-values """ mux = np.mean(x, axis=0) muy = np.mean(y, axis=0) X = x - mux Y = y - muy X_norm = np.linalg.norm(X) # frobenius norm Y_norm = np.linalg.norm(Y) # frobenius norm normalized_X = X / X_norm normalized_Y = Y / Y_norm u, w, vt = np.linalg.svd(np.dot(normalized_X, normalized_Y.T)) R = np.dot(vt.T, u.T) scale = w.sum() * X_norm / Y_norm Z = Y_norm * w.sum() * np.dot(R, normalized_X) + muy return Z
二次元の点群に対して回転・並進・スケーリングした上で各点にガウスノイズを加えてできた点群と,もとの点群でプロクラステス分析した結果が次の図です.
補足
プロクラステス分析は2点群間の対応が取れているのに対して,ICP(Iterative Closest Point)は一般に揃えたい点群間の対応が取れていない場合や点数が異なるケースを扱っている(大規模な点群の一部分に位置合わせしたい,など)という違いがあるようです.
参考資料
[1] Ross, A. "Procrustes analysis." Course report, Department of Computer Science and Engineering, University of South Carolina (2004).
[2] Akça, M. Mehmet, D. "Generalized procrustes analysis and its applications in photogrammetry." (2003).