使用RANSAC算法拟合直线(含python实现代码)


RANSAC算法介绍

  • 定义
    RANSAC (RAndom SAmple Consensus,随机采样一致) 算法是从一组含有“外点”(outliers)的数据中正确估计数学模型参数的迭代算法。“外点”一般指的的数据中的噪声,比如说匹配中的误匹配和估计曲线中的离群点。

    RANSAC 算最早是由Fischler和Bolles在SRI上提出用来解决LDP(Location Determination Proble)问题的。

  • 算法基本思想和流程

    RANSAC 是通过反复选择数据集去估计出模型,一直迭代到估计出认为比较好的模型。
    具体的实现步骤可以分为以下几步:

    1、选择出可以估计出模型的最小数据集;
    2、使用这个数据集来计算出数据模型;
    3、将所有数据带入这个模型,计算出“内点”的数目;
    4、比较当前模型和之前推出的最好的模型的“内点“的数量,记录最大“内点”数的模型参数和“内点”数;
    5、重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于一定数量”)。


python实现代码

  • 环境依赖

    • python3.x
    • numpy
  • 核心代码

    import numpy as np
    import random
    import math
    
    
    def fit_line_by_ransac(point_list, sigma, iters = 1000, P = 0.99):
        # 使用RANSAC算法拟合直线
        # 迭代最大次数 iters = 1000
        # 数据和模型之间可接受的差值 sigma
        # 希望的得到正确模型的概率P = 0.99
        
        # 最好模型的参数估计
        best_a = 0#直线斜率
        best_b = 0#直线截距
        n_total = 0#内点数目
        for i in range(iters):
            # 随机选两个点去求解模型
            sample_index = random.sample(range(len(point_list)), 2)
            x_1 = point_list[sample_index[0]][0]
            y_1 = point_list[sample_index[0]][1]
            x_2 = point_list[sample_index[1]][0]
            y_2 = point_list[sample_index[1]][1]
            if x_2 == x_1:
                continue
                
            # 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(len(point_list)):
                y_estimate = a * point_list[index][0] + b
                if abs(y_estimate - point_list[index][1]) < sigma:
                    total_inlier += 1
    
            # 判断当前的模型是否比之前估算的模型好
            if total_inlier > n_total:
                iters = math.log(1 - P) / math.log(1 - pow(total_inlier/len(point_list), 2))
                n_total = total_inlier
                best_a = a
                best_b = b
    
            # 判断是否当前模型已经符合超过一半的点
            if total_inlier > len(point_list)//2:
                break
    
        return best_a, best_b
    
    
    if __name__ == '__main__':
        #测试
        points = [(1,3), (5,11), (8,18), (9,22), (10, 19), (19,37)]
    
        a,b = fit_line_by_ransac(points, sigma=3)
        print('line: y=%s*x+%s' %(a, b))
    
  • 输出结果

    line: y=2.0*x+-1.0
    

猜你喜欢

转载自blog.csdn.net/zengNLP/article/details/104065343