Python 利用最小二乘圆度拟合 实现圆角测量
最小二乘法(又称最小平方法)是一种数学优化技术。它通过最小化误差的平方和寻找数据的最佳函数匹配。利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。
课题介绍:
利用Keyence线扫传感器 获取的圆角数据,拟合计算圆角大小。并显示圆角分布图
工具:python 3.6 Keyence LJX8000
导出数据 利用keyence FTP功能将线扫数据传输到本地电脑
代码
1.引用空间
from numpy import *
from scipy import optimize
import functools
from matplotlib import pyplot as p
import csv
import os
method = "RKS Fitting Circle"
x = [] #拟合点X坐标
y = [] # 拟合点Y坐标
R = [] # 输出半径集合
Num=600 # 参考点数量
2.获取数据
path 为文件路径 ,当前使用的线扫宽度j精度为0.005mm.获取原始400到1000点的数据
def GetData(path):
px = []
py = []
with open(path, 'r') as f:
reader = csv.reader(f)
result = list(reader)
for i in range(0, Num):
px.append(i*0.005)
py.append(float(result[400 + i][0]))
return px, py
圆心计算公式
def calc_R(xc, yc):
return sqrt((x - xc) ** 2 + (y - yc) ** 2)
def countcalls(fn):
"decorator function count function calls "
@functools.wraps(fn)
def wrapped(*args):
wrapped.ncalls +=1
return fn(*args)
wrapped.ncalls = 0
return wrapped
@countcalls
def f_2(c):
Ri = calc_R(*c)
return Ri - Ri.mean()
def FitCircle(item):
# 圆心心坐标
x_m = mean(x)# 圆心初始值x
y_m = mean(y) # 圆心初始值y
# 圆心估计
center_estimate = x_m, y_m
center_rks, ier = optimize.leastsq(f_2, center_estimate) #最小二乘预测结果
xc_rks, yc_rks = center_rks
Ri_rks = calc_R(xc_rks, yc_rks)
# 拟合圆的半径
R_rks = Ri_rks.mean() #均值
residu_2 = sum((Ri_rks - R_rks) ** 2) # 方差
residu2_2 = sum((Ri_rks ** 2 - R_rks ** 2) ** 2)
ncalls_2 = f_2.ncalls
# 输出列表
fmt = '%s_%s %10.5f %10.5f %10.5f %10d %10.6f %10.6f %10.2f'
print(('\n%s' + ' %10s' * 7) % tuple('方法 Xc Yc Rc nb_calls std(Ri) residu residu2'.split()))
print('-' * (22 + 7 * (10 + 1)))
print(fmt % (method, item, xc_rks, yc_rks, R_rks, ncalls_2, Ri_rks.std(), residu_2, residu2_2))
R.append(R_rks)
#输出结果
def plot_all(xc_2,yc_2,R_2,residu2=False):
# 输出图
p.close('all')
p.figure(facecolor='white') # figsize=(7, 5.4), dpi=72,
p.axis('equal')
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, lw=2)
p.plot([xc_2], [yc_2], 'gD', mec='r', mew=1)
# draw
p.xlabel('x')
p.ylabel('y')
# 数据
p.plot(x, y, 'ro', label='data', ms=8, mec='b', mew=1)
p.legend(loc='best', labelspacing=0.1)
#标题
# p.grid()
p.title('Least Squares Circle'+ str(R_2))
p.savefig('%s_residu%d_%d.png' % (basename, 2 if residu2 else 1,Num))
p.show()
调用
files = os.listdir(file_path)
for item in files:
file = os.path.join(file_path, item)
if os.path.isfile(file):
name, type = file.split('.', 1)
if type == 'csv':
x,y = GetData(file)
xc,yc,rc= FitCircle(item)
plot_all(xc,yc,rc,residu2=True)
p.plot(R, ls="-", lw=2, label="plot figure")
p.title('Radius R Distribution')
p.legend()
p.show()
效果图