随机一致性采样RANSAC是一种鲁棒的模型拟合算法,能够从有外点的数据中拟合准确的模型。
它的原理很朴素就是从样本数据中找到具有一致性的数据,用这些数据去建立样本的数学模型。这个一致性怎么理解?我的理解是:如果按照聚类处理方式,一致性数据就是可以归为一类的数据,他们最相近。俗话说:物以类聚,人以群分。非我族类,其心必异。
算法的详细原理及说明在维基上很详细,不赘述。维基上给的是一个直线随机一致性检测,而且还提供了Matlab演示代码,这个代码有几步关键的地方,由于是采用Matlab矩阵快速操作风格写的有点晦涩,当时我看这个代码后还做了些注解,后来维基采用了我的那部分注解。
维基随机一致性算法网址:https://en.wikipedia.org/wiki/Random_sample_consensus
下面是我根据算法原理利用Matlab进行直线的随机一致性检测,为了直观没用采用Matlab矩阵化的一些操作,速度上肯定是不太快的呀:
%%2016/11/12 by DQ
clc;
clear ;
close all;
%数据的初始化
m=100;
data=zeros(2,m);
data(1,:)=1:m;
data(2,:)=100+20*rand(1,m);
DataLen=length(data);
DistThresh=4;
InlierRatio=0.3;
MinInlierNum=round(InlierRatio*DataLen);
BestPointsNum=0;
MaxIteration=200;
Iter=0;
x=data(1,:);
y=data(2,:);
%原始散点图
OriginalScatterPlot=plot(x,y,'*');
grid on;
%Matlab 函数polyfit 最小二乘法拟合
p=polyfit(x,y,1);
x1=x;
y1=polyval(p,x);
hold on;
PolyFitPlot=plot(x1,y1,'b');
%RANSAC 执行过程,不断迭代
while Iter<MaxIteration
%随机选取两个点,因为两个不同点确定一条直线啊
PreSelectIndex=randperm(DataLen,2);
P1=data(:,PreSelectIndex(1));
P2=data(:,PreSelectIndex(2));
P1x=P1(1);P1y=P1(2);
P2x=P2(1);P2y=P2(2);
%直线方程:A.x+B.y+C=0
A=P2y-P1y;
B=-(P2x-P1x);
C=P2x*P1y-P1x*P2y;
PointToLineDist=zeros(DataLen,1);
for i=1:DataLen
%点到直线的距离:d=(A*X+B*Y+C)/sqrt(A^2+B^2)
CurrentPoint=data(:,i);
X=CurrentPoint(1);
Y=CurrentPoint(2);
PointToLineDist(i)=abs(A*X+B*Y+C)/sqrt(A^2+B^2);
end
InlierIndex=find(PointToLineDist<=DistThresh);
InlierNum=length(InlierIndex);
if (InlierNum>BestPointsNum)&&(InlierNum>=MinInlierNum)
BestPointsSet=zeros(2,DataLen);
BestPointsNum=InlierNum;
BestPointsSet(:,InlierIndex)=data(:,InlierIndex);
end
Iter=Iter+1;
end
BestPointsSet(:,BestPointsSet(1,:)==0)=[];
hold on;
RANSACScatterPlot=plot(BestPointsSet(1,:),BestPointsSet(2,:),'ro');
BestParameter = polyfit(BestPointsSet(1,:),BestPointsSet(2,:),1);
xMin=min(data(1,:));
xMax=max(data(1,:));
x=xMin:0.5:xMax;
%最佳直线方程
y=BestParameter(1)*x+BestParameter(2);
%画出直线方程
hold on;
RANSACLinePlot=plot(x,y,'r');
title('RANSAC Find Best Line Fit Inlier');
legend([OriginalScatterPlot,PolyFitPlot,RANSACScatterPlot,RANSACLinePlot],'OriginalScatter','PolyFit','RANSACScatter','RANSACLine');