找到的散点线性拟合方法都是基于最小二乘法的(numpy.polyfit()
,scipy.optimize()
)
以下是根据 GB/T 18459-2001中附录 A2 提供的独立线性度拟合方法,求得的最佳拟合直线
import mathdef find_line(x0, y0):'''根据散点求得端基直线k,b,并得到每点对端基直线的偏差dy:param x0: x坐标数组:param y0: y坐标数组:return: 每点的偏差dy'''# 求得端基直线的k,bk = (y0[-1] - y0[0]) / (x0[-1] - x0[0])d = y0[-1] - (k * x0[-1])# 根据端基直线的k,b,求得每点对端基直线的偏差dydy = [(y0[i] - ((k * x0[i]) + d)) for i in range(len(x0))]return dydef find_poly(x_lst, y_lst):'''找到凸多边形,可以包含全部偏差点dy:param x_lst:x数组:param y_lst:偏差点dy数组:return:最佳凸多边形各个点'''g_x = []g_y = []# 从起始点开始,向右(x增大方向),找到最大斜率点,再从最大斜率点开始,向右继续寻找start_index = 0x_tmp = x_lst[1:]y_tmp = y_lst[1:]while len(x_tmp) > 0:k_lst = [((j - y_lst[start_index]) / (i - x_lst[start_index])) for i, j in zip(x_tmp, y_tmp)]start_index = k_lst.index(max(k_lst)) + 1 + start_indexg_x.append(x_lst[start_index])g_y.append(y_lst[start_index])x_tmp = x_lst[start_index + 1:]y_tmp = y_lst[start_index + 1:]# 从最末点开始,向左(x减小方向),也找到最大斜率点(有人说找最小斜率点,但是结果算出来不对),再从最大斜率点开始,向左继续寻找start_index = len(x_lst) - 1x_tmp = x_lst[:start_index]y_tmp = y_lst[:start_index]while len(x_tmp) > 0:k_lst = [((j - y_lst[start_index]) / (i - x_lst[start_index])) for i, j in zip(x_tmp, y_tmp)]start_index = k_lst.index(max(k_lst))g_x.append(x_lst[start_index])g_y.append(y_lst[start_index])x_tmp = x_lst[:start_index]y_tmp = y_lst[:start_index]return g_x, g_ydef find_cross(p1, p2, p3):'''根据一个点p1和一条直线(p2和p3的连线),求得该点对直线的铅垂线(平行于纵轴坐标的直线)和直线的交点:param p1: 点:param p2: 线上一点:param p3: 线上另一点:return: 铅垂线与线(p2-p3)的交点'''k = (p2[1] - p3[1]) / (p2[0] - p3[0])b = p2[1] - k * p2[0]p4 = [p1[0], (k * p1[0]) + b]return p4def find_perfect_line(a, b, x0, y0):'''根据凸多边形的每个点,找到凸多边形内最长的一根铅垂线,与最长垂线相交的直线l1的斜率就是最佳直线的斜率过最长铅垂线的中点作直线l2平行于直线l1,直线l2为最佳直线:param a:凸多边形的x轴数组:param b:凸多边形的y轴数组:param x0: 实际x轴数组:param y0: 实际y轴数组:return:最佳直线的斜率k, 截距b'''dic = {}point_lst = [[i, j] for i, j in zip(a, b)]for i in range(len(a)):p1 = (a[i], b[i]) # 凸多边形的每个点坐标rp1 = (x0[x0.index(p1[0])], y0[x0.index(p1[0])])for j in range(len(a)):p2 = (a[j], b[j]) # 凸多边形的每个点坐标rp2 = (x0[x0.index(p2[0])], y0[x0.index(p2[0])])if j == len(a) - 1:p3 = (a[0], b[0])else:p3 = (a[j + 1], b[j + 1])rp3 = (x0[x0.index(p3[0])], y0[x0.index(p3[0])])if p1 == p2 or p1 == p3:passelse:# print('====+++===', p1, p2, p3)# print('====+++===', rp1, rp2, rp3)# 铅垂线长度s_length = abs((p2[1] * (p1[0] - p3[0])) + (p1[1] * (p3[0] - p2[0]) + (p3[1] * (p2[0] - p1[0]))) / (p3[0] - p2[0]))s = find_cross(p1, p2, p3)if isPointinPolygon(s, point_lst):dic[s_length] = [rp1, rp2, rp3]print('铅垂线长度', s_length, s, dic[s_length])# print(dic)max_s_length = dic[max(dic)]rp1 = max_s_length[0]rp2 = max_s_length[1]rp3 = max_s_length[2]# 点和直线两端点中点连线的斜率k = (((rp1[1] + rp2[1]) / 2) - ((rp1[1] + rp3[1]) / 2)) / (((rp1[0] + rp2[0]) / 2) - ((rp1[0] + rp3[0]) / 2))b = ((rp1[1] + rp2[1]) / 2) - (k * ((rp1[0] + rp2[0]) / 2))return k, bdef isPointinPolygon(point, rangelist): # [[0,0],[1,1],[0,1],[0,0]] [1,0.8]print(point)# 判断是否在外包矩形内,如果不在,直接返回falselnglist = []latlist = []for i in range(len(rangelist) - 1):lnglist.append(rangelist[i][0])latlist.append(rangelist[i][1])# print(lnglist, latlist)maxlng = max(lnglist)minlng = min(lnglist)maxlat = max(latlist)minlat = min(latlist)# print(maxlng, minlng, maxlat, minlat)if (point[0] > maxlng or point[0] < minlng orpoint[1] > maxlat or point[1] < minlat):return Falsecount = 0point1 = rangelist[0]for i in range(1, len(rangelist)):point2 = rangelist[i]# 点与多边形顶点重合if (point[0] == point1[0] and point[1] == point1[1]) or (point[0] == point2[0] and point[1] == point2[1]):print("在顶点上")return False# 判断线段两端点是否在射线两侧 不在肯定不相交 射线(-∞,lat)(lng,lat)if (point1[1] < point[1] and point2[1] >= point[1]) or (point1[1] >= point[1] and point2[1] < point[1]):# 求线段与射线交点 再和lat比较point12lng = point2[0] - (point2[1] - point[1]) * (point2[0] - point1[0]) / (point2[1] - point1[1])# print(point12lng)# 点在多边形边上if (point12lng == point[0]):print("点在多边形边上")return Trueif (point12lng < point[0]):count += 1point1 = point2print(count)if count % 2 == 0:return Trueelse:return Trueif __name__ == '__main__':x0 = [1.00, 2.00, 3.00, 4.00, 5.00, 6.00]y0 = [2.02, 4.00, 5.98, 7.90, 10.10, 12.05]dy = find_line(x0, y0)print(dy)a0, b0 = find_poly(x0, dy)print(a0, b0)print(find_perfect_line(a0, b0, x0, y0))