解bundle adjustment,由於完全是自己實現這份**還是存在很大的缺陷,殘差只能降低20倍(但是,它至少能下降,能收斂...)。目前看來,僅僅能作為對整個ba過程理解的**,實際應用概率不大。
本來想實現dso中的滑窗優化,可是寫到後來發現這個東西還是需要前端來支援的,最起碼得形成乙個由視窗、相機引數、路標引數組成的流式資料結構才能進行完整地滑窗優化。所以目前退而求其次,解個ba就算了。由於完全是自己實現這份**還是存在很大的缺陷,殘差只能降低20倍(但是,它至少能下降,能收斂...)。接下來直接開始正文吧。
關於ba的過程這裡不展開,只說這份**幹了什麼。在關於ba中梯度求法的總結中,附帶總結了ba的過程。
ba初始情況如上圖左所示,這是在關於ba中梯度求法的總結中的\(j\)進行\(h=j^tj\)的結果。根據\(j\)的格式,可以推導出,\(h\)共有四個部分,三種型別的矩陣塊組成。
\[h=\left[ \begin
\_ & \_ \\
\_ & \_
\end \right]
\]其中\(i \in 1...m\)為相機的下標,\(k \in 1...n\)為路標點的下標。\(b\)為相機的部分,\(c\)為點的部分,\(e\)為聯合的部分。顯然左上角\(b\)共有\(m\times m\)個塊,右上角\(e\)共有\(m\times n\)個塊,右下角\(c\)共有\(n\times n\)個塊。其中\(b,c\)都為對角塊矩陣。
上一小節已經將hession的各個部分的大致分布說明。接下來要進行各個部分的推導,這需要進行殘差的各個偏導的說明。
由於優化變數是相機位姿\(\xi\)和路標點\(p\)。所以\(j^tj\delta x = -j^tr\)這個公式解的\(\delta x\)是乙個\((md_ + nd_) \times 1\)的向量。從上到下分別是各個相機的更新量和各個路標點的更新量,很容易驗證這和hession的維度的意義是統一的。
求hession實際上就是求j,j是乙個\(ld_ \times (md_ + nd_)\)的矩陣,其中\(l\)為殘差個數。在實現中顯然不能把j直接在**中寫出來,ba的殘差數量是非常大的,點的數量也很多,很明顯會爆記憶體。那麼在**中實際上就是將每個殘差的資訊分布到各個點、相機中的資料結構中去。下面給出殘差對於各個相機、路標點的梯度的定義。
\[_ = \frac^k},
_ = \frac^k}
\]這兩個偏導的實際表示式在關於ba中梯度求法的總結中已經提到。\(r_^k\)表示第\(i\)個相機看到了第\(k\)個路標點,如果沒有看到,這一項為0。對應的導數項也為0。當然\(r_^k\)只存在一項,即第\(i\)個相機不能兩次看到第\(k\)個路標點,這樣就無法確認該計算哪個,這在bal的資料集中也是可以驗證的。
\[\_ = \sum_^_^t_
\]\[\_ = _^t_
\]\[\_ = \sum_^_^t_
\]\(j^tj\delta x = -j^tr\)等式右邊顯然也和\(\delta x\)維度相同且同樣分為兩部分,上面是殘差對於相機的倒數轉置乘以殘差,下面是路標點的倒數轉置乘以殘差。在bal問題中殘差是2維的,相機是9維的,點是3維的。
\[j^tr =\left[ \begin
j_^tr \\
j_^tr
\end \right]
= \left[ \begin
\^ _^tr_^k\}_i \\
\^ _^tr_^k\}_k
\end \right]
\]至此,具體的各矩陣塊就清楚了。
不加證明的引入舒爾補的操作過程:
\[\begin
[b-ec^e^t] \delta x_ = -j_^tr + ec^j_^tr\\
\delta x_ = c^(-j_^tr - e^t\delta x_)
\end
\]關鍵問題是如何去完成這個舒爾補的操作,總不能把\(e,j_^tr,j_^tr,ec^j_^tr\)拼出來再去算這個公式吧。\(e,j_,j_\)可都是很大的矩陣,稍微上點規模的ba肯定是沒辦法這麼算的。但是雖然這些元素都比較大,他們組成的東西在第乙個第乙個求相機更新量時的矩陣是比較小的。總的來說,對於第乙個公式拼出下面這些量就解決了第乙個公式的問題(第乙個公式沒有稀疏性,只能硬算,拼出來等式兩邊解方程組即可)
\[\begin
ec^e^t\\ j_^tr\\ ec^j_^tr
\end
\]而這三個矩陣本身並不大,可以採用提前講殘差項、點、相機的資訊分布開來,之後統一集中起來的策略。
對於第二個公式,其實相對來說更好解決一點,首先等式左邊的\(c^\)是乙個對角塊矩陣,這個可以最後再考慮。\(-j_r - e^t\delta x_\)分別是兩個向量,都可見下面分析。總的來說第二個公式要求這些量
\[\begin
j_^tr \\ e^t\delta x_
\end
\]仔細觀察\(b\)的結構可以知道最終的\(ec^e^t\)本身並不大只與相機位姿個數有關,而且\(e,c\)本身都是矩陣塊,有\(m\times m\)個小塊組成,記每個小塊為\(e^t\}}_\),那麼可以通過基本的矩陣乘法得到
\[e^t\}}_ = \sum_^e_c_^e_^t
\]\(j_^tr\)是乙個比較短的向量,\(r\)是乙個\(d_ \times 1\)的向量,\(j_\)是\(d_ \times (md_+nd_)\)的矩陣。乙個殘差項其實對於相機的梯度在整個大雅克比矩陣來講就是在這個相機上位置上疊加乙個雅克比。所以可以在計算殘差時,分別求出殘差對相機的梯度,然後把這個梯度直接加到相機上去。額好像在上面說了具體表示式了,檢視殘差中的各偏導-等式的右邊
這一節。
\[\^tr\}_i = \sum_^_^tr_^k
\]\[\j_^tr\}_i = \sum_^e_c_^\^tr\}_k
\]\[\^tr\}_k=\sum_^_^tr_^k
\]\[\\}_ = \sum_^e_^t }_i
\]\[\_k = c_^(-\^tr\}_k - \\}_)
\]至此,公式最細節的部分已經描述完畢,接下來再說說**中是如何安排這些中間變數的。
//對每個點,統計資訊到b
//這個函式進行舒爾布的計算,主要是將點的資訊更新到相機的hession塊上
for (int k = 0; k < camsize; ++k) }}
for (int k = 0; k < camsize; ++k)
mat optright = eigen::matrix::ones();
for (int i = 0; i < camsize; ++i)
void getdelta(const mat &camdelta)
}delta = c.inverse()*(-jp_r-eikcamdelta);
}
關於python中b a與b a 的區別
b a與b a 的區別 b a將兩者指向同乙個物件 而b a 會建立乙個新的與a完全相同的物件,但是與a並不指向同一物件。在計算機中,不同的物件即不同的記憶體位址。可理解為 b a將建立a與b兩個快捷方式並指向同一檔案 而b a 先將a指向的檔案複製乙份作為副本,然後建立乙個指向該副本的快捷方式b。...
BA的廣度和深度
ba,或者稱業務分析師,是企業數字能力和業務能力之間的溝通橋梁。隨著企業數字轉型的進一步深化,相信對ba這樣的技能需求會越來越多,只是未必都用 ba 業務分析師 這樣的title。在thoughtworks做ba是怎樣一種體驗 中提到,ba的職責是把業務和使用者需求轉換為軟體需求。即使是這樣乙個單一...
敏捷開發模式下的BA崗
傳統的瀑布開發模式下需求分析崗是必不可少的。那麼敏捷專案沒有需求分析嗎?在很多人的印象中,敏捷軟體開發是種類似黑客行為的過程,是程式設計師最愛的勾當。不寫文件,不作需求分析,沒有專案經理,做什麼東西完全是程式設計師自己的行為。他們認為這樣的過程無法滿足真正大型專案和複雜專案的需要,因此在經過考慮後,...