采用RANSAC做直线拟合最大的优点是具有一定的抗噪声性能,但是其终止条件的选择对拟合效果很关键
RANSAC的线性拟合算法步骤大致如下:
while 最大尝试次数
从观测点集中随机取两点,计算出直线的参数k, t(或者k用向量表示),得出一个候选的直线模型。
计算候选直线与整个点集的匹配程度,可以采用统计在直线上(或到直线的距离小于一个阈值)的点的个数。
保留匹配程度最好的直线的参数。
如果本次尝试匹配点的个数 占整个点集大部分,超出预期(阈值),提前结束尝试。
endwhile
clc;clear;
%真实数据
mu = [0,0];%均值
S = [1 2.5;2.5 8];%协方差
data1 = mvnrnd(mu,S,200); %产生200个高斯分布数据
%噪声数据
mu = [2 2];
S = [8 0;0 8];
data2 = mvnrnd(mu,S,100);%产生100个噪声数据
data = [data1;data2];
plot(data(:,1),data(:,2),'ro');
K = 100; %设置最大迭代次数
sigma = 1; %设置拟合直线与数据的距离的偏差
pretotal = 0; %符合拟合模型数据的个数
k = 1;
while pretotal < size(data,1) * 2 / 3 && k < K %2/3的数据符合拟合模型或者达到最大迭代次数才退出
SampleIndex = floor(1 + (size(data,1) - 1) * rand(2,1)); %产生两个随机索引,用于找样本,floor乡下取整
samp1 = data(SampleIndex(1),:); %对元素数据随机抽样两个样本
samp2 = data(SampleIndex(2),:);
line = lineParam([samp1;samp2]); %对两个数据拟合出直线
temp = [data ones(size(data,1),1)];
mask = abs(line * [data ones(size(data,1),1)]'); %求每格数据到拟合直线的距离 d = |ax0 + by0 + c| / sqrt(a * a + b * b);
total = sum(mask < sigma);%计算距离小于一定阈值的个数
if total > pretotal
pretotal = total;
bestline = line; %找到的最好的拟合直线
end
k = k + 1;
end
%显示符合最佳拟合的数据
mask = abs(bestline * [data ones(size(data,1),1)]') < sigma;
hold on;
%将局内点打印出来
for i = 1 : length(mask)
if mask(i)
plot(data(i,1),data(i,2),'+');
end
end
%----------------------------------------------
%这里是解以下三个方程组
%a * x1 + b * y1 + c = 0
%a * x2 + b * y2 + c = 0
%a^2 + b^2 = 1
%返回系数[a b c]
%----------------------------------------------
function line = lineParam(data)
x = data(1,:);
y = data(2,:);
k = (y(1) - y(2)) / (x(1) - x(2)) %直线斜率,需要另加判别条件,此时忽略
a = sqrt(1 - 1 / (1 + k^2));
b = sqrt(1 - a^2);
if k > 0
b = -b;
end
c = -a * x(1) - b * y(1);
line = [a b c];
end