[英]How to find fundamental matrix based on other fundamental matrix and camera movement?
我正在嘗試加速一些依賴於計算每個相機對之間的基本矩陣的多相機系統。
請注意以下是偽代碼。 @
表示矩陣乘法, |
是串聯的意思。
我有代碼來計算F
為每對calculate_f(camera_matrix1_3x4, camera_matrix1_3x4)
,天真的解決方案是
for c1 in cameras:
for c2 in cameras:
if c1 != c2:
f = calculate_f(c1.proj_matrix, c2.proj_matrix)
這很慢,我想加快速度。 我有大約 5000 台相機。
I have pre calculated all rotations and translations (in world coordinates) between every pair of cameras, and internal parameters k
, such that for each camera c
, it holds that c.matrix = c.k @ (c.rot | c.t)
我可以使用參數r, t
來幫助加快F
的以下計算嗎?
以數學形式,對於 3 個不同的相機c1
, c2
, c3
我有
f12=(c1.proj_matrix, c2.proj_matrix)
,我想要f23=(c2.proj_matrix, c3.proj_matrix)
, f13=(c1.proj_matrix, c3.proj_matrix)
和一些 function f23 f23, f13 = fast_f(f12, c1.r, c1.t, c2.r, c2.t, c3.r, c3.t)
?
一個工作 function 用於計算 numpy 中的基本矩陣:
def fundamental_3x3_from_projections(p_left_3x4: np.array, p_right__3x4: np.array) -> np.array:
# The following is based on OpenCv-contrib's c++ implementation.
# see https://github.com/opencv/opencv_contrib/blob/master/modules/sfm/src/fundamental.cpp#L109
# see https://sourishghosh.com/2016/fundamental-matrix-from-camera-matrices/
# see https://answers.opencv.org/question/131017/how-do-i-compute-the-fundamental-matrix-from-2-projection-matrices/
f_3x3 = np.zeros((3, 3))
p1, p2 = p_left_3x4, p_right__3x4
x = np.empty((3, 2, 4), dtype=np.float)
x[0, :, :] = np.vstack([p1[1, :], p1[2, :]])
x[1, :, :] = np.vstack([p1[2, :], p1[0, :]])
x[2, :, :] = np.vstack([p1[0, :], p1[1, :]])
y = np.empty((3, 2, 4), dtype=np.float)
y[0, :, :] = np.vstack([p2[1, :], p2[2, :]])
y[1, :, :] = np.vstack([p2[2, :], p2[0, :]])
y[2, :, :] = np.vstack([p2[0, :], p2[1, :]])
for i in range(3):
for j in range(3):
xy = np.vstack([x[j, :], y[i, :]])
f_3x3[i, j] = np.linalg.det(xy)
return f_3x3
Numpy 顯然沒有針對小型矩陣進行優化。 CPython 輸入對象的解析、內部檢查和 function 調用引入了顯着的開銷,遠遠大於執行實際計算所需的執行時間。 更不用說創建許多臨時 arrays也很昂貴。 解決此問題的一種解決方案是使用 Numba 或 Cython 。
此外,行列式的計算可以優化很多,因為您知道矩陣的確切大小,並且矩陣的一部分並不總是改變。 實際上,由於 通用子表達式消除(不是由 CPython 解釋器執行)和np.linalg.det
中復雜循環/條件的刪除,使用4x4 行列式的基本代數表達式有助於編譯器優化整體計算.
這是生成的代碼:
import numba as nb
@nb.njit('float64(float64[:,::1])')
def det_4x4(mat):
a, b, c, d = mat[0,0], mat[0,1], mat[0,2], mat[0,3]
e, f, g, h = mat[1,0], mat[1,1], mat[1,2], mat[1,3]
i, j, k, l = mat[2,0], mat[2,1], mat[2,2], mat[2,3]
m, n, o, p = mat[3,0], mat[3,1], mat[3,2], mat[3,3]
return a * (f * (k*p - l*o) + g * (l*n - j*p) + h * (j*o - k*n)) + \
b * (e * (l*o - k*p) + g * (i*p - l*m) + h * (k*m - i*o)) + \
c * (e * (j*p - l*n) + f * (l*m - i*p) + h * (i*n - j*m)) + \
d * (e * (k*n - j*o) + f * (i*o - k*m) + g * (j*m - i*n))
@nb.njit('float64[:,::1](float64[:,::1], float64[:,::1])')
def fundamental_3x3_from_projections(p_left_3x4, p_right_3x4):
f_3x3 = np.empty((3, 3))
p1, p2 = p_left_3x4, p_right_3x4
x = np.empty((3, 2, 4), dtype=np.float64)
x[0, 0, :] = p1[1, :]
x[0, 1, :] = p1[2, :]
x[1, 0, :] = p1[2, :]
x[1, 1, :] = p1[0, :]
x[2, 0, :] = p1[0, :]
x[2, 1, :] = p1[1, :]
y = np.empty((3, 2, 4), dtype=np.float64)
y[0, 0, :] = p2[1, :]
y[0, 1, :] = p2[2, :]
y[1, 0, :] = p2[2, :]
y[1, 1, :] = p2[0, :]
y[2, 0, :] = p2[0, :]
y[2, 1, :] = p2[1, :]
xy = np.empty((4, 4), dtype=np.float64)
for i in range(3):
xy[2:4, :] = y[i, :, :]
for j in range(3):
xy[0:2, :] = x[j, :, :]
f_3x3[i, j] = det_4x4(xy)
return f_3x3
這在我的機器上快了 130 倍(85.6 us VS 0.66 us)。
如果應用的 function 是可交換的(即f(c1, c2) == f(c2, c1)
),您可以將過程加快兩倍。 如果是這樣,您可以只計算上半部分。 事實證明,您的 function 具有一些有趣的屬性,因為f(c1, c2) == f(c2, c1).T
似乎總是正確的。 另一種可能的優化是並行運行循環。
通過所有這些優化,生成的程序應該快大約 3 個數量級。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.