算法过程
- 随机挑选四组点对生成内点集,并计算初始变换矩阵 H
- 根据 H 对剩余点进行变换,计算预测点与真实点之间的均方差,存储所有误差
- 判断整体误差的最大值是否小于指定阈值,并且如果小于最小误差,则将此次误差的最大值作为最小误差,循环结束前返回到第一步。
- 返回最小误差对应的变换矩阵
迭代次数确定
Ransac 算法需要多次迭代来确定最优变换矩阵,假设
w
=
内
点
个
数
/
所
有
点
的
个
数
w = 内点个数 / 所有点的个数
w=内点个数/所有点的个数
采样的 n个点全为内点的概率
p
0
=
w
n
p_0=w^n
p0=wn,至少有一个为外点的概率
p
1
=
1
−
p
0
p1=1−p0
p1=1−p0
则重复 K 次实验,每次都至少有一个外点的概率
p
2
=
p
1
K
p2=p1^K
p2=p1K
则K次采样中至少一次采样是有效采样的概率
p
=
1
−
p
2
p=1−p2
p=1−p2,最终计算得:
K
=
l
o
g
(
1
−
p
)
l
o
g
(
1
−
p
0
)
K=\frac{log(1−p)}{log(1−p_0)}
K=log(1−p0)log(1−p)
ransac_iters = int(round(math.log(1 - valid_prob) / math.log(math.pow(1 - inner_prob, samples) + 1e-8)))
这里 inner_prob 为内点概率值,valid_prob 为采样有效的概率值
迭代估计最优单应矩阵
每次迭代进行以下操作
- 随机选取四个点对作为初始内点集合,并计算变换矩阵
consensus_set = []
points_list_temp = deepcopy(points_list).tolist()
for j in range(4):
temp = random.choice(points_list_temp)
consensus_set.append(temp)
points_list_temp.remove(temp)
sp = np.asarray([_[0] for _ in consensus_set], dtype=np.float32)
dp = np.asarray([_[1] for _ in consensus_set], dtype=np.float32)
# 从一致集合中计算变换矩阵
H = cv2.getPerspectiveTransform(sp, dp)
- 对剩下的点进行遍历,计算误差
for p1, p2 in points_list_temp:
x1, y1 = p1
x2, y2 = p2
src_p = np.array([x1, y1, 1], dtype=np.float32)
dst_p = np.array([x2, y2, 1], dtype=np.float32)
# 计算实际值与预测结果的均方差
out = dst_p - np.dot(H, src_p)
# 计算 sqrt(dx2+dy2)
dist_error = np.hypot(out[0], out[1])
dist_errors.append(dist_error)
if dist_error < threshold and dist_error < max_error:
consensus_set.append([p1, p2])
dist_errors.append(dist_error)
- 与最小的误差进行比较,获取最优集
if max(dist_errors) < max_error:
max_error = max(dist_errors)
max_inliers = consensus_set
model_h = H
return np.asarray(max_inliers, dtype=np.float32), model_h