python基于三阶贝塞尔曲线的数据平滑算法

  

  

很多文章在谈及曲线平滑的时候,习惯使用拟合的概念,我认为这是不恰当的。平滑后的曲线,一定经过原始的数据点,而拟合曲线,则不一定要经过原始数据点。

  

一般而言,需要平滑的数据分为两种:时间序列的单值数据,时间序列的二维数据。对于前者,并非一定要用贝塞尔算法,仅用样条插值就可以轻松实现平滑;而对于后者,不管是numpy还是scipy提供的那些插值算法,就都不适用了。

  

本文基于三阶贝塞尔曲线,实现了时间序列的单值数据和时间序列的二维数据的平滑算法,可满足大多数的平滑需求。

  

  

关于贝塞尔曲线的数学原理,这里就不讨论了,直接贴出结论:

  

一阶贝塞尔曲线
  

  

 python基于三阶贝塞尔曲线的数据平滑算法”> <br/>
  </p>
  <p> <img src=

  

二阶贝塞尔曲线
  

  

 python基于三阶贝塞尔曲线的数据平滑算法”> <br/>
  </p>
  <p> <img src=

  

三阶贝塞尔曲线
  

  

 python基于三阶贝塞尔曲线的数据平滑算法”> <br/>
  </p>
  <p> <img src=

  

  

如果我们把三阶贝塞尔曲线的P0和P3视为原始数据,只要找到P1和P2两个点(我们称其为控制点),就可以根据三阶贝塞尔曲线公式,计算出P0和P3之间平滑曲线上的任意点。
  

  

 python基于三阶贝塞尔曲线的数据平滑算法

  

现在,平滑问题变成了如何计算两个原始数据点之间的控制点的问题。步骤如下:

  

<强>第1步:绿色直线连接相邻的原始数据点,计算出个线段的中点,红色直线连接相邻的中点
  

  

 python基于三阶贝塞尔曲线的数据平滑算法

  

<强>第2步:根据相邻两条绿色直线长度之比,分割其中点之间红色连线,标记分割点
  

  

 python基于三阶贝塞尔曲线的数据平滑算法

  

<强>第3步:平移红色连线,使其分割点与相对的原始数据点重合
  

  

 python基于三阶贝塞尔曲线的数据平滑算法

  

<强>第4步:调整平移后红色连线的端点与原始数据点的距离,通常缩减40% - -80%
  

  

 python基于三阶贝塞尔曲线的数据平滑算法

  

算法实现

        # - * -编码:utf - 8 - *      进口numpy np      def bezier_curve (p0, p1, p2, p3,插入):   ”“”   三阶贝塞尔曲线      p0, p1, p2, p3 -点坐标、元组、列表或numpy.ndarray类型   插入——p0和p3之间插值的数量   ”“”      断言isinstance (p0,(元组、列表np.ndarray)), u”点坐标不是期望的元组,列表或numpy数组类型的   断言isinstance (p0,(元组、列表np.ndarray)), u”点坐标不是期望的元组,列表或numpy数组类型的   断言isinstance (p0,(元组、列表np.ndarray)), u”点坐标不是期望的元组,列表或numpy数组类型的   断言isinstance (p0,(元组、列表np.ndarray)), u”点坐标不是期望的元组,列表或numpy数组类型的      如果isinstance (p0,(元组、列表):   p0=np.array (p0)   如果isinstance (p1(元组列表)):   p1=np.array (p1)   如果isinstance (p2(元组列表)):   p2=np.array (p2)   如果isinstance (p3,(元组、列表):   p3=np.array (p3)      点=列表()   np的t。linspace(0, 1,插入+ 2):   points.append (p0 * np.power ((1 - t), 3) + 3 * p1 * t * np.power ((1 - t), 2) + 3 * p2 * (1 - t) * np.power (t, 2) + p3 * np.power (t, 3))      返回np.vstack(分)         def smoothing_base_bezier (date_x date_y k=0.5,插入=10,关闭=False):   ”“”   基于三阶贝塞尔曲线的数据平滑算法      date_x - x维度数据集、列表或numpy.ndarray类型   date_y - y维度数据集、列表或numpy.ndarray类型   k -调整平滑曲线形状的因子,取值一般在0.2 ~ 0.6之间。默认值为0.5   插入——两个原始数据点之间插值的数量。默认值为10   关闭-曲线是否封闭,如是,则首尾相连。默认曲线不封闭   ”“”      断言isinstance (date_x(列表,np.ndarray)), u 'x数据集不是期望的列表或numpy数组类型的   断言isinstance (date_y(列表,np.ndarray)),你没有数据集不是期望的列表或numpy数组类型的      如果isinstance (date_x列表)和isinstance (date_y,列出):   断言len (date_x)==len (date_y), u 'x数据集和y数据集长度不匹配的   date_x=np.array (date_x)   date_y=np.array (date_y)   elif isinstance (date_x np.ndarray)和isinstance (date_y np.ndarray):   断言date_x.shape==date_y。形状,u 'x数据集和y数据集长度不匹配的   其他:   提高异常(u 'x数据集或y数据集类型错误”)      #第1步:生成原始数据折线中点集   mid_points=列表()   我的范围(1,date_x.shape [0]):   mid_points.append ({   “开始”:(date_x(张),date_y(张)),   “结束”:(date_x[我],date_y[我]),   “中期”:((date_x[我]+ date_x(张))/2.0 (date_y[我]+ date_y(张))/2.0)   })      如果关闭:   mid_points.append ({   “开始”:(date_x [1], date_y [1]),   “结束”:(date_x [0], date_y [0]),   “中期”:((date_x [0] + date_x [1])/2.0 (date_y [0] + date_y [1])/2.0)   })      #第2步:找出中点连线及其分割点   split_points=列表()   因为我在范围(len (mid_points)):   如果我& lt;(len (mid_points) 1):   j=i + 1   elif关闭:   j=0   其他:   继续      x00 y00=mid_points[我]['开始']   x01 y01=mid_points[我]['最后']   x10,日元=mid_points [j](“开始”)   x11,日元=mid_points [j](“结束”)   d0=np.sqrt (np.power ((x00-x01), 2) + np.power ((y00-y01), 2))   d1=np.sqrt (np.power ((x10-x11), 2) + np.power ((y10-y11), 2))   k_split=1.0 * d0/(d0 + d1)      mx0 my0=mid_points[我][“中期”)   mx?,当=mid_points [j](“中期”)      split_points.append ({   “开始”:(mx0 my0),   “结束”:(mx?,当我),   “分裂”:(mx0 + (mx1-mx0) * k_split my0 + (my1-my0) * k_split)   })      #第3步:平移中点连线,调整端点,生成控制点   crt_points=列表()   因为我在范围(len (split_points)):   vx, v=mid_points[我]['最后']#当前顶点的坐标   dx=vx - split_points[我]['分裂'][0]#平移线段x偏移量   dy=v - split_points[我]['分裂'][1]#平移线段y偏移量      sx, sy=split_points[我]['开始'][0]+ dx, split_points[我]['开始'][1]+ dy #平移后线段起点坐标   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null   null

python基于三阶贝塞尔曲线的数据平滑算法