1. 程式人生 > >SLAM從入門到放棄:SLAM十四講第八章習題(1-3)

SLAM從入門到放棄:SLAM十四講第八章習題(1-3)

以下均為簡單筆記,如有錯誤,請多多指教。

  1. 除了LK光流之外,還有哪些光流方法?它們各有什麼特點? 答:此答案轉載於:https://blog.csdn.net/iloveayu/article/details/76728412。 Barron等人對多種光流計算技術進行了總結,按照理論基礎與數學方法的區別把它們分成四種:基於梯度的方法、基於匹配的方法、基於能量的方法、基於相位的方法。當然除了這些方法之外,現在也有非常多基於深度學習的方法,例如flownet1、基於梯度的方法 基於梯度的方法又稱為微分法,它是利用時變影象灰度(或其濾波形式)的時空微分(即時空梯度函式)來計算畫素的速度向量。由於計算簡單和較好的結果,該方法得到了廣泛應用和研究。典型的代表是Horn-Schunck的光流計算方法,該方法在光流基本約束方程的基礎上附加了全域性平滑假設,從而計算出光流場。基於此思想,大量的改進演算法不斷提出。Nagel採用有條件的平滑約束,即通過加權矩陣的控制對梯度進行不同平滑處理;Black和Anandan針對多運動的估計問題,提出了分段平滑的方法。雖然很多基於梯度的光流估計方法取得了較好的光流估計,但由於在計算光流時涉及到可調引數的人工選取、可靠性評價因子的選擇困難,以及預處理對光流計算結果的影響,在應用光流對目標進行實時檢測與自動跟蹤時仍存在很多問題。 2、基於匹配的方法
    基於匹配的光流計算方法包括基於特徵和區域的兩種。基於特徵的方法不斷地對目標主要特徵進行定位和跟蹤,對目標大的運動和亮度變化具有魯棒性(robustness)。存在的問題是光流通常很稀疏,而且特徵提取和精確匹配也十分困難。基於區域的方法先對類似的區域進行定位,然後通過相似區域的位移計算光流。這種方法在視訊編碼中得到了廣泛的應用。然而,它計算的光流仍不稠密。另外,這兩種方法估計亞畫素精度的光流也有困難,計算量很大。在考慮光流精度和稠密性時,基於匹配的方法適用。 3、基於能量的方法 基於能量的方法首先要對輸入影象序列進行時空濾波處理,這是一種時間和空間整合。對於均勻的流場,要獲得正確的速度估計,這種時空整合是非常必要的。然而,這樣做會降低光流估計的空間和時間解析度。尤其是當時空整合區域包含幾個運動成分(如運動邊緣)時,估計精度將會惡化。此外,基於能量的光流技術還存在高計算負荷的問題。此方法涉及大量的濾波器,目前這些濾波器是主要的計算消費。然而,可以預期,隨著相應硬體的發展,在不久的將來,濾波將不再是一個嚴重的限制因素,所有這些技術都可以在幀速下加以實現。 4、基於相位的方法
    Fleet和Jepson首次從概念上提出了相位資訊用於光流計算的問題。因為速度是根據帶通濾波器輸出的相位特性確定的,所以稱為相位方法。他們根據與帶通速度調諧濾波器輸出中的等相位輪廓相垂直的瞬時運動來定義分速度。帶通濾波器按照尺度、速度和定向來分離輸入訊號。 基於相位的光流技術的綜合性能是比較好的:速度估計比較精確且具有較高的空間解析度,對影象序列的適用範圍也比較寬。同時,這裡仍有幾個問題值得討論: (1)與基於能量的光流技術一樣,基於相位的模型既有一定的生物合理性,又有較高的計算複雜性; (2)儘管相位技術用兩幀影象就可計算光流,但要獲得足夠的估計精度,就必須有一定的整合時間,這個延遲將會降低邊緣處運動估計的時間解析度; (3)Fleet和Jespon的方法對輸入影象序列中的時間混疊比較敏感。
  1. 在本節程式的求影象梯度過程中,我們簡單地求了u+1u+1u1u-1的灰度之差除以22,作為uu方向上的梯度值。這種做法有什麼缺點?提示:對於距離較近的特徵,變化應該較快;而距離較遠的特徵在影象中變化較慢,求梯度時能否利用此資訊? 答:個人看法,可能不是很完整。缺點主要有兩個。第一個就如提示所示,距離較近的特徵運動較快,不是十分符合光流中運動較小的假設,可能會使得光流跟蹤失敗;第二個問題就是,在影象的採集過程中必然存在噪聲等等影響,簡單的相減必然有大量的噪聲,也會對光流產生干擾。

  2. 在稀疏直接法中,假設單個畫素周圍小塊的光度也不變,是否可以提高演算法健壯性?請程式設計實現。 答:參照https://www.cnblogs.com/newneul/p/8571653.html的思路,如果假設周圍小塊的光度也不變,可以利用一個畫素塊的灰度值來代替當前一個畫素的灰度值。整體而言程式碼的改變不大,主要是在ComputeError()中殘差項的計算換成一個基於畫素塊的殘差計算。

float sumValue = 0.0;
for(int i = x-PATCH_RADIUS ; i<= x+PATCH_RADIUS ; ++i)
{  
  for (int j = y-PATCH_RADIUS; j <= y+PATCH_RADIUS ; ++j)
  {
     sumValue += getPixelValue(i,j);
  }
}
sumValue /=( (2*PATCH_RADIUS +1)*(2*PATCH_RADIUS+1) );  //求得元素周圍小塊的平均灰度值
_error (0,0) = sumValue - _measurement;

不過感覺純粹的求取平均值並不是特別合理,個人感覺比較合理方法是進行高斯加權,一般情況下這樣會更加魯邦。

float sigma;
float sumValue = 0.0;
float sumGauss = 0.0;
for(int i = x-PATCH_RADIUS ; i<= x+PATCH_RADIUS ; ++i)
{  
  for (int j = y-PATCH_RADIUS; j <= y+PATCH_RADIUS ; ++j)
  {
     float gaussValue = exp(-(i*i+j*j)/(2*sigma*sigma))/(2*3.1415926*sigma*sigma);
     sumValue += getPixelValue(i,j)*gaussValue ;
     sumGauss += gaussValue;
  }
}
sumValue /= sumGauss;
_error (0,0) = sumValue - _measurement;