RANSAC為RANdom SAmple Consensus的縮寫,它是根據一組包含異常數據的樣本數據集,計算出數據的數學模型參數,得到有效樣本數據的算法。它於1981年由 Fischler和Bolles最先提出[1]。
RANSAC算法的基本假設是樣本中包含正確數據(inliers,可以被模型描述的數據),也包含異常數據(Outliers,偏離正常范 圍很遠、無法適應數學模型的數據),即數據集中含有噪聲。這些異常數據可能是由於錯誤的測量、錯誤的假設、錯誤的計算等產生的。同時RANSAC也假設, 給定一組正確的數據,存在可以計算出符合這些數據的模型參數的方法。
RANSAC基本思想描述如下:
①考慮一個最小抽樣集的勢為n的模型(n為初始化模型參數所需的最小樣本數)和一個樣本集P,集合P的樣本數num(P)>n,從P中隨機 抽取包含n個樣本的P的子集S初始化模型M;
②余集SC=P\S中與模型M的誤差小於某一設定閾值t的樣本集以及S構成S*。S*認為是內點集,它們構成S的一致集(Consensus Set);
③若#(S*)≥N,認為得到正確的模型參數,並利用集S*(內點inliers)采用最小二乘等方法重新計算新的模型M*;重新隨機抽取新 的S,重復以上過程。
④在完成一定的抽樣次數后,若為找到一致集則算法失敗,否則選取抽樣后得到的最大一致集判斷內外點,算法結束。
由上可知存在兩個可能的算法優化策略。①如果在選取子集S時可以根據某些已知的樣本特性等采用特定的選取方案或有約束的隨機選取來代替原來的 完全隨機選取;②當通過一致集S*計算出模型M*后,可以將P中所有與模型M*的誤差小於t的樣本加入S*,然后重新計算M*。
RANSAC算法包括了3個輸入的參數:①判斷樣本是否滿足模型的誤差容忍度t。t可以看作為對內點噪聲均方差的假設,對於不同的輸入數據需 要采用人工干預的方式預設合適的門限,且該參數對RANSAC性能有很大的影響;②隨機抽取樣本集S的次數。該參數直接影響SC中樣本參與模型參數的檢驗 次數,從而影響算法的效率,因為大部分隨機抽樣都受到外點的影響;③表征得到正確模型時,一致集S*的大小N。為了確保得到表征數據集P的正確模型,一般 要求一致集足夠大;另外,足夠多的一致樣本使得重新估計的模型參數更精確。
RANSAC算法經常用於計算機視覺中。例如,在立體視覺領域中同時解決一對相機的匹配點問題及基本矩陣的計算。
其偽代碼如下
1 input:
2 data - a set of observations
3 model - a model that can be fitted to data
4 n - the minimum number of data required to fit the model
5 k - the number of iterations performed by the algorithm
6 t - a threshold value for determining when a datum fits a model
7 d - the number of close data values required to assert that a model fits well to data
8 output:
9 best_model - model parameters which best fit the data (or nil if no good model is found)
10 best_consensus_set - data point from which this model has been estimated
11 best_error - the error of this model relative to the data
12
13 iterations := 0
14 best_model := nil
15 best_consensus_set := nil
16 best_error := infinity
17 while iterations < k
18 maybe_inliers := n randomly selected values from data
19 maybe_model := model parameters fitted to maybe_inliers
20 consensus_set := maybe_inliers
21
22 for every point in data not in maybe_inliers
23 if point fits maybe_model with an error smaller than t
24 add point to consensus_set
25
26 if the number of elements in consensus_set is > d
27 (this implies that we may have found a good model,
28 now test how good it is)
29 this_model := model parameters fitted to all points in consensus_set
30 this_error := a measure of how well better_model fits these points
31 if this_error < best_error
32 (we have found a model which is better than any of the previous ones,
33 keep it until a better one is found)
34 best_model := this_model
35 best_consensus_set := consensus_set
36 best_error := this_error
37
38 increment iterations
39
40 return best_model, best_consensus_set, best_error
下面是C語言實現

