1. 程式人生 > >Ransac演算法--直線擬合

Ransac演算法--直線擬合

Ransac演算法


1、演算法簡介

隨機抽樣一致演算法(RANdom SAmple Consensus,RANSAC)。它是一種迭代的方法,用來在一組包含離群的被觀測資料中估算出數學模型的引數。 RANSAC是一個非確定性演算法,在某種意義上說,它會產生一個在一定概率下合理的結果,其允許使用更多次的迭代來使其概率增加。此RANSAC演算法在1981年由Fischler和Bolles首次提出。

RANSAC的基本假設是 “內群”資料可以通過幾組模型引數來敘述其資料分佈,而“離群”資料則是不適合模型化的資料。 資料會受噪聲影響,噪聲指的是離群,例如從極端的噪聲或錯誤解釋有關資料的測量或不正確的假設。 RANSAC假定,給定一組(通常很小)的內群,存在一個程式,這個程式可以估算最佳解釋或最適用於這一資料模型的引數。

2、範例

這裡用一個簡單的例子來說明,在一組資料點中找到一條最適合的線。 假設,此有一組集合包含了內群以及離群,其中內群為可以被擬合到線段上的點,而離群則是無法被擬合的點。如果我們用簡單的最小平方法來找此線,我們將無法得到一條適合於內群的線,因為最小平方法會受離群影響而影響其結果。而RANSAC,可以只由內群來計算出模型,而且概率還夠高。 然而,RANSAC無法保證結果一定最好,所以必須小心選擇引數,使其能有足夠的概率。

3、概述

  1. 在資料中隨機選擇幾個點設定為內群
  2. 計算適合內群的模型
  3. 把其它剛才沒選到的點帶入剛才建立的模型中,計算是否為內群
  4. 記下內群數量
  5. 重複以上步驟多做幾次
  6. 比較哪次計算中內群數量最多,內群最多的那次所建的模型就是我們所要求的解
  7. 這裡有幾個問題
  8. 一開始的時候我們要隨機選擇多少點(n)
  9. 以及要重複做多少次(k)

4、引數確定

假設每個點時真正內群的概率為 w

w = 內群的數目/(內群數目+外群數目)

通常我們不知道 w 是多少, w^n是所選擇的n個點都是內群的機率, 1-w^n 是所選擇的n個點至少有一個不是內群的機率, (1 − w^n)^k 是表示重複 k 次都沒有全部的n個點都是內群的機率, 這邊定演算法跑 k 次以後成功的機率是p,那麼,

1 − p = (1 − w^n)^k
p = 1 − (1 − w^n)^k

所以如果希望成功機率高,p = 0.99, 當n不變時,k越大,p越大, 當w不變時,n越大,所需的k就越大, 通常w未知,所以n 選小一點比較好。

5、應用

RANSAC常被用在電腦視覺 ,例如,對應點問題 和 估算立體攝影機雙眼相對點的基本矩陣。

6、C實現原始碼

float Ransac
(
  Point2D32f* points, 
  size_t Cnt, 
  float *line,
  int numForEstimate,
  float successProbability,
  float maxOutliersPercentage
){

  //1 − p = (1 − w^n)^k
  //p = 
  //float outlierPercentage = maxOutliersPercentage;//估計值
  float numerator = log(1.0f-successProbability);
  float denominator = log(1.0f- pow(1.0-maxOutliersPercentage, numForEstimate));
  //隨機抽取一定比例的點
  int ransac_times = (int)(numerator/denominator + 0.5);
  
  printf("ransac_times: %d\n", ransac_times);
  int numDataObjects = Cnt;
  //int numForEstimate = Cnt*0.1;
  int maxVoteCnt = 0;
  float tempLine[4];
  float inliersPercentage = 0.0;
  
  
  int *Chosen = new int[numDataObjects];

  Point2D32f *subPoints = new Point2D32f[numForEstimate];
  int pointCnt = 0;
  int voteCnt = 0;
  for(int i = 0; i < ransac_times; i++)
  {
    //隨機抽取 
    //randomly select data for exact model fit ('numForEstimate' objects).
        memset(Chosen,0,numDataObjects*sizeof(int));
        int maxIndex = numDataObjects-1;
    for(int j = 0; j < numForEstimate; j++)
    {
      int selectedIndex = rand() % numDataObjects;
      Chosen[selectedIndex] = 1;
    }
    //擬合
    pointCnt = 0;
    for(int k = 0; k < numDataObjects; k++)
    {
      if(Chosen[k])
      {
        subPoints[pointCnt].x = points[k].x;
        subPoints[pointCnt].y = points[k].y;
        pointCnt++;
      }
    }
    FitLine2D(subPoints, pointCnt, tempLine);
    float a = tempLine[1]/tempLine[0];
    float b = tempLine[3] - a*tempLine[2];
    
    
    //擬合完整之後要對擬合的結果進行鑑定,選出最優的結果
    voteCnt = 0;
    for(int k = 0; k < Cnt; k++)
    {
      //如果在直線上或者附近
      if(abs(points[k].y - a*points[k].x - b) < 2)
      {
        voteCnt++;
      }
    }

    if(voteCnt > maxVoteCnt)
    {
      maxVoteCnt = voteCnt;
      inliersPercentage = (float)maxVoteCnt/Cnt;
//			printf("a: %f\tb%f\tpercent: %f\n", a, b, inliersPercentage);
      for(int m = 0; m < 4; m++)
      {
        line[m] = tempLine[m];
      }
      
    }	
    //當inliers的比例比較高的時候就可以直接取該值作為最優解
//		if(inliersPercentage > 0.2)
//		{
//			return inliersPercentage;
//		}
  }
  return inliersPercentage;
}


7、優缺點

RANSAC的優點是它能魯棒的估計模型引數。例如,它能從包含大量局外點的資料集中估計出高精度的引數。RANSAC的缺點是它計算引數的迭代次數沒有上限;如果設定迭代次數的上限,得到的結果可能不是最優的結果,甚至可能得到錯誤的結果。RANSAC只有一定的概率得到可信的模型,概率與迭代次數成正比。RANSAC的另一個缺點是它要求設定跟問題相關的閥值。

RANSAC只能從特定的資料集中估計出一個模型,如果存在兩個(或多個)模型,RANSAC不能找到別的模型。