python-最小二乘法拟合圆

# tkinter 里面调用的方式
def draw_circle(self, df_calc, ax1, pt):
x = df_calc['x']
y = df_calc['y']

# coordinates of the barycenter
x_m = np.mean(x)
y_m = np.mean(y)

method_2 = "leastsq"

def calc_R(c):
""" calculate the distance of each 2D points from the center c=(xc, yc) """
return np.sqrt((x - c[0]) ** 2 + (y - c[1]) ** 2)

def calc_ecart(c):
""" calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """
Ri = calc_R(c)
return Ri - Ri.mean()

center_estimate = x_m, y_m
try:
center_2, ier = optimize.leastsq(calc_ecart, center_estimate)
except Exception as e:
import traceback
traceback.print_exc()
errMsg = traceback.format_exc()
self.status.config(fg="red", font=("simsun", 16))
self.statusStr.set('圆弧计算失败. 请调整计算点数后重试...')
self.log.error("arc calc exception." + errMsg)
return

xc_2, yc_2 = center_2
Ri_2 = calc_R(center_2)
R_2 = Ri_2.mean()
residu_2 = sum((Ri_2 - R_2) ** 2)

print('centerPoint x={},y={},r={}'.format(xc_2, yc_2, R_2))

pt['nameShow'] = pt['name'] + '\nr={:.4f}um'.format(R_2)
pt['annotate'].remove()
bbox = dict(boxstyle="round", fc="0.5")
pt['annotate'] = plt.annotate(pt['nameShow'],
xy=(pt['points'][0] + (pt['points'][2] - pt['points'][0]) / 2, pt['points'][1] + abs(pt['points'][3] - pt['points'][1]) / 3 * 2),
bbox=bbox, xytext=(0, 0), xycoords='data', textcoords='offset points', fontsize=12, ha='center')

if 'arc' in pt:
for it in pt['arc']:
it.remove()
self.canvas.draw_idle()
pt['arc'].clear()

line1, = ax1.plot(x, y, 'ro', label='data', ms=9, mec='b', mew=1)
pt['arc'].append(line1)

theta_fit = np.linspace(-np.pi, np.pi, 180)

x_fit2 = xc_2 + R_2 * np.cos(theta_fit)
y_fit2 = yc_2 + R_2 * np.sin(theta_fit)

# 拟合圆
line2, = ax1.plot(x_fit2, y_fit2, 'k--', label=method_2, lw=2)
pt['arc'].append(line2)

# 圆心
line3, = ax1.plot([xc_2], [yc_2], 'gD', mec='r', mew=1)
pt['arc'].append(line3)

self.ax.set_ymargin(0.3)
self.ax.autoscale(enable=True, tight=False)
self.ax.set_aspect('equal', adjustable='box', anchor='C')

self.canvas.draw_idle()
# python 脚本调用方式
draw_circle(df_point, ax1, plot_name_list, plot_list)

def draw_circle(df_calc,ax1,plot_name_list,plot_list):
x = df_calc['inner']
y = df_calc['height']

# x = [23.10770,23.11350,23.11770,23.12230,23.12610,23.13230]
# y = [5.19880,5.18250,5.16730,5.15070,5.13360,5.10250]

# coordinates of the barycenter
x_m = mean(x)
y_m = mean(y)

method_2 = "leastsq"

def calc_R(c):
""" calculate the distance of each 2D points from the center c=(xc, yc) """
return sqrt((x - c[0]) ** 2 + (y - c[1]) ** 2)

def calc_ecart(c):
""" calculate the algebraic distance between the 2D points and the mean circle centered at c=(xc, yc) """
Ri = calc_R(c)
return Ri - Ri.mean()

center_estimate = x_m, y_m
center_2, ier = optimize.leastsq(calc_ecart, center_estimate)

xc_2, yc_2 = center_2
Ri_2 = calc_R(center_2)
R_2 = Ri_2.mean()
residu_2 = sum((Ri_2 - R_2) ** 2)

print('x={},y={},r={}'.format(xc_2, yc_2, R_2))

# from matplotlib import pyplot as p, cm
#
# f = p.figure()

line2, = ax1.plot(x, y, 'ro', label='data', ms=9, mec='b', mew=1)
plot_name_list.append('circle orig')
plot_list.append(line2)

# p.plot(x, y, 'ro', label='data', ms=9, mec='b', mew=1)

theta_fit = linspace(-pi, pi, 180)

x_fit2 = xc_2 + R_2 * cos(theta_fit)
y_fit2 = yc_2 + R_2 * sin(theta_fit)
# p.plot(x_fit2, y_fit2, 'k--', label=method_2, lw=2)

line2, = ax1.plot(x_fit2, y_fit2, 'k--', label=method_2, lw=2)
plot_name_list.append('1 orig')
plot_list.append(line2)

# p.plot([xc_2], [yc_2], 'gD', mec='r', mew=1)
line2, = ax1.plot([xc_2], [yc_2], 'gD', mec='r', mew=1)
plot_name_list.append('2 orig')
plot_list.append(line2)