RANSAC算法与原理(二)


之前介绍了RANSAC算法原理的基本原理和算法实现流程,那么我们在具体使用时,应当如何应用呢。由于RANSAC算法的通用性,其适用于各种模型拟合的场景下,如二维(三维)直线拟合、平面拟合、椭圆拟合等等。 skimage官方文档中给出了几个使用RANSAC进行模型拟合的例子。

使用RANSAC进行直线拟合

首先先看一个使用RANSAC进行直线拟合的简单例子。参考RANSAC算法详解(附Python拟合直线模型代码) - 知乎 (zhihu.com),并对迭代次数的更新部分进行修改。

import numpy as np
import matplotlib.pyplot as plt
import random
import math

# 数据量。
SIZE = 50
# 产生数据。np.linspace 返回一个一维数组,SIZE指定数组长度。
# 数组最小值是0,最大值是10。所有元素间隔相等。
X = np.linspace(0, 10, SIZE)
Y = 3 * X + 10

fig = plt.figure()
# 画图区域分成1行1列。选择第一块区域。
ax1 = fig.add_subplot(1,1, 1)
# 标题
ax1.set_title("RANSAC")


# 让散点图的数据更加随机并且添加一些噪声。
random_x = []
random_y = []
# 添加直线随机噪声
for i in range(SIZE):
    random_x.append(X[i] + random.uniform(-0.5, 0.5)) 
    random_y.append(Y[i] + random.uniform(-0.5, 0.5)) 
# 添加随机噪声
for i in range(SIZE):
    random_x.append(random.uniform(0,10))
    random_y.append(random.uniform(10,40))
RANDOM_X = np.array(random_x) # 散点图的横轴。
RANDOM_Y = np.array(random_y) # 散点图的纵轴。

# 画散点图。
ax1.scatter(RANDOM_X, RANDOM_Y)
# 横轴名称。
ax1.set_xlabel("x")
# 纵轴名称。
ax1.set_ylabel("y")

# 使用RANSAC算法估算模型
# 迭代最大次数,每次得到更好的估计会优化iters的数值
iters = 100000
# 数据和模型之间可接受的差值
sigma = 0.25
# 最好模型的参数估计和内点数目
best_a = 0
best_b = 0
pretotal = 0
# 希望的得到正确模型的概率
P = 0.99
i=0
while True:
    if i<iters:
        i+=1
        # 随机在数据中红选出两个点去求解模型
        sample_index = random.sample(range(SIZE * 2),2)
        x_1 = RANDOM_X[sample_index[0]]
        x_2 = RANDOM_X[sample_index[1]]
        y_1 = RANDOM_Y[sample_index[0]]
        y_2 = RANDOM_Y[sample_index[1]]

        # y = ax + b 求解出a,b
        a = (y_2 - y_1) / (x_2 - x_1)
        b = y_1 - a * x_1

        # 算出内点数目
        total_inlier = 0
        for index in range(SIZE * 2):
            y_estimate = a * RANDOM_X[index] + b
            if abs(y_estimate - RANDOM_Y[index]) < sigma:
                total_inlier = total_inlier + 1

        # 判断当前的模型是否比之前估算的模型好
        if total_inlier > pretotal:
            iters = math.log(1 - P) / math.log(1 - pow(total_inlier / (SIZE * 2), 2))
            pretotal = total_inlier
            best_a = a
            best_b = b

        # 判断是否当前模型已经符合超过一半的点
        if total_inlier > SIZE:
            break
	else:
        break
# 用我们得到的最佳估计画图
Y = best_a * RANDOM_X + best_b

# 直线图
ax1.plot(RANDOM_X, Y)
text = "best_a = " + str(best_a) + "\nbest_b = " + str(best_b)
plt.text(5,10, text,
         fontdict={'size': 8, 'color': 'r'})
plt.show()

上述示例是使用RANSAC进行直线拟合的一个简单实现,我们可以注意到下述这段代码:

 for index in range(SIZE * 2):
            y_estimate = a * RANDOM_X[index] + b
            if abs(y_estimate - RANDOM_Y[index]) < sigma:
                total_inlier = total_inlier + 1

