いぬおさんのおもしろ数学実験室

おいしい紅茶でも飲みながら数学、物理、工学、プログラミング、そして読書を楽しみましょう

写真から立体を再現(10) カメラ行列をRQ分解する

 QR分解ではありません、RQ分解です。QR分解について書かれているサイトはたくさんありますがRQ分解については少ないようです。しかしこの分野(3Dビジョン)では必要です。
 カメラ行列(透視投影行列)Pというのがありました。過去記事にあります。
www.omoshiro-suugaku.com
Pは P=A[R T] のようにできあがっています。このブログではまだ解説していませんが、Aはカメラの内部パラメータ行列と呼ばれ、成分が焦点距離などカメラの内部パラメータからなる上3角行列です。R、Tは上の過去記事(『写真から立体を再現(4)』)にも書いた、座標軸の回転と平行移動に関わる行列(3次元の回転を表すので直交行列)、ベクトルです。P=A[R T] =[AR AT] で AT は列ベクトルなので、行列 P の左側3×3の部分をかけ算の形に分解すればA、Rを求められます行列を(上3角行列)×(直交行列)の形に分解するのです。手作業で(いや、計算はプログラムで……)これを実行することもできますが結構大変です。何かライブラリはないかな、と探したら scipy にありました! numpy にはないようです(見つからなかった。間違えていたらすみません)。A、Rはどちらも3次の正則な正方行列ですから、ARは正則のはずです。なので、今回の実験では2次、3次の正則行列をRQ分解してみます。

import sys
from scipy import linalg
import numpy as np

A = np.array([[1,2], [4,5]])

print('rank =  ', np.linalg.matrix_rank(A), '\n')
R, Q = linalg.rq(A)
print(R, '\n')
print(Q, '\n')
print(np.dot(R, Q))
print('\n')

A = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 0]])
print('rank =  ', np.linalg.matrix_rank(A), '\n')
R, Q = linalg.rq(A)
print(R, '\n')
print(Q, '\n')
print(np.dot(R, Q))
sys.exit()

実行結果は以下の通り。

rank = 2

[[-0.46852129 -2.18643267]
[ 0. -6.40312424]]

[[ 0.78086881 -0.62469505]
[-0.62469505 -0.78086881]]

[[1. 2.]
[4. 5.]]


rank = 3

[[ -0.42285689 3.02320627 -2.163658 ]
[ 0. 6.0066335 -6.39690191]
[ 0. 0. -10.63014581]]

[[ 0.75174558 -0.65777738 0.0469841 ]
[-0.03535914 0.03093925 0.99889564]
[-0.65850461 -0.75257669 0. ]]

[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 0.]]

ランクも確認。正則なのだから2次ならランク2で、3次ならランク3です。結果を見るとちゃんと(上3角行列)×(直交行列)と分解していることが分かります。分解後、積がもとに戻るかも確認しました。
 サイトが少ないということは、RQ分解を使う人は少ないということでしょうか……。OpenCVにも関数(RQDecomp3×3)がありましたが、これを Python から使えるのか分かりませんでした。