python ransac_最小二乘拟合圆(附代码python,加入RANSAC)

#!/usr/bin/env python

# coding=utf-8

import random

import math

import matplotlib.pyplot as plt

from matplotlib.patches import Ellipse, Circle

import numpy as np

import scipy.linalg as sl

import scipy as sp

true_x = 5

true_y = 5

true_r = 10

points_num = 150

inline_points = 130

points_x = []

points_y = []

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 = 0bestfit = nil #后面更新besterr = something really large #后期更新besterr = thiserrwhile 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 = bettermodelbesterr = thiserr}}iterations++}return bestfit"""

iterations = 0

bestfit = None

besterr = np.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)', np.mean(test_err))

print ('iteration%d:len(alsoinliers) =%d' % (iterations, len(also_inliers)))

if len(also_inliers > d):

betterdata = np.concatenate((maybe_inliers, also_inliers)) # 样本连接

bettermodel = model.fit(betterdata)

better_errs = model.get_error(betterdata, bettermodel)

thiserr = np.mean(better_errs) # 平均误差作为新的误差

if thiserr < besterr:

bestfit = bettermodel

besterr = thiserr

best_inlier_idxs = np.concatenate((maybe_idxs, also_idxs)) # 更新局内点,将新点加入

iterations += 1

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 = np.arange(n_data) # 获取n_data下标索引

np.random.shuffle(all_idxs) # 打乱下标索引

idxs1 = all_idxs[:n]

idxs2 = all_idxs[n:]

return idxs1, idxs2

'''最小二乘拟合直线模型'''

class CircleLeastSquareModel:

# 最小二乘 fitting circle

def __init__(self):

pass

def fit(self, data):

A = []

B = []

for d in data:

A.append([-d[0], -d[1], -1])

B.append(d[0] ** 2 + d[1] ** 2)

A_matrix = np.array(A)

B_matrix = np.array(B)

C_matrix = A_matrix.T.dot(A_matrix)

result = np.linalg.inv(C_matrix).dot(A_matrix.T.dot(B_matrix))

model.a = result[0]

model.b = result[1]

model.c = result[2]

return model # 返回最小平方和向量

# get error 为每个数据点和拟合后的结果之间的误差的平方,换其他模型也可以用

def get_error(self, data, model):

err_per_point = []

for d in data:

B = d[0] ** 2 + d[1] ** 2

B_fit = model.a * d[0] + model.b * d[1] + model.c

err_per_point.append((B + B_fit) ** 2) # sum squared error per row

return np.array(err_per_point)

if __name__ == "__main__":

'''生成随机点, 作为数据源'''

for i in range(1, points_num):

# print(random.randint(-5, 15))

a = random.uniform(true_x - true_r, true_x + true_r)

x = round(a, 2)

up_down = random.randrange(-1, 2, 2)

y = true_y + up_down * math.sqrt(true_r ** 2 - (x - true_x) ** 2)

b1 = random.uniform(-0.05, 0.05)

b2 = random.uniform(-0.05, 0.05)

c1 = random.uniform(0.3, 0.8)

c2 = random.uniform(0.3, 0.8)

error_b1 = round(b1, 2)

error_b2 = round(b1, 2)

error_c1 = round(c1, 2)

error_c2 = round(c2, 2)

if i <= inline_points:

points_x.append(x + error_b1)

points_y.append(y + error_b2)

else:

up_down1 = random.randrange(-1, 2, 2)

points_x.append(x + error_c1)

points_y.append(y + error_c2)

plt.plot(points_x, points_y, "ro", label="data points")

plt.axis('equal')

circle1 = Circle(xy=(true_x, true_y), radius=true_r, alpha=0.5, fill=False, label="true circle")

plt.gcf().gca().add_artist(circle1)

model = CircleLeastSquareModel() # 类的实例化:用最小二乘生成已知模型

data = np.vstack([points_x, points_y]).T

result = model.fit(data)

