forked from spz1063769322/Weak-scratch-detection
-
Notifications
You must be signed in to change notification settings - Fork 0
/
RANSAC.py
112 lines (103 loc) · 4.74 KB
/
RANSAC.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
import numpy
import scipy as sp
import scipy.linalg as sl
def ransac(data, model, n, k, t, d, debug=False, return_all=False):
"""
参考:http://scipy.github.io/old-wiki/pages/Cookbook/RANSAC
伪代码:http://en.wikipedia.org/w/index.php?title=RANSAC&oldid=116358182
输入:
data - 样本点
model - 假设模型:事先自己确定
n - 生成模型所需的最少样本点
k - 最大迭代次数
t - 阈值:作为判断点满足模型的条件
d - 拟合较好时,需要的样本点最少的个数,当做阈值看待
输出:
bestfit - 最优拟合解(返回nil,如果未找到)
iterations = 0
bestfit = nil #后面更新
besterr = something really large #后期更新besterr = thiserr
while iterations < k
{
maybeinliers = 从样本中随机选取n个,不一定全是局内点,甚至全部为局外点
maybemodel = n个maybeinliers 拟合出来的可能符合要求的模型
alsoinliers = emptyset #满足误差要求的样本点,开始置空
for (每一个不是maybeinliers的样本点)
{
if 满足maybemodel即error < t
将点加入alsoinliers
}
if (alsoinliers样本点数目 > d)
{
%有了较好的模型,测试模型符合度
bettermodel = 利用所有的maybeinliers 和 alsoinliers 重新生成更好的模型
thiserr = 所有的maybeinliers 和 alsoinliers 样本点的误差度量
if thiserr < besterr
{
bestfit = bettermodel
besterr = thiserr
}
}
iterations++
}
return bestfit
"""
iterations = 0
bestfit = None
besterr = numpy.inf # 设置默认值
best_inlier_idxs = None
while iterations < k:
maybe_idxs, test_idxs = random_partition(n, data.shape[0])
maybe_inliers = data[maybe_idxs, :] # 获取size(maybe_idxs)行数据(Xi,Yi)
test_points = data[test_idxs] # 若干行(Xi,Yi)数据点
maybemodel = model.fit(maybe_inliers) # 拟合模型
test_err = model.get_error(test_points, maybemodel) # 计算误差:平方和最小
also_idxs = test_idxs[test_err < t]
also_inliers = data[also_idxs, :]
if debug:
print('test_err.min()', test_err.min())
print('test_err.max()', test_err.max())
print('numpy.mean(test_err)', numpy.mean(test_err))
print('iteration %d:len(alsoinliers) = %d' % (iterations, len(also_inliers)))
if len(also_inliers > d):
betterdata = numpy.concatenate((maybe_inliers, also_inliers)) # 样本连接
bettermodel = model.fit(betterdata)
better_errs = model.get_error(betterdata, bettermodel)
thiserr = numpy.mean(better_errs) # 平均误差作为新的误差
if thiserr < besterr:
bestfit = bettermodel
besterr = thiserr
best_inlier_idxs = numpy.concatenate((maybe_idxs, also_idxs)) # 更新局内点,将新点加入
iterations += 1
print(bestfit)
print(best_inlier_idxs)
if bestfit is None:
raise ValueError("did't meet fit acceptance criteria")
if return_all:
return bestfit, {'inliers': best_inlier_idxs}
else:
return bestfit
def random_partition(n, n_data):
"""return n random rows of data and the other len(data) - n rows"""
all_idxs = numpy.arange(n_data) # 获取n_data下标索引
numpy.random.shuffle(all_idxs) # 打乱下标索引
idxs1 = all_idxs[:n]
idxs2 = all_idxs[n:]
return idxs1, idxs2
class LinearLeastSquareModel:
# 最小二乘求线性解,用于RANSAC的输入模型
def __init__(self, input_columns, output_columns, debug=False):
self.input_columns = input_columns
self.output_columns = output_columns
self.debug = debug
def fit(self, data):
A = numpy.vstack([data[:, i] for i in self.input_columns]).T # 第一列Xi-->行Xi
B = numpy.vstack([data[:, i] for i in self.output_columns]).T # 第二列Yi-->行Yi
x, resids, rank, s = sl.lstsq(A, B) # residues:残差和
return x # 返回最小平方和向量
def get_error(self, data, model):
A = numpy.vstack([data[:, i] for i in self.input_columns]).T # 第一列Xi-->行Xi
B = numpy.vstack([data[:, i] for i in self.output_columns]).T # 第二列Yi-->行Yi
B_fit = sp.dot(A, model) # 计算的y值,B_fit = model.k*A + model.b
err_per_point = numpy.sum((B - B_fit) ** 2, axis=1) # sum squared error per row
return err_per_point