1 void Ransac(IplImage *pload,IplImage *pnew,int *x_cord,int *y_cord,int length, double &c0,double &c1,double &c2,char *file_name_prefix2,int nums,int &min)
2 {
3 int *count = new int[RANSAC_TIMES]; //計數
4 memset(count,0x00,sizeof(int)*RANSAC_TIMES);
5 CvMat mat_x, mat_b, mat_c;
6 double p_mat_x[9], p_mat_b[3],p_mat_c[3];//要轉化成數組
7 min = length; //求最小值用
8 int flag_linear =0;
9 int position = 0; //記錄誤差最小的位置
10
11 uchar *loadimageData = (uchar*)pload->imageData;
12 int step = pload->widthStep;
13 double a =0,b=0,c =0;
14 for(int i =0; i<RANSAC_TIMES; i++)
15 {
16 int randnums[3];
17 int n = 0;
18
19 for (int t=0;t<3;t++)
20 {
21 n = rand() % length;
22 randnums[t] = n;
23 p_mat_x[t*3] = 1.0;
24 p_mat_x[t*3+1] = x_cord[n];
25 p_mat_x[t*3+2] = x_cord[n] * x_cord[n];
26
27 p_mat_b[t] = y_cord[n];
28 p_mat_c[t] = 0;
29 }
30 cvInitMatHeader(&mat_x,3,3,CV_64FC1,p_mat_x);
31 cvInitMatHeader(&mat_b,3,1,CV_64FC1,p_mat_b);
32 cvInitMatHeader(&mat_c,3,1,CV_64FC1,p_mat_c);
33
34 flag_linear = cvSolve(&mat_x, &mat_b, &mat_c,CV_LU);
35 if ( flag_linear == 0)
36 {
37 continue;
38 }
39 double *temp = mat_c.data.db; //結果保存下來。
40 c = temp[0]; //常數項 //保留第i次結果
41 b = temp[1]; //一次項
42 a = temp[2]; //平方項
43 if (c2 < 0)
44 {
45 c2 = -c2;
46 }
47 double y_value = 0;
48 double x_square = 0;
49 int y_floor = 0;
50
51 double dis_error = 0;
52
53 for (int j=0;j<length;j++)
54 {
55 dis_error = fabs(y_cord[j] - ( a*(x_cord[j]*x_cord[j]) + b*x_cord[j] + c ));
56 if ( dis_error > RANSAC_THRESHOLD)
57 {
58 count[i]++;
59 }
60 }
61
62 if (min > count[i])
63 {
64 min = count[i];
65 position = i;
66 c0 = c;
67 c1 = b;
68 c2 = a;
69 }
70
71 } //50次循環結束。
72
73 double x_square = 0;
74 double y_value = 0;
75 int y_floor = 0;
76 int pixelposition;
77 for (int x=0; x<pnew->width; x++) //自變量取值范圍
78 {
79 x_square = pow(double(x),2);
80 y_value = c2*x_square + c1*x + c0;
81 y_floor = cvFloor((y_value));
82
83 if ( y_floor >= 0 && y_floor < pnew->height )
84 {
85 ((uchar*)(pnew->imageData + pnew->widthStep*y_floor))[3*x]=255;
86 ((uchar*)(pnew->imageData + pnew->widthStep*y_floor))[3*x+1]=0;
87 ((uchar*)(pnew->imageData + pnew->widthStep*y_floor))[3*x+2]=0;
88 }
89 for (int y=0;y<pnew->height;y++)
90 {
91 pixelposition = y*step+x;
92 if ( 0 == loadimageData[pixelposition])
93 {
94 ((uchar*)(pnew->imageData + pnew->widthStep*y))[3*x]= 0;
95 ((uchar*)(pnew->imageData + pnew->widthStep*y))[3*x+1]=0;
96 ((uchar*)(pnew->imageData + pnew->widthStep*y))[3*x+2]=255;
97 }
98 }
99 }
100
101 delete []count;
102 cvSaveImage(file_name_prefix2,pnew);
103
104 }