在进行内点和外点的判断选择时,是采用循环的方式逐一判断的,实际上,我们可以利用线性代数的知识,利用numpy矩阵运算将代码简化。

上述的代码,在每次进行直线拟合的时候,使用的两个点来进行直线方程的求解。那么当我想使用大于等于2个的数据点进行直线拟合时,最常见的就是使用最小二乘法拟合直线。

在使用最小二乘法进行直线拟合时,需要注意传统的最小二乘法(least squares)和总体最小二乘法(total least squares)的区别,详细说明请参考wiki链接,分别为最小二乘法 - 维基百科,自由的百科全书 (wikipedia.org)和[Total least squares - Wikipedia](https://en.wikipedia.org/wiki/Total_least_squares#:~:text=In applied statistics%2C total least squares is a,dependent and independent variables are taken into account.)。

两种方法的示意图如下图所示:

1024px-Linear_least_squares_example2.svg

1024px-Total_least_squares.svg

知乎上也有作者对这两个问题进行了说明和推导,参见线性拟合1-最小二乘 - 知乎 (zhihu.com)

线性拟合2-正交回归 - 知乎 (zhihu.com)

下面我将对总体最小二乘法的推导进行详细说明。

总体最小二乘法直线推导

根据几何意义推导

下面的推导主要是根据线性拟合2-正交回归 - 知乎 (zhihu.com)进行整理得到。

首先需要说明的是,下述推导是二维直线点法式推导(三维直线没有点法式方程)。点法式的方程相比斜截式的方程,能更完整地的表示所有的直线情况。

横坐标和纵坐标的误差定义如下:
η i ^ = x i − x i ^ \hat{\eta _{i}} =x_{i}-\hat{x_{i}} ηi^=xixi^

ϵ i ^ = y i − y i ^ \hat{\epsilon _{i}} =y_{i}-\hat{y_{i}} ϵi^=yiyi^

综合考虑横纵坐标的误差,目标函数的形式如下:
J 2 = ∑ i n [ ( η i ^ ) 2 + ( ϵ i ^ ) 2 ] = ∑ i n [ ( x i − x i ^ ) 2 + ( y i − y i ^ ) 2 ] J_{2}=\sum_{i}^{n} [(\hat{\eta _{i}})^{2}+(\hat{\epsilon _{i}})^{2}]=\sum_{i}^{n} [(x_{i}-\hat{x_{i}})^{2}+(y_{i}-\hat{y_{i}})^{2}] J2=in[(ηi^)2+(ϵi^)2]=in[(xixi^)2+(yiyi^)2]
因为要求目标函数的最小值,所以就是求观测点 ( x i , y i ) (x_{i},y_{i}) (xi,yi)到估计点 ( x i ^ , y i ^ ) (\hat{x_{i}},\hat{y_{i}}) (xi^,yi^)的最小值,因为点 ( x i , y i ) (x_{i},y_{i}) (xi,yi)我们是已知的,也就是求点 ( x i , y i ) (x_{i},y_{i}) (xi,yi)到拟合直线的距离的和的最小值。估计点 ( x i ^ , y i ^ ) (\hat{x_{i}},\hat{y_{i}}) (xi^,yi^)是点 ( x i , y i ) (x_{i},y_{i}) (xi,yi)在拟合直线上的正交投影点。所以目标函数可以写成:
J 2 = ∑ i n d i 2 J_{2}=\sum_{i}^{n}d_{i}^{2} J2=indi2
d i d_{i} di为第 i i i个点 ( x i , y i ) (x_{i},y_{i}) (xi,yi)到拟合直线的距离。

用点法式拟合直线的表示形式为
a ( x − x 0 ) + b ( y − y 0 ) = 0 a(x-x_0)+b(y-y_0)=0 a(xx0)+b(yy0)=0
其中, ( x 0 , y 0 ) (x_0,y_0) (x0,y0)为经过直线的一个点, ( a , b ) (a,b) (a,b)表示直线的法向量。 ( a , b ) (a,b) (a,b)仅仅表示一个方向,为了计算方便,我们取单位向量,即满足下式:
a 2 + b 2 = 1 a^2+b^2=1 a2+b2=1
i i i个点到直线的距离,可以表示为向量 ( x i − x 0 , y i − y 0 ) (x_i-x_0,y_i-y_0) (xix0,yiy0)在法向量方向 ( a , b ) (a,b) (a,b)投影的长度,目标函数可以写成:
J 2 = ∑ i n d i 2 = ∑ i n ( ( x i − x 0 , y i − y 0 ) ⋅ ( a , b ) ) 2 a 2 + b 2 = ∑ i n [ a ( x i − x 0 ) + b ( y i − y 0 ) ] 2 J_2=\sum_{i}^{n}d_i^{2}=\sum_{i}^{n}\frac{((x_i-x_0,y_i-y_0)\cdot(a,b))^2}{a^2+b^2}=\sum_{i}^{n}[a(x_i-x_0)+b(y_i-y_0)]^2 J2=indi2=ina2+b2((xix0,yiy0)(a,b))2=in[a(xix0)+b(yiy0)]2
由极值点和可导函数之间的关系得,极值点可以推出一阶导数为0,那么一阶导数为0就是极值点的必要条件。那么可以推出:一阶导数不为0,不是极值点。

将目标函数 J 2 J_2 J2 x 0 x_0 x0 y 0 y_0 y0求偏导,并令其等于0,得:
∂ J 2 ∂ x 0 = − 2 a ∑ i n [ a ( x i − x 0 ) + b ( y i − y 0 ) ] = 0 \frac{\partial J_2}{\partial x_0}=-2a\sum_{i}^{n}[a(x_i-x_0)+b(y_i-y_0)]=0 x0J2=2ain[a(xix0)+b(yiy0)]=0

∂ J 2 ∂ y 0 = − 2 b ∑ i n [ a ( x i − x 0 ) + b ( y i − y 0 ) ] = 0 \frac{\partial J_2}{\partial y_0}=-2b\sum_{i}^{n}[a(x_i-x_0)+b(y_i-y_0)]=0 y0J2=2bin[a(xix0)+b(yiy0)]=0

上式等号两边同时除以n得
a ( x ˉ − x 0 ) + b ( y ˉ − y 0 ) = 0 a(\bar{x}-x_0)+b(\bar{y}-y_0)=0 a(xˉx0)+b(yˉy0)=0
可以看到点 ( x ˉ , y ˉ ) (\bar{x},\bar{y}) (xˉ,yˉ)满足直线方程,所以令 x 0 = x ˉ , y 0 = y ˉ x_0=\bar{x},y_0=\bar{y} x0=xˉ,y0=yˉ,此时目标函数变为:
J 2 = ∑ i n [ a ( x i − x ˉ ) + b ( y i − y ˉ ) ] 2 = [ a b ] [ ∑ i n ( x i − x ˉ ) 2 ∑ i n ( x i − x ˉ ) ( y i − y ˉ ) ∑ i n ( x i − x ˉ ) ( y i − y ˉ ) ∑ i n ( y i − y ˉ ) 2 ] [ a b ] J_2=\sum_{i}^{n}[a(x_i-\bar{x})+b(y_i-\bar{y})]^2=\\ \begin{bmatrix} a & b \end{bmatrix} \begin{bmatrix} \sum_{i}^{n}(x_i-\bar{x})^2 &\sum_{i}^{n}(x_i-\bar{x})(y_i-\bar{y}) \\ \sum_{i}^{n}(x_i-\bar{x})(y_i-\bar{y}) &\sum_{i}^{n}(y_i-\bar{y})2 \end{bmatrix} \begin{bmatrix} a\\ b \end{bmatrix} J2=in[a(xixˉ)+b(yiyˉ)]2=[ab][in(xixˉ)2in(xixˉ)(yiyˉ)in(xixˉ)(yiyˉ)in(yiyˉ)2][ab]
对目标函数 J 2 J_2 J2除以n可得:
J 2 n = [ a b ] [ S x x S x y S x y S y y ] [ a b ] = v T S v \frac{J_2}{n}= \begin{bmatrix} a & b \end{bmatrix} \begin{bmatrix} S_{xx} & S_{xy}\\ S_{xy} & S_{yy} \end{bmatrix} \begin{bmatrix} a\\ b \end{bmatrix}=v^TSv nJ2=[ab][SxxSxySxySyy][ab]=vTSv
其中 S x x S_{xx} Sxx S y y S_{yy} Syy x x x y y y的方差, S x y S_{xy} Sxy x x x y y y的协方差。

很明显,这是一个二次型求最小值的问题。相关定理证明也可参考线性代数及其应用 (豆瓣) (douban.com)

因为 S S S是实对称矩阵,所以可以将其进行正交对角化分解:
S = [ q 1 q 2 ] [ λ 1 0 0 λ 2 ] [ q 1 T q 2 T ] = Q Λ Q T S= \begin{bmatrix} q_1 & q_2 \end{bmatrix} \begin{bmatrix} \lambda_1 &0 \\ 0 &\lambda_2 \end{bmatrix} \begin{bmatrix} q_{1}^{T}\\ q_{2}^{T} \end{bmatrix}=Q\Lambda Q^T S=[q1q2][λ100λ2][q1Tq2T]=QΛQT

J 2 n = v T S v = ( v T Q ) Λ ( v T Q ) T \frac{J_2}{n}=v^TSv=(v^TQ)\Lambda(v^TQ)^T nJ2=vTSv=(vTQ)Λ(vTQ)T
u 1 = v T q 1 , u 2 = v T q 2 , u = [ u 1 u 2 ] u_1=v^Tq_1,u_2=v^Tq_2,u=\begin{bmatrix} u_1\\ u_2 \end{bmatrix} u1=vTq1,u2=vTq2,u=[u1u2]则:
J 2 n = u T Λ u = λ 1 u 1 2 + λ 2 u 2 2 \frac{J_2}{n}=u^T\Lambda u=\lambda_1u_1^2+\lambda_2u_2^2 nJ2=uTΛu=λ1u12+λ2u22
因为:
u T u = v T Q Q T v = v T v = 1 u^Tu=v^TQQ^Tv=v^Tv=1 uTu=vTQQTv=vTv=1
所以 u u u为单位矩阵,即 u 1 2 + u 2 2 = 1 u_1^2+u_2^2=1 u12+u22=1

不妨设 λ 1 ≤ λ 2 \lambda_1\le\lambda_2 λ1λ2,即当 u 1 = 1 , u 2 = 0 u_1=1,u_2=0 u1=1,u2=0时, J 2 J_2 J2取得最小值 λ 1 \lambda_1 λ1,即 v = q 1 v=q_1 v=q1

所以最终的直线拟合结果是法向量 v v v对应矩阵 S S S的最小特征值的特征向量。

结果整理:
x 0 = x ˉ , y 0 = y ˉ x_0=\bar{x},y_0=\bar{y} x0=xˉ,y0=yˉ
拟合直线法向量:
v = [ a b ] = q 1 v=\begin{bmatrix} a\\ b \end{bmatrix}=q_1 v=[ab]=q1
那么如何求矩阵 S S S的最小特征值对应的特征向量呢

下面介绍使用奇异值分解求解矩阵 S S S的最小特征值对应的特征向量,参考奇异值分解(SVD)原理与在降维中的应用 - 刘建平Pinard - 博客园 (cnblogs.com)

假设现在有 n n n个二维点 ( x 1 , y 1 ) , ( x 2 , y 2 ) . . . ( x n , y n ) (x_1,y_1),(x_2,y_2)...(x_n,y_n) (x1,y1),(x2,y2)...(xn,yn),那么我们可以直接得到
A = [ x 1 − x ˉ y 1 − y ˉ x 2 − x ˉ y 2 − y ˉ . . . . . . x n − x ˉ y n − y ˉ ] A=\begin{bmatrix} x_1-\bar{x}&y_1-\bar{y} \\ x_2-\bar{x}&y_2-\bar{y} \\ ...&... \\ x_n-\bar{x}&y_n-\bar{y} \end{bmatrix} A=x1xˉx2xˉ...xnxˉy1yˉy2yˉ...ynyˉ
那么我们可以观察得到,矩阵 A T A A^TA ATA就是矩阵 S S S,那么根据奇异值分解的定义
A = U Σ V T A=U\Sigma V^T A=UΣVT
上式中的 V V V就是矩阵 A T A A^TA ATA也就是 S S S的特征值对应的特征向量构成的正交矩阵,又因为在奇异值分解时,矩阵 V V V中的特征值已经根据大小从大到小重新排列了,所以我们需要的就是 V V V的最后一列 ,也就是 V T V^T VT的最后一行

在python中,我们可以很方便的使用numpy中的np.linalg.svd求得相应的特征矩阵和特征向量。

从解齐次方程的角度推导

参考SVD之最小二乘【推导与证明】 - Brad_Lucas - 博客园 (cnblogs.com)奇异值分解(SVD)方法求解最小二乘问题的原理 - 一抹烟霞 - 博客园 (cnblogs.com)

求解直线拟合的问题,可以转化为求解齐次方程 A x = 0 Ax=0 Ax=0的问题,其中
A = [ x 1 − x ˉ y 1 − y ˉ x 2 − x ˉ y 2 − y ˉ . . . . . . x n − x ˉ y n − y ˉ ] x = [ a b ] A=\begin{bmatrix} x_1-\bar{x}&y_1-\bar{y} \\ x_2-\bar{x}&y_2-\bar{y} \\ ...&... \\ x_n-\bar{x}&y_n-\bar{y} \end{bmatrix}\\x= \begin{bmatrix} a\\b \end{bmatrix} A=x1xˉx2xˉ...xnxˉy1yˉy2yˉ...ynyˉx=[ab]
可以想到,当直线拟合的越好时, ∣ ∣ A x ∣ ∣ ||Ax|| Ax越小

方法一

求min ∣ ∣ A x ∣ ∣ ||Ax|| Ax,根据正交矩阵的性质:
∣ ∣ A x ∣ ∣ = ∣ ∣ U Σ V T x ∣ ∣ = ∣ ∣ Σ V T x ∣ ∣ ||Ax||=||U\Sigma V^Tx||=||\Sigma V^Tx|| Ax=UΣVTx=ΣVTx
y = V T x y=V^Tx y=VTx,则:
∣ ∣ Σ V T x ∣ ∣ = ∣ ∣ Σ y ∣ ∣ ||\Sigma V^Tx||=||\Sigma y|| ΣVTx=Σy
进一步处理,求 m i n ( y T D T D y ) min(y^TD^TDy) min(yTDTDy)
y T Σ T Σ y = σ 1 2 y 1 2 + ⋯ + σ n 2 y n 2 σ 1 ≥ σ 2 ≥ … σ n ≥ 0 y^T\Sigma^T\Sigma y=\sigma_1^2y_1^2+\dots+\sigma_n^2y_n^2\\ \sigma_1\ge\sigma_2\ge\dots\sigma_n\ge0 yTΣTΣy=σ12y12++σn2yn2σ1σ2σn0
约束条件为 ∣ ∣ y ∣ ∣ = 1 ||y||=1 y=1,如上所示, y = [ 0 0 … 1 ] y=\begin{bmatrix} 0&0&\dots&1\end{bmatrix} y=[001]是最小解,即:
x = V y = [ V 1 V 2 … V n ] [ 0 0 0 … 1 ] = V n x=Vy=\begin{bmatrix}V_1&V_2&\dots&V_n\end{bmatrix}\begin{bmatrix}0\\0\\0\\ \dots\\1\end{bmatrix}=V_n x=Vy=[V1V2Vn]0001=Vn
即最优解是 V V V的最后一列

方法二

m i n ∣ ∣ A x ∣ ∣ = m i n ( x T A T A x ) min||Ax||=min(x^TA^TAx) minAx=min(xTATAx),其中 A = U Σ V T , U T U = I , V T V = I A=U\Sigma V^T,U^TU=I,V^TV=I A=UΣVT,UTU=I,VTV=I , , , Σ \Sigma Σ为对角阵。
A T A = V Σ T U T U Σ V T = V Σ T Σ V T = V [ σ m a x 2 ⋱ σ m i n 2 ] V T A^TA=V\Sigma^TU^TU\Sigma V^T=V\Sigma^T\Sigma V^T\\=V\begin{bmatrix}\sigma_{max}^2&&&\\ &\ddots&&\\&&&\sigma_{min}^2 \end{bmatrix}V^T\\ ATA=VΣTUTUΣVT=VΣTΣVT=Vσmax2σmin2VT
V = [ V 0 V 1 … V n ] V=\begin{bmatrix}V_0&V_1&\dots&V_n\end{bmatrix} V=[V0V1Vn],得:
A T A = σ m a x 2 V 0 V 0 T + ⋯ + σ m i n 2 V n V n T A^TA=\sigma_{max}^2V_0V_0^T+\dots+\sigma_{min}^2V_nV_n^T ATA=σmax2V0V0T++σmin2VnVnT
由正交矩阵的性质:
V T V = I V i T V j = 0. i ≠ j ∣ ∣ V i ∣ ∣ = 1 V^TV=I\\ V_i^TV_j=0.i\ne j\\ ||V_i||=1 VTV=IViTVj=0.i=jVi=1
x = ∑ 0 n k i V i x=\sum_0^nk_iV_i x=0nkiVi,其中 V i V_i Vi为基向量
x T A T A x = σ m a x 2 k 0 2 V 0 T V 0 V 0 T V 0 + ⋯ + σ m i n 2 k n 2 V n T V n V n T V n = k 0 2 σ m a x 2 + ⋯ + k n 2 σ m i n 2 x^TA^TAx=\sigma_{max}^2k_0^2V_0^TV_0V_0^TV_0+\dots+\sigma_{min}^2k_n^2V_n^TV_nV_n^TV_n\\=k_0^2\sigma_{max}^2+\dots+k_n^2\sigma_{min}^2 xTATAx=σmax2k02V0TV0V0TV0++σmin2kn2VnTVnVnTVn=k02σmax2++kn2σmin2
由于 ∣ ∣ x ∣ ∣ = 1 ||x||=1 x=1,则
∑ 0 n k i 2 = 1 \sum_0^nk_i^2=1 0nki2=1
上式取最小的情况为 k n = 1 , k i = 0 ( i ≠ n ) k_n=1,k_i=0(i\ne n) kn=1,ki=0(i=n)

此时 x = V n x=V_n x=Vn,为 σ m i n \sigma_{min} σmin对应的列向量。

总结

我们发现,如果把上述的推导过程变为三维,把二维直线的点法式方程变为空间平面的点法式方程,上述推导依旧是成立的,所以我们已经得到了拟合空间平面的理论基础了。

References

RANSAC算法详解(附Python拟合直线模型代码) - 知乎 (zhihu.com)

线性拟合1-最小二乘 - 知乎 (zhihu.com)

线性拟合2-正交回归 - 知乎 (zhihu.com)

线性代数及其应用 (豆瓣) (douban.com)

奇异值分解(SVD)原理与在降维中的应用 - 刘建平Pinard - 博客园 (cnblogs.com)

奇异值分解(SVD)方法求解最小二乘问题的原理 - 一抹烟霞 - 博客园 (cnblogs.com)

SVD之最小二乘【推导与证明】 - Brad_Lucas - 博客园 (cnblogs.com)

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值