- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一些地理数据(下图将河流的路径显示为红点),我想使用多段三次贝塞尔曲线对其进行近似。通过关于stackoverflow的其他问题here和 here我从“Graphics Gems”中找到了 Philip J. Schneider 的算法。我成功地实现了它,并且可以报告说,即使有数千个点,它也非常快。不幸的是,这种速度有一些缺点,即拟合做得很草率。考虑下图:
红点是我的原始数据,蓝线是施耐德算法创建的多段贝塞尔曲线。如您所见,该算法的输入是一个容差,该容差至少与绿线指示的一样高。然而,该算法创建了一个具有太多急转弯的贝塞尔曲线。您也可以在图像中看到这些不必要的急转弯。很容易想象一条贝塞尔曲线对于显示的数据具有较少的急转弯,同时仍保持最大容差条件(只需将贝塞尔曲线推向洋红色箭头的方向即可)。问题似乎是该算法从我的原始数据中选取数据点作为各个贝塞尔曲线的端点(品红色箭头点表示一些可疑点)。由于贝塞尔曲线的端点受到这样的限制,很明显该算法有时会产生相当尖锐的曲率。
我正在寻找的是一种算法,它使用具有两个约束的多段贝塞尔曲线来近似我的数据:
最佳答案
我找到了满足我的标准的解决方案。解决方案是首先找到一个在最小二乘意义上逼近点的 B 样条,然后将该样条转换为多段贝塞尔曲线。 B 样条确实具有与贝塞尔曲线相比的优点,它们不会通过控制点,并且提供了一种指定近似曲线所需“平滑度”的方法。生成此类样条所需的功能在 scipy 提供了 python 绑定(bind)的 FITPACK 库中实现。假设我将数据读入列表 x
和 y
,那么我可以这样做:
import matplotlib.pyplot as plt
import numpy as np
from scipy import interpolate
tck,u = interpolate.splprep([x,y],s=3)
unew = np.arange(0,1.01,0.01)
out = interpolate.splev(unew,tck)
plt.figure()
plt.plot(x,y,out[0],out[1])
plt.show()
s
splprep
的参数.如果我想让近似值更接近数据,我可以减少
s
平滑度较低的参数。通过多个
s
以编程方式参数我可以找到一个符合给定要求的好参数。
def b_spline_to_bezier_series(tck, per = False):
"""Convert a parametric b-spline into a sequence of Bezier curves of the same degree.
Inputs:
tck : (t,c,k) tuple of b-spline knots, coefficients, and degree returned by splprep.
per : if tck was created as a periodic spline, per *must* be true, else per *must* be false.
Output:
A list of Bezier curves of degree k that is equivalent to the input spline.
Each Bezier curve is an array of shape (k+1,d) where d is the dimension of the
space; thus the curve includes the starting point, the k-1 internal control
points, and the endpoint, where each point is of d dimensions.
"""
from fitpack import insert
from numpy import asarray, unique, split, sum
t,c,k = tck
t = asarray(t)
try:
c[0][0]
except:
# I can't figure out a simple way to convert nonparametric splines to
# parametric splines. Oh well.
raise TypeError("Only parametric b-splines are supported.")
new_tck = tck
if per:
# ignore the leading and trailing k knots that exist to enforce periodicity
knots_to_consider = unique(t[k:-k])
else:
# the first and last k+1 knots are identical in the non-periodic case, so
# no need to consider them when increasing the knot multiplicities below
knots_to_consider = unique(t[k+1:-k-1])
# For each unique knot, bring it's multiplicity up to the next multiple of k+1
# This removes all continuity constraints between each of the original knots,
# creating a set of independent Bezier curves.
desired_multiplicity = k+1
for x in knots_to_consider:
current_multiplicity = sum(t == x)
remainder = current_multiplicity%desired_multiplicity
if remainder != 0:
# add enough knots to bring the current multiplicity up to the desired multiplicity
number_to_insert = desired_multiplicity - remainder
new_tck = insert(x, new_tck, number_to_insert, per)
tt,cc,kk = new_tck
# strip off the last k+1 knots, as they are redundant after knot insertion
bezier_points = numpy.transpose(cc)[:-desired_multiplicity]
if per:
# again, ignore the leading and trailing k knots
bezier_points = bezier_points[k:-k]
# group the points into the desired bezier curves
return split(bezier_points, len(bezier_points) / desired_multiplicity, axis = 0)
关于python - 使用多段三次贝塞尔曲线和距离以及曲率约束逼近数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22556381/
我正在尝试将高斯-博内定理应用于我的 C++ OpenGL 应用程序,并计算网格中相邻三角形 Fi 中顶点 Vi 处的内角值。 在发表这篇文章之前我做了一些搜索,我知道要为 2D 模型执行此操作,可以
我正在使用 MATLAB 进行坦克模拟。坦克有两个马达,一个左马达和一个右马达。这些都可以单独编写,以从 (-100%) 到 (+100%) 的速度运行。所以,如果我写 L, R = (100%, 1
我是一名优秀的程序员,十分优秀!