zoukankan      html  css  js  c++  java
  • 独立线性度 最佳直线

    找到的散点线性拟合方法都是基于最小二乘法的(numpy.polyfit() scipy.optimize())

    以下是根据 GB/T 18459-2001中附录 A2 提供的独立线性度拟合方法,求得的最佳拟合直线

    import math
    
    
    def find_line(x0, y0):
        '''
        根据散点求得端基直线k,b,并得到每点对端基直线的偏差dy
        :param x0: x坐标数组
        :param y0: y坐标数组
        :return: 每点的偏差dy
        '''
        # 求得端基直线的k,b
        k = (y0[-1] - y0[0]) / (x0[-1] - x0[0])
        d = y0[-1] - (k * x0[-1])
    
        # 根据端基直线的k,b,求得每点对端基直线的偏差dy
        dy = [(y0[i] - ((k * x0[i]) + d)) for i in range(len(x0))]
    
        return dy
    
    
    def find_poly(x_lst, y_lst):
        '''
        找到凸多边形,可以包含全部偏差点dy
        :param x_lst:x数组
        :param y_lst:偏差点dy数组
        :return:最佳凸多边形各个点
        '''
        g_x = []
        g_y = []
    
        # 从起始点开始,向右(x增大方向),找到最大斜率点,再从最大斜率点开始,向右继续寻找
        start_index = 0
        x_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_index
            g_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) - 1
        x_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_y
    
    
    def 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 p4
    
    
    def 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:
                    pass
                else:
                    # 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, b
    
    def isPointinPolygon(point, rangelist):  # [[0,0],[1,1],[0,1],[0,0]] [1,0.8]
        print(point)
        # 判断是否在外包矩形内,如果不在,直接返回false
        lnglist = []
        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 or
                point[1] > maxlat or point[1] < minlat):
            return False
        count = 0
        point1 = 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 True
                if (point12lng < point[0]):
                    count += 1
            point1 = point2
        print(count)
        if count % 2 == 0:
            return True
        else:
            return True
    
    
    if __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))
    
  • 相关阅读:
    表单提交
    后台返回来的数据是字符串
    背景图充满屏幕
    微信小程序添加模板消息
    axios
    前端常见的跨域解决方案
    gulp的压缩
    git的使用步骤
    vue项目使用mint UI
    利用HBuilder将vue项目打包成移动端app
  • 原文地址:https://www.cnblogs.com/sunqim16/p/9121011.html
Copyright © 2011-2022 走看看