x0 = result.a * -0.5

y0 = result.b * -0.5

r = 0.5 * math.sqrt(result.a ** 2 + result.b ** 2 - 4 * result.c)

circle2 = Circle(xy=(x0, y0), radius=r, alpha=0.5, fill=False, label="least square fit circle")

plt.gcf().gca().add_artist(circle2)

print("circle x is%f, y is%f, r is%f" % (x0, y0, r))

# run RANSAC 算法

ransac_fit, ransac_data = ransac(data, model, 20, 1000, 20, 50, debug=False, return_all=True)

x1 = ransac_fit.a * -0.5

y1 = ransac_fit.b * -0.5

r_1 = 0.5 * math.sqrt(ransac_fit.a ** 2 + ransac_fit.b ** 2 - 4 * ransac_fit.c)

circle3 = Circle(xy=(x1, y1), radius=r_1, alpha=0.5, fill=False, label="least square ransac fit circle")

plt.gcf().gca().add_artist(circle3)

points_x_array = np.array(points_x)

points_y_array = np.array(points_y)

plt.plot(points_x_array[ransac_data['inliers']], points_y_array[ransac_data['inliers']], 'bx',

label="RANSAC data")

print("ransac circle x is%f, y is%f, r is%f" % (x1, y1, r_1))

plt.grid()

plt.legend(loc='upper right')

plt.show()

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
RANSACRandom Sample Consensus)是一种用于拟合模型的统计算法,在拟合问题中也可以使用。下面是一个使用Python实现RANSAC拟合代码: ```python import numpy as np import math def fit_circle_ransac(points, iterations=100, threshold=0.1): best_circle = None best_inliers = [] for i in range(iterations): # 随机选择3个点作为候选心 sample_points = np.random.choice(points, 3, replace=False) # 计算的参数 x = [p[0] for p in sample_points] y = [p[1] for p in sample_points] center_x, center_y, radius = fit_circle(x, y) # 计算所有点到拟合的的距离 distances = [] for point in points: d = math.sqrt((point[0] - center_x) ** 2 + (point[1] - center_y) ** 2) - radius distances.append(abs(d)) # 将距离小于阈值的点标记为内点 inliers = [point for i, point in enumerate(points) if distances[i] < threshold] # 更新最好的 if len(inliers) > len(best_inliers): best_inliers = inliers best_circle = (center_x, center_y, radius) return best_circle, best_inliers def fit_circle(x, y): # 使用最小二乘法拟合的参数 n = len(x) A = np.vstack([x, y, np.ones(n)]).T b = np.vstack([-(x ** 2 + y ** 2)]).T center_x, center_y, radius = np.linalg.lstsq(A, b, rcond=None)[0] return center_x, center_y, abs(radius) # 测试代码 if __name__ == '__main__': # 构造一些测试点 points = [(0, 0), (1, 1), (1, -1), (-1, 1), (-1, -1), (2, 0), (0, 2), (2, 2), (-2, 0), (0, -2)] # 使用RANSAC拟合 circle, inliers = fit_circle_ransac(points) center_x, center_y, radius = circle print("拟合的心坐标:(%.2f, %.2f)" % (center_x, center_y)) print("拟合的半径:%.2f" % radius) print("内点数量:%d" % len(inliers)) print("内点坐标:", inliers) ``` 这段代码中,`fit_circle_ransac`函数使用了RANSAC算法来拟合。它首先随机选择3个点作为候选心,然后根据这3个点拟合的参数。接着计算所有点到拟合的的距离,并将距离小于阈值的点标记为内点。通过迭代多次,找到内点最多的作为最终拟合结果。 `fit_circle`函数使用最小二乘法来拟合的参数。它将的方程转换为线性方程组,并求解得到心坐标和半径。 在测试代码中,我们使用了一些构造的测试点,并调用`fit_circle_ransac`函数拟合。输出结果为拟合的心坐标、半径、内点数量和内点坐标。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值