程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> Ransac算法

Ransac算法

編輯:C++入門知識

1、算法簡介

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

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

2、范例

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

3、概述

在數據中隨機選擇幾個點設定為內群
計算適合內群的模型
把其它剛才沒選到的點帶入剛才建立的模型中,計算是否為內群
記下內群數量
重復以上步驟多做幾次
比較哪次計算中內群數量最多,內群最多的那次所建的模型就是我們所要求的解
這裡有幾個問題
一開始的時候我們要隨機選擇多少點(n)
以及要重復做多少次(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)^kp = 1 − (1 − w^n)^k所以如果希望成功機率高,p = 0.99, 當n不變時,k越大,p越大, 當w不變時,n越大,所需的k就越大, 通常w未知,所以n 選小一點比較好。

5、應用

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

6、C實現源碼


[cpp] view plaincopyprint?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; 

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不能找到別的模型。


